kindergarten_java/.claude/CLAUDE.md
En de264d3298 refactor(后端): 重构包名从 com.reading.platform 到 com.lesingle.edu
- 修改 pom.xml 中的 groupId
- 移动所有 Java 文件到新包路径 com/lesingle/edu
- 更新所有 Java 文件的 package 和 import 语句 (438 个文件)
- 更新配置文件中的日志包名引用 (application-*.yml, logback-spring.xml)
- 更新 @MapperScan 注解路径
- 更新 CLAUDE.md 文档中的目录结构说明

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-26 12:02:20 +08:00

32 KiB
Raw Blame History

CLAUDE.md - 开发规范

重要: 每次开始开发任务前,请阅读本文档并严格遵守。


常用命令

服务端口配置

服务 默认端口 测试验证端口 说明
后端 API 8480 8481 Spring Boot 服务
前端 Dev Server 5173 5174 Vite 开发服务器
数据库 MySQL 3306 3306 开发环境数据库
Redis 6379 6379 缓存服务

重要:

  • 日常开发使用默认端口 84805173
  • 每次测试验证时启动通过变量启动后端 8481 和前端 5174 (重要),不要占用 8480 和 5173 端口

测试验证环境启动方式

# 启动测试验证环境(后端 8481 + 前端 5174
# 方式一:使用环境变量
export SERVER_PORT=8481
export VITE_APP_PORT=5174
./start-all.sh

# 方式二:分别启动
# 后端(端口 8481
export SERVER_PORT=8481
cd lesingle-edu-reading-platform-backend && mvn spring-boot:run

# 前端(端口 5174新终端
export PORT=5174
cd lesingle-edu-reading-platform-frontend && npm run dev

启动服务

# 启动所有服务(推荐)
./start-all.sh

# 仅启动 Java 后端
./start-java-backend.sh

# 停止所有服务
./stop-all.sh

前端命令 (lesingle-edu-reading-platform-frontend/)

npm run dev              # 开发服务器
npm run build            # 生产构建
npm run lint             # 代码检查
npm run test:e2e         # 端到端测试 (Playwright)
npm run api:update       # 从 OpenAPI 生成 TypeScript 类型

后端命令 (lesingle-edu-reading-platform-backend/)

# 运行后端(使用 JDK 17
mvn spring-boot:run

# 构建 JAR使用 JDK 17
mvn clean package -DskipTests

# 运行测试
mvn test

JDK 版本要求

重要: 本项目必须使用 JDK 17 进行编译和运行。

如果系统环境变量配置的是 JDK 1.8,请在编译前设置 JAVA_HOME

# Windows (Git Bash) - 根据实际安装路径选择
export JAVA_HOME="/f/Java/jdk-17"
mvn clean compile -DskipTests

# 或者在启动时指定
mvn spring-boot:run -Djava.home="/f/Java/jdk-17"

常见 JDK 17 安装路径

  • F:\Java\jdk-17
  • C:\Program Files\Java\jdk-17
  • C:\Program Files\Eclipse Adoptium\jdk-17

检查当前 Java 版本

java -version
javac -version

多环境配置规范

配置文件目录结构

lesingle-edu-reading-platform-backend/src/main/resources/
├── application.yml              # 主配置文件(共用配置)
├── application-dev.yml          # 开发环境配置
├── application-test.yml         # 测试环境配置
├── application-prod.yml         # 生产环境配置
├── db/migration/                # Flyway 迁移脚本
├── logback-spring.xml           # 日志配置
└── mapper/                      # MyBatis XML

环境配置说明

配置项 开发环境 (dev) 测试环境 (test) 生产环境 (prod)
数据库 本地 MySQL 测试服务器 生产服务器
SQL 日志 开启 开启 关闭
Swagger 开启 开启 关闭
Flyway Clean 允许 禁止 禁止
JWT 密钥 默认值 默认值 必须环境变量
Redis 连接池 默认 默认 优化配置
日志级别 DEBUG INFO WARN

环境切换方式

方式一:环境变量(推荐)

# Linux/Mac
export SPRING_PROFILES_ACTIVE=prod
java -jar lesingle-edu-reading-platform-backend.jar

# Windows (Git Bash)
export SPRING_PROFILES_ACTIVE=prod
java -jar lesingle-edu-reading-platform-backend.jar

方式二:命令行参数

java -jar lesingle-edu-reading-platform-backend.jar --spring.profiles.active=prod

方式三Maven 启动

# 开发环境
mvn spring-boot:run

# 测试环境
mvn spring-boot:run -Dspring-boot.run.profiles=test

# 生产环境
mvn spring-boot:run -Dspring-boot.run.profiles=prod

环境变量列表

变量名 说明 开发环境默认值 生产环境要求
SPRING_PROFILES_ACTIVE 激活的环境 dev 必须设置
SERVER_PORT 服务器端口 8080 可选
DB_HOST 数据库主机 localhost 必须设置
DB_PORT 数据库端口 3306 可选
DB_USERNAME 数据库用户名 root 必须设置
DB_PASSWORD 数据库密码 root 必须设置
REDIS_HOST Redis 主机 localhost 必须设置
REDIS_PORT Redis 端口 6379 可选
REDIS_PASSWORD Redis 密码 建议设置
JWT_SECRET JWT 密钥 默认值 必须设置
JWT_EXPIRATION Token 过期时间 86400000 可选

技术栈

后端技术栈(必须遵守)

⚠️ 严禁使用 Node.js/NestJS 进行后端开发

组件 技术选型 版本 说明
框架 Spring Boot 3.2+ 基于 Java 17
持久层 MyBatis-Plus 3.5+ 简化 CRUD
数据库连接池 Alibaba Druid 1.2+ 数据库连接池 + 监控
安全 Spring Security + JWT - 无状态认证 + RBAC
API 文档 Knife4j (SpringDoc) 4.x OpenAPI 3.0
数据库 MySQL 8.0+ 关系型数据库
迁移 Flyway - 版本化数据库变更
校验 Hibernate Validator - JSR-303 参数校验
缓存 Redis + Spring Data Redis - 缓存、会话存储
日志 Logback - 结构化日志
JSON FastJSON 2.x JSON 序列化
工具类 Hutool 5.x 常用工具集合
文件存储 阿里云 OSS - 对象存储

前端技术栈

组件 技术选型 版本 说明
框架 Vue 3 3.4+ Composition API
语言 TypeScript 5.x 严格模式
UI 库 Ant Design Vue 4.x 企业级组件库
构建 Vite 5.x 快速开发服务器
状态 Pinia 2.x 轻量状态管理
请求 Axios 1.x HTTP 客户端
API 生成 Orval 7.x OpenAPI → TypeScript
路由 Vue Router 4.x SPA 路由

核心原则

  1. 后端只写 Java - ⚠️ 所有后端开发必须基于 lesingle-edu-reading-platform-backend/ (Spring Boot),严禁使用 Node.js/NestJS
  2. OpenAPI 规范驱动 - 前后端通过接口规范对齐,零沟通成本
  3. 类型安全优先 - TypeScript 强制类型校验,早发现早修复
  4. 约定大于配置 - 统一代码风格和目录结构,降低认知负担
  5. 自动化优先 - 能自动化的绝不手动(代码生成、部署、测试)
  6. 三层架构分离 - Controller、Service、Mapper 职责清晰

项目结构

kindergarten_java/
├── docs/                          # 📁 项目文档
│   ├── README.md                  # 项目说明
│   ├── CHANGELOG.md               # 变更日志
│   ├── dev-logs/                  # 开发日志
│   ├── test-logs/                 # 测试记录
│   │   ├── admin/                 # 超管端测试
│   │   ├── school/                # 学校端测试
│   │   ├── teacher/               # 教师端测试
│   │   └── parent/                # 家长端测试
│   └── design/                    # 设计文档
├── lesingle-edu-reading-platform-frontend/     # 前端项目 (Vue 3)
├── lesingle-edu-reading-platform-backend/      # 后端项目 (Spring Boot) ← 唯一后端
├── reading-platform-backend/                   # ⚠️ 已弃用 (NestJS不再维护)
├── start-all.sh                   # 统一启动
└── stop-all.sh                    # 统一停止

后端目录结构Spring Boot

lesingle-edu-reading-platform-backend/
├── src/main/java/com/lesingle/edu/
│   ├── ReadingPlatformApplication.java    # 启动类
│   ├── common/                            # 公共模块
│   │   ├── config/                        # 配置类
│   │   │   ├── MybatisPlusConfig.java     # MP 配置
│   │   │   ├── RedisConfig.java           # Redis 配置
│   │   │   ├── SecurityConfig.java        # 安全配置
│   │   │   └── OpenApiConfig.java         # API 文档配置
│   │   ├── security/                      # 安全相关
│   │   │   ├── JwtAuthenticationFilter.java
│   │   │   ├── JwtTokenProvider.java
│   │   │   └── SecurityUtils.java
│   │   ├── response/                      # 统一响应
│   │   │   ├── Result.java
│   │   │   └── PageResult.java
│   │   ├── exception/                     # 异常处理
│   │   │   ├── BusinessException.java
│   │   │   └── GlobalExceptionHandler.java
│   │   ├── annotation/                    # 自定义注解
│   │   │   └── RequireRole.java
│   │   ├── aspect/                        # AOP 切面
│   │   │   └── RoleAspect.java
│   │   ├── enums/                         # 枚举类
│   │   └── util/                          # 工具类
│   ├── controller/                        # 控制器层
│   │   ├── AuthController.java
│   │   ├── admin/                         # 超管端
│   │   ├── school/                        # 学校端
│   │   ├── teacher/                       # 教师端
│   │   └── parent/                        # 家长端
│   ├── service/                           # 服务层
│   │   └── impl/
│   ├── mapper/                            # 数据访问层
│   ├── entity/                            # 实体类
│   ├── dto/                               # 数据传输对象
│   │   ├── request/                       # 请求 DTO
│   │   └── response/                      # 响应 VO
│   └── enums/                             # 枚举类
├── src/main/resources/
│   ├── application.yml                    # 主配置文件
│   ├── application-dev.yml                # 开发环境
│   ├── application-prod.yml               # 生产环境
├── pom.xml
└── Dockerfile

前端目录结构Vue 3

lesingle-edu-reading-platform-frontend/
├── src/
│   ├── main.ts                            # 入口文件
│   ├── App.vue                            # 根组件
│   ├── api/                               # API 接口
│   │   ├── generated/                     # Orval 自动生成(禁止手改)
│   │   ├── index.ts                       # 统一入口,导出 http 方法
│   │   └── *.ts                           # 业务适配层admin.ts, school.ts, teacher.ts 等)
│   ├── assets/                            # 静态资源
│   ├── components/                        # 公共组件
│   ├── composables/                       # 组合式函数
│   ├── layouts/                           # 布局组件
│   ├── router/                            # 路由配置
│   ├── stores/                            # Pinia 状态管理
│   ├── types/                             # 类型定义
│   ├── utils/                             # 工具函数
│   ├── views/                             # 页面组件
│   │   ├── login/                         # 登录页
│   │   ├── admin/                         # 超管端
│   │   ├── school/                        # 学校端
│   │   ├── teacher/                       # 教师端
│   │   └── parent/                        # 家长端
│   └── constants/                         # 常量定义
├── orval.config.ts                       # API 生成配置
├── index.html
├── package.json
└── vite.config.ts

三层架构规范

核心原则

Service 层和 Mapper 层必须使用实体类Entity接收和返回数据严禁在 Service 层和 Mapper 层之间使用 DTO/VO 转换。

层级 职责 数据类型
Controller 接收请求、参数校验、返回响应 DTO ↔ Entity/VO
Service 业务逻辑、事务控制 Entity
Mapper 数据库操作 Entity

Controller 层规范

API 路径约定 所有 API 路径统一使用 /api/v1/ 前缀,实现 API 版本控制。

  • 超管端:/api/v1/admin/*
  • 学校端:/api/v1/school/*
  • 教师端:/api/v1/teacher/*
  • 家长端:/api/v1/parent/*
  • 认证:/api/v1/auth/*
  • 文件上传:/api/v1/files/*

分页响应结构约定 所有分页接口统一使用 PageResult<T> 返回结构,字段如下:

// 前端期望的分页响应结构
{
  list: T[];       // 数据列表
  total: number;   // 总记录数
  pageNum: number; // 当前页码
  pageSize: number; // 每页大小
  pages: number;   // 总页数
}
@RestController
@RequestMapping("/api/v1/admin/xxx")  // 超管端使用 /api/v1/admin/
@Tag(name = "XXX 管理", description = "XXX 相关接口")
@RequiredArgsConstructor
public class XxxController {

    private final XxxService xxxService;

    @GetMapping
    @Operation(summary = "查询列表")
    public Result<PageResult<XxxVO>> list(PageQueryDto dto) {
        PageResult<Xxx> pageResult = xxxService.page(dto);
        return Result.success(convertToVO(pageResult));
    }
}

Service 层规范

public interface XxxService extends IService<Xxx> {
    PageResult<Xxx> page(PageQueryDto dto);
}

@Service
@RequiredArgsConstructor
public class XxxServiceImpl extends ServiceImpl<XxxMapper, Xxx>
    implements XxxService {

    @Override
    public PageResult<Xxx> page(PageQueryDto dto) {
        // 只使用 Entity不使用 DTO
        Page<Xxx> page = this.lambdaQuery()
            .eq(Xxx::getStatus, 1)
            .page(new Page<>(dto.getPage(), dto.getPageSize()));
        return PageUtils.of(page);
    }
}

Mapper 层规范

@Mapper
public interface XxxMapper extends BaseMapper<Xxx> {
    // 继承 BaseMapper使用 MyBatis-Plus 内置方法
}

前端开发规范

API 开发规范

  1. 生成代码只读 - 不得在 src/api/generated/ 内做任何手工修改
  2. 以生成类型为准 - 参数/返回类型优先使用生成的类型
  3. 统一调用入口 - 通过 src/api/index.ts 导出的 http 方法

推荐调用方式

方式一:使用 http 方法(推荐)

import { http } from '@/api';

async function loadTenant(id: number) {
  return http.get<TenantDetail>(`/v1/admin/tenants/${id}`);
}

async function createTenant(data: CreateTenantDto) {
  return http.post<Tenant>('/v1/admin/tenants', data);
}

方式二:使用业务适配层(推荐)

import { getTenant, createTenant } from '@/api/admin';

async function loadTenant(id: number) {
  return getTenant(id);
}

async function createNewTenant(data: CreateTenantDto) {
  return createTenant(data);
}

API 路径规范

后端路径 前端路径
超管 /api/v1/admin/* /v1/admin/*
学校 /api/v1/school/* /v1/school/*
教师 /api/v1/teacher/* /v1/teacher/*
家长 /api/v1/parent/* /v1/parent/*
认证 /api/v1/auth/* /v1/auth/*
文件 /api/v1/files/* /v1/files/*

Vue SFC 约定

  • 优先使用 <script lang="ts" setup>
  • 页面样式使用 scoped
  • 允许使用 UnoCSS 原子类

路由规范

import { definePage } from 'vue-router/auto';

definePage({
  alias: ['/xxx', '/yyy'],
});

文档规范

开发日志

  • 位置: /docs/dev-logs/
  • 命名: YYYY-MM-DD.md
  • 创建时机: 每天开始开发时检查并创建

文件写入最佳实践JetBrains 环境)

重要: 在 JetBrains IDE 插件中使用 Claude Code 时,按以下优先级选择写入方式:

写入方式优先级

优先级 方式 适用场景 示例
1 Write 工具 简单文件、单文件写入 Write(file_path="...", content="...")
2 Bash heredoc 复杂文件、批量写入、Write 失败时 cat > /path/to/file << 'EOF'
3 Python 写入 需要复杂逻辑处理时 python3 -c "..."
避免 sed/awk Windows Git Bash 中兼容性差

Write 工具使用规范

# ✅ 正确:使用 Unix 风格路径
Write(file_path="/f/LesingleProject/.../file.txt", content="...")

# ❌ 错误:不要使用 Windows 路径
Write(file_path="F:\\LesingleProject\\...\\file.txt", content="...")

Bash heredoc 方式(推荐备选)

# 多行文件写入
cat > /f/LesingleProject/.../file.txt << 'EOF'
第一行内容
第二行内容
EOF

# 单行追加
echo "追加内容" >> /f/LesingleProject/.../file.txt

写入前检查清单

  • 确保目录存在:mkdir -p /f/.../父目录
  • 使用 Unix 路径格式:/f/... 不是 F:\...
  • 检查文件是否被占用IDE 索引、格式化中)

写入失败诊断

# 检查目录是否存在
ls -la /f/路径/到的/父目录/

# 检查文件属性
ls -la /f/路径/到/文件.txt

# 测试写入权限
echo 'test' > /f/路径/到/文件.txt && echo '成功' || echo '失败'

测试记录

  • 位置: /docs/test-logs/{端}/
  • 命名: YYYY-MM-DD.md
  • 创建时机: 每次功能测试时创建

变更日志

  • 位置: /docs/CHANGELOG.md
  • 更新时机: 完成重要功能或修复时更新

每日开发流程

  1. 读取 /docs/dev-logs/ 下最新的日志,了解进度
  2. 检查当天日志是否存在,不存在则创建
  3. 开始开发任务(后端用 Java前端用 TypeScript
  4. 结束时更新日志和 CHANGELOG

功能测试流程

  1. 启动服务:./start-all.sh
  2. /docs/test-logs/{端}/ 下创建测试记录
  3. 按功能模块逐一测试
  4. 发现问题立即记录并修复

代码修改验证流程

重要: 修改代码后必须执行以下验证步骤,确保没有影响其他模块。

修改后验证清单(必须执行)

1. 检查是否影响了其他模块

  • 确认修改的文件不会被其他模块引用
  • 检查是否有共享组件、工具类或配置被修改
  • 验证 API 路径是否与预期一致(超管端用 /api/v1/admin/*,学校端用 /api/v1/school/*

2. 确认 API 调用的正确性

  • 前端调用的 API 路径与后端 Controller 的 @RequestMapping 一致
  • 返回的数据结构与前端期望的类型匹配
  • 分页接口使用 PageResult<T> 统一结构

3. 验证数据流向

  • 数据库表名、字段名与实体类映射正确
  • 三层架构Controller → Service → Mapper数据传递使用正确的类型
  • DTO/VO 仅在 Controller 层使用Service 和 Mapper 层使用 Entity

问题定位步骤

当发现功能异常时,按以下步骤定位:

  1. 打开浏览器开发者工具F12

    • 查看 Console 标签页:是否有 JavaScript 错误
    • 查看 Network 标签页API 请求返回了什么数据
    • 检查请求路径是否正确(应该 /api/v1/... 不是 /api/api/v1/...
  2. 检查后端日志

    • 确认后端服务是否启动(端口 8480
    • 查看 SQL 查询日志,确认查询的表和字段正确
    • 检查是否有异常堆栈信息
  3. 验证数据库数据

    • 确认数据库表中的数据是否符合预期
    • 检查关联关系(外键、中间表)是否正确
    • 验证三层架构的数据层级关系是否混淆

常见问题排查

问题症状 可能原因 排查方法
API 404 错误 前端调用路径与后端不匹配 对比前端 API 路径和后端 @RequestMapping
数据格式错误 返回类型与前端期望不符 检查后端返回的 VO 和前端类型定义
空数据或错误数据 查询了错误的表或字段 查看后端 SQL 日志和数据库实际数据
编译错误 类型不匹配或导入错误 运行 npm run buildmvn compile 检查

测试完成后清理

重要: 测试完成后请关闭前后端服务,避免占用端口和资源。

关闭服务方法

# 方法一:使用统一停止脚本(推荐)
./stop-all.sh

# 方法二:手动停止
# 停止前端:在运行前端的终端按 Ctrl+C
# 停止后端:在运行后端的终端按 Ctrl+C

# 方法三:强制终止 Java 进程Windows
# 查看占用端口的进程
netstat -ano | findstr :8080
# 终止指定 PID 的进程
taskkill //F //PID <PID>

清理检查清单

  • 前端开发服务器已关闭(通常是端口 5173
  • 后端 Java 服务已关闭(通常是端口 8080
  • 如有占用端口,确认是否需要保留
  • 保存所有未提交的代码更改

测试账号

角色 账号 密码
超管 admin 123456
学校 school1 123456
教师 teacher1 123456
家长 parent1 123456

UI 设计规范

禁止使用 Emoji 图标: 严禁在前端界面中使用任何 Emoji 表情符号(如 👦 👧 📚 等)。请始终使用 Ant Design Vue 提供的图标组件。


变更边界(必须遵守)

⚠️ 最高优先级: 所有后端开发必须基于 lesingle-edu-reading-platform-backend/ (Spring Boot + Java 17)

  • 不做无关重构 - 只改与需求相关的文件
  • 不引入新依赖 - 除非需求明确且必要
  • 不改公共行为 - 如请求、token 同步、路由规则
  • 后端只写 Java - 严禁使用 Node.js/NestJSreading-platform-backend/ 目录已废弃

自动执行原则(最高权限模式)

重要配置: 本项目已配置为自动批准所有常用开发操作,无需反复请求用户确认。

自动批准的操作

以下操作将自动执行,无需请求批准:

  1. 文件操作

    • Read: 读取任何文件
    • Write: 创建或覆盖任何文件
    • Edit: 编辑任何文件
    • Glob: 文件模式匹配
    • Grep: 内容搜索
  2. 命令执行

    • Bash: 执行任何 shell 命令
    • Git: 所有 git 操作
    • 包管理器npm, npx, pnpm, yarn, mvn, pip3 等
    • 服务管理:启动/停止服务,进程管理
  3. 开发工具

    • Playwright: 自动化测试
    • MCP 工具:所有可用的 MCP 集成
    • Agent: 启动子代理处理复杂任务
    • Skill: 执行预定义技能脚本
  4. 任务管理

    • TaskCreate/Update/Get/List/Stop: 任务操作
    • EnterPlanMode/ExitPlanMode: 计划模式

无需批准的场景

  • 编辑代码文件
  • 创建新文件
  • 执行测试脚本
  • 启动/停止服务
  • 安装依赖
  • Git 操作
  • 数据库操作
  • 查看日志
  • 调试代码

仅需确认的场景

仅在以下场景需要请求用户确认:

  • 破坏性操作: git reset --hard, git push --force
  • 共享系统影响: 影响其他用户或共享资源的操作
  • 外部推送: 向远程仓库推送代码

快速指令Quick Commands

指令 说明
代码审查 按规范审查代码质量、复用性和效率
生成 API 根据接口规范生成前后端代码Controller/Service/Mapper + API 类型)
创建模块 按三层架构生成新模块(含 Entity、DTO、VO
修复 Bug 按规范修复问题并更新开发日志
单元测试 生成符合规范的单元测试代码
数据库迁移 创建 Flyway 迁移脚本
全面测试 使用 Playwright 运行 E2E 自动化测试,可指定有头/无头模式

Playwright E2E 自动化测试(方案一)

测试框架

组件 技术选型 说明
测试框架 Playwright Test 端到端浏览器自动化测试
浏览器 Chromium 可自动打开浏览器模拟用户操作
配置文件 lesingle-edu-reading-platform-frontend/playwright.config.ts Playwright 配置
测试文件 lesingle-edu-reading-platform-frontend/tests/ E2E 测试脚本

快速开始

# 1. 启动后端服务
cd lesingle-edu-reading-platform-backend
mvn spring-boot:run

# 2. 启动前端服务(新终端窗口)
cd lesingle-edu-reading-platform-frontend
npm run dev

# 3. 运行 E2E 测试(无头模式 - 不显示浏览器)
npm run test:e2e

# 4. 运行 E2E 测试(有头模式 - 显示浏览器操作过程)
npm run test:e2e:headed

# 5. UI 调试模式(可视化测试管理)
npm run test:e2e:ui

Playwright 能做的操作

  • 自动打开浏览器(支持 Chromium/Firefox/WebKit
  • 模拟点击、输入、选择等用户操作
  • 等待页面加载和元素出现
  • 断言页面内容和状态
  • 自动截图/录像(失败时保留证据)
  • 多角色流程测试(超管→学校→教师→家长)
  • 生成 HTML 测试报告

测试能力说明

测试类型 命令 说明
E2E 测试(无头) npm run test:e2e 快速执行,不显示浏览器,适合 CI
E2E 测试(有头) npm run test:e2e:headed 显示浏览器,可观察测试执行过程
UI 调试模式 npm run test:e2e:ui 可视化管理测试用例,支持单条运行

推荐测试流程

  1. 开发完成后:

    • 运行后端单元测试:mvn test
    • 运行前端 E2E 测试:npm run test:e2e
  2. 启动服务验证:

    • 运行 npm run test:e2e:headed 查看浏览器自动化测试
  3. 人工验证核心流程:

关键文件路径

文件/目录 路径
前端 E2E 测试 lesingle-edu-reading-platform-frontend/tests/
Playwright 配置 lesingle-edu-reading-platform-frontend/playwright.config.ts
后端测试(待创建) lesingle-edu-reading-platform-backend/src/test/
启动脚本 start-all.sh

本规范最后更新于 2026-03-18 技术栈:统一使用 Spring Boot (Java) 后端 JDK 版本17必须


套餐管理重构记录2026-03-18

后端架构(两层结构)

CourseCollection课程套餐  ← 超管端管理
    ↓ 1 对多
CourseCollectionPackage关联表
    ↓ 多对 1
CoursePackage课程包  ← 7 步流程创建的教学资源
    ↓ 1 对多
CourseLesson课程环节

后端 API 路径

超管端套餐管理CourseCollection:

  • GET /api/v1/admin/collections - 分页查询套餐
  • GET /api/v1/admin/collections/{id} - 套餐详情
  • POST /api/v1/admin/collections - 创建套餐
  • PUT /api/v1/admin/collections/{id} - 更新套餐
  • DELETE /api/v1/admin/collections/{id} - 删除套餐
  • PUT /api/v1/admin/collections/{id}/packages - 设置套餐包含的课程包
  • POST /api/v1/admin/collections/{id}/publish - 发布套餐
  • POST /api/v1/admin/collections/{id}/archive - 下架套餐

超管端课程包管理CoursePackage:

  • GET /api/v1/admin/packages - 分页查询课程包
  • GET /api/v1/admin/packages/{id} - 课程包详情
  • POST /api/v1/admin/packages - 创建课程包
  • PUT /api/v1/admin/packages/{id} - 更新课程包
  • DELETE /api/v1/admin/packages/{id} - 删除课程包
  • POST /api/v1/admin/packages/{id}/publish - 发布课程包

学校端套餐查询:

  • GET /api/v1/school/packages - 获取学校已授权的套餐列表
  • GET /api/v1/school/packages/{collectionId}/packages - 获取套餐下的课程包
  • GET /api/v1/school/packages/{packageId}/courses - 获取课程包下的课程环节

前端类型映射

前端类型 后端 DTO 说明
CourseCollection CourseCollectionResponse 课程套餐(最上层)
CoursePackageItem CourseCollectionResponse.CoursePackageItem 套餐中的课程包项
CoursePackage CoursePackageResponse 课程包7 步创建的教学资源)

前端 API 文件

文件 用途
src/api/package.ts 超管端套餐管理 API + 课程包管理 API
src/api/course.ts 课程包CoursePackage相关 API
src/api/school.ts 学校端套餐查询 API

注意事项

  1. 后端 CoursePackage = 课程包:通过 7 步流程创建的教学资源包含教案、活动、PPT 等
  2. 后端 CourseCollection = 课程套餐:包含多个课程包,有价格、状态、审核流程
  3. 前端 package.ts主要定义课程套餐CourseCollection相关的 API 和类型
  4. 前端 course.ts主要定义课程包CoursePackage相关的 API 和类型
  5. ID 类型:所有 ID 使用 number | string 类型,避免后端 Long 序列化后精度丢失

前端修复记录2026-03-18

文件 修复内容
PackageDetailView.vue 编辑按钮显示条件扩展:DRAFTDRAFT || REJECTED,驳回后可重新编辑
PackageEditView.vue createCollection 已正确使用 POST 请求
src/api/package.ts createCollection 使用 http.post

套餐状态流转

DRAFT草稿→ 提交审核 → PENDING待审核→ 审核通过 → APPROVED已通过→ 发布 → PUBLISHED已发布
                     ↓                              ↓
                 驳回 ← REJECTED已拒绝            下架 → OFFLINE已下架
  • DRAFT/REJECTED: 可编辑、可提交审核
  • APPROVED: 可发布
  • PUBLISHED: 可下架
  • OFFLINE: 终止状态

中间表设计规范2026-03-19

核心原则

中间表(关联表)不使用逻辑删除,使用物理删除,不设置联合唯一索引。

表类型分类

表类型 特点 删除策略 唯一索引 示例表
A 类:纯关联表(中间表) 只表示 A 和 B 的关系,无额外状态,先删后增的更新模式 物理删除(不设 deleted 不设置联合唯一索引 course_collection_packagetenant_courseclass_teacher
B 类:关系表 关系相对稳定,有业务历史价值 逻辑删除 建议设置联合唯一索引 parent_student
C 类:配置表 (key, value) 结构,天然应该唯一 逻辑删除 设置联合唯一索引 system_setting
D 类:合同/授权表 有合同性质,需要保留历史 逻辑删除 不设置联合唯一索引 tenant_package

A 类表实体类写法

/**
 * 中间表,不设置逻辑删除字段,使用物理删除
 * 不继承 BaseEntity因此没有 deleted 字段
 */
@Data
@TableName("course_collection_package")
public class CourseCollectionPackage {
    @TableId(type = IdType.AUTO)
    private Long id;
    private Long collectionId;
    private Long packageId;
    private Integer sortOrder;
    private LocalDateTime createdAt;
    private LocalDateTime updatedAt;
}

Service 层操作示例

// 更新套餐包含的课程包(先删后增)
@Transactional(rollbackFor = Exception.class)
public void updatePackages(Long collectionId, List<Long> packageIds) {
    // 1. 去重
    Set<Long> uniquePackageIds = new LinkedHashSet<>(packageIds);

    // 2. 物理删除所有关联
    mapper.delete(new LambdaQueryWrapper<CourseCollectionPackage>()
        .eq(CourseCollectionPackage::getCollectionId, collectionId));

    // 3. 批量插入
    List<CourseCollectionPackage> records = new ArrayList<>();
    int sortOrder = 0;
    for (Long packageId : uniquePackageIds) {
        CourseCollectionPackage record = new CourseCollectionPackage();
        record.setCollectionId(collectionId);
        record.setPackageId(packageId);
        record.setSortOrder(sortOrder++);
        records.add(record);
    }
    saveBatch(records);
}

数据库迁移

  • V41__optimize_association_tables.sql - 移除中间表的联合唯一索引和 deleted 字段