kindergarten_java/CLAUDE.md
En 0d4275b235 feat: 完善 OpenAPI 注解和前端 API 客户端
主要变更:
1. 所有 Entity/DTO/VO 添加 @Schema 注解,完善 API 文档
2. 新增前端 API 封装模块 (src/apis),包含 fetch.ts 和 apis.ts
3. 生成完整的 TypeScript 类型定义(100+ 个模型)
4. pom.xml 添加 Maven 编译配置和 UTF-8 编码支持
5. 更新 CLAUDE.md 开发文档,新增接口规范和 Swagger 注解规范
6. 清理旧的文档文件和 Flyway 迁移脚本

技术细节:
- 后端:27 个实体类 + 所有 DTO/Response 添加 Swagger 注解
- 前端:新增 orval 生成的 API 客户端类型
- 构建:配置 Maven compiler plugin 和 Spring Boot 插件的 JVM 参数
- 数据库:新增 schema 导出文件,删除旧 Flyway 迁移脚本

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 23:51:02 +08:00

724 lines
24 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# CLAUDE.md
本文档为 Claude Code (claude.ai/code) 在本项目中工作时提供指导。
## 项目概述
这是一个**少儿智慧阅读平台**Kindergarten Course Management System采用 Spring Boot 后端 + Vue 3 前端架构。系统管理幼儿园的课程、课时、任务和学生成长记录。
## 技术架构
### 后端 (`reading-platform-java`)
- **框架**: Spring Boot 3.2.3 + Java 17
- **持久层**: MyBatis-Plus 3.5.5
- **安全**: Spring Security + JWT
- **API 文档**: Knife4j (Swagger OpenAPI 3)
- **数据库**: MySQL 8.0
- **数据库迁移**: Flyway
### 前端 (`reading-platform-frontend`)
- **框架**: Vue 3 + TypeScript + Vite
- **UI 组件库**: Ant Design Vue
- **状态管理**: Pinia
- **API**: Axios + Orval 自动生成的 TypeScript 客户端
## 多租户架构
系统支持多个幼儿园(租户):
- `admin` 角色:超级管理员(无租户,管理全系统课程)
- `school` 角色:学校管理员(管理本校的教师、学生、班级)
- `teacher` 角色:教师(管理本校的课时和任务)
- `parent` 角色:家长(查看孩子的进度和任务)
`admin_users` 外,每个实体都有 `tenant_id` 字段。系统课程的 `tenant_id = NULL`
## 项目结构
```
kindergarten_java/
├── reading-platform-java/ # Spring Boot 后端
│ ├── src/main/java/.../controller/
│ │ ├── admin/ # 超级管理员端点 (/api/v1/admin/*)
│ │ ├── school/ # 学校管理员端点 (/api/v1/school/*)
│ │ ├── teacher/ # 教师端点 (/api/v1/teacher/*)
│ │ └── parent/ # 家长端点 (/api/v1/parent/*)
│ ├── entity/ # 数据库实体27张表
│ ├── mapper/ # MyBatis-Plus 映射器
│ ├── service/ # 服务层接口 + 实现
│ ├── common/
│ │ ├── annotation/RequireRole # 基于角色的访问控制
│ │ ├── security/ # JWT 认证
│ │ ├── enums/ # UserRole, CourseStatus 等枚举
│ │ ├── response/ # Result<T>, PageResult<T>
│ │ └── config/ # Security, MyBatis, OpenAPI 配置
│ └── resources/
│ ├── db/migration/ # Flyway 迁移脚本
│ └── mapper/ # MyBatis XML 文件
├── reading-platform-frontend/ # Vue 3 前端
│ ├── src/views/
│ │ ├── admin/ # 超级管理员页面
│ │ ├── school/ # 学校管理员页面
│ │ ├── teacher/ # 教师页面
│ │ └── parent/ # 家长页面
│ ├── api/generated/ # 自动生成的 API 客户端
│ ├── api-spec.yml # OpenAPI 规范
│ └── router/index.ts # Vue Router 配置
├── docker-compose.yml # 后端 + 前端服务
└── docs/开发协作指南.md # 开发指南(中文)
```
## 关键模式
### 1. 基于角色的访问控制
在 Controller/Service 上使用 `@RequireRole` 注解:
```java
@RequireRole(UserRole.SCHOOL) // 只有学校管理员可以访问
```
### 2. 租户隔离
在学校/教师/家长端点中使用 `SecurityUtils.getCurrentTenantId()` 按当前租户过滤数据。
### 3. 统一响应格式
```java
Result<T> success(T data) // { code: 200, message: "success", data: ... }
Result<T> error(code, msg) // { code: xxx, message: "...", data: null }
```
### 4. OpenAPI 驱动开发
- **后端**:在 Controller 上使用 `@Operation`、`@Parameter`、`@Schema` 注解
- **前端**:运行 `npm run api:update``api-spec.yml` 重新生成 TypeScript 客户端
### 5. 前后端接口规范
#### 后端:以 Controller 为"唯一真源"
以后端 `Spring Boot Controller` 为接口定义的唯一真源,通过 `SpringDoc/Knife4j` 导出`OpenAPI` 规范,所有接口必须符合统一响应模型。
**统一响应模型:**
```java
// 普通接口
Result<T> success(T data) // { code: 200, message: "success", data: ... }
Result<T> error(code, msg) // { code: xxx, message: "...", data: null }
// 分页接口
Result<PageResult<T>> // { code: 200, message: "success", data: { items, total, page, pageSize } }
```
**响应结构说明:**
| 接口类型 | 返回类型 | 分页字段命名 |
|---------|---------|-------------|
| 普通接口 | `Result<T>` | - |
| 分页接口 | `Result<PageResult<T>>` | `page`, `pageSize`, `total`, `items` |
| 错误响应 | `Result<Void>` | 参考 `ErrorCode` 枚举 |
**请求参数规范:**
| 参数类型 | 注解 | 说明 |
|---------|------|------|
| 路径变量 | `@PathVariable` | 与 OpenAPI path 模板保持一致 |
| 查询参数 | `@RequestParam` | 分页:`page`, `pageSize`;过滤:`keyword`, `category` 等 |
| 请求体 | `@RequestBody DTO` | 使用 `*Request` 类,不直接暴露实体 |
#### 前端src/apis + fetch.ts 调用模式
围绕 `src/apis` + `fetch.ts` 的调用模式将真实接口规范路径、method、参数、响应结构维护到 `apis.ts`
**工作流程:**
```
后端 Controller (带 @Schema 注解)
Knife4j/Swagger → /v3/api-docs
api-spec.yml (OpenAPI 规范)
orval (npm run api:gen)
生成的 TypeScript 类型 + API 客户端
Vue 组件使用 (强制类型校验)
```
#### 实施步骤
**一、梳理并固化接口响应规范**
1. **确认统一响应模型**
- 普通接口:`Result<业务 DTO>`,字段 `code/message/data`
- 分页接口:`Result<PageResult<业务 DTO>>`,分页字段命名(`page`, `pageSize`, `total` 等)
- 错误响应:统一使用 `Result<Void>` 或类似 `ResultVoid` schema
2. **从后端提炼规范说明**
- 位置:`reading-platform-java/common/response` 与 `common/enums/ErrorCode`
- 输出:简短的"接口规范说明"文档,写入 `docs/` 目录
**二、从后端生成/校准 OpenAPI 规范**
1. **配置 SpringDoc/Knife4j 导出 OpenAPI**
- 查看/完善后端 OpenAPI 配置类(如 `OpenApiConfig` 或 Knife4j 配置)
- 指定 API 基本信息title/description/version与当前 `api-spec.yml` 对齐
- 扫描 `controller/*` 包下所有带 `@RestController` 的类
- 支持 `@Operation`、`@Parameter`、`@Schema` 注解
2. **规范化 Controller 注解与返回类型**
- 检查 Controller 方法返回类型是否全部为 `Result<T>` 或`Result<PageResult<T>>`
- 为缺少注解的接口补全 `@Operation`、`@Parameter`、`@Schema`
- 校准路径前缀与角色划分(`/api/v1/teacher/*`、`/api/v1/school/*` 等)
3. **替换/同步前端 api-spec.yml**
- 使用导出的 OpenAPI JSON/YAML 覆盖/更新 `reading-platform-frontend/api-spec.yml`
- 约定更新流程:修改后端 Controller → 查看/验证文档 → 导出并覆盖 api-spec.yml → 前端重新生成客户端
**三、将接口规范映射到前端 src/apis 体系**
1. **分析现有 src/apis 使用方式**
- 搜索全项目对 `from 'src/apis/fetch'` 或`getRequests` 的引用
- 列出当前真实在用的 URL 列表及对应页面组件
- 对比这些 URL 与后端 Controller 路径以及 `api-spec.yml` 中的 paths
2. **设计 apis.ts 的"接口字典"结构**
-`SwaggerType` / `RequestType` 为基础
- 将真实接口按模块分类(教师端、学校端、家长端、管理员端)
- 每个接口包含路径、method、请求参数类型、响应类型
### 6. DTO/VO 使用规范
#### 响应对象Response/VO
- **必须创建独立的 VO 实体类**,不要使用 `Map`、`HashMap` 或 `JSONObject` 返回数据
- VO 类应放在 `com.reading.platform.dto.response` 包下
- 使用 `@Schema` 注解描述字段含义,便于生成 API 文档
- 使用 `@Data``@Builder` 注解简化代码
**示例:**
```java
@Data
@Builder
@Schema(description = "用户信息响应")
public class UserInfoResponse {
@Schema(description = "用户 ID")
private Long id;
@Schema(description = "用户名")
private String username;
@Schema(description = "昵称")
private String nickname;
@Schema(description = "角色")
private String role;
}
```
#### 请求对象Request/DTO
- 复杂请求参数应创建 DTO 类,放在 `com.reading.platform.dto.request` 包下
- 使用 `@Valid` 和校验注解确保参数合法性
#### 为什么不用 Map
- ✅ VO 实体类类型安全、IDE 智能提示、API 文档自动生成、易于维护
- ❌ Map类型不安全、无文档、易出错、难以重构
### 7. Swagger/OpenAPI 注解规范
#### 强制要求
**所有实体类Entity、DTO、VO 都必须添加 `@Schema` 注解**,确保 API 文档完整性和前端类型生成准确性。
#### 注解使用规范
**1. 类级别注解**
```java
// Entity 类
@Data
@TableName("users")
@Schema(description = "用户信息") // 必须添加
public class User { ... }
// DTO/VO 类
@Data
@Schema(description = "用户创建请求") // 必须添加
public class UserCreateRequest { ... }
@Data
@Schema(description = "用户信息响应") // 必须添加
public class UserResponse { ... }
```
**2. 字段级别注解**
```java
@Schema(description = "用户 ID", example = "1", requiredMode = Schema.RequiredMode.READ_ONLY)
private Long id;
@Schema(description = "用户名", example = "zhangsan", requiredMode = Schema.RequiredMode.REQUIRED)
private String username;
@Schema(description = "年龄", example = "18", minimum = "1", maximum = "150")
private Integer age;
@Schema(description = "创建时间", example = "2024-01-01 12:00:00")
private LocalDateTime createdAt;
```
**3. Controller 方法注解**
```java
@Operation(summary = "创建用户", description = "创建新用户并返回用户信息")
@ApiResponses({
@ApiResponse(responseCode = "200", description = "创建成功"),
@ApiResponse(responseCode = "400", description = "参数错误"),
@ApiResponse(responseCode = "409", description = "用户名已存在")
})
@PostMapping
public Result<UserResponse> createUser(@Valid @RequestBody UserCreateRequest request) {
return Result.success(userService.createUser(request));
}
```
**4. 参数注解**
```java
@Operation(summary = "根据 ID 获取用户")
@GetMapping("/{id}")
public Result<UserResponse> getUser(
@Parameter(description = "用户 ID", required = true)
@PathVariable Long id,
@Parameter(description = "是否包含详细信息")
@RequestParam(defaultValue = "false")
Boolean includeDetails
) {
return Result.success(userService.getUser(id, includeDetails));
}
```
#### 常用注解说明
| 注解 | 位置 | 说明 |
|------|------|------|
| `@Schema(description = "...")` | 类/字段 | 描述类或字段的含义 |
| `@Schema(example = "...")` | 字段 | 示例值 |
| `@Schema(requiredMode = REQUIRED)` | 字段 | 必填字段 |
| `@Schema(requiredMode = READ_ONLY)` | 字段 | 只读字段(如 ID、创建时间 |
| `@Schema(minimum = "1", maximum = "100")` | 字段 | 数值范围 |
| `@Schema(minLength = 1, maxLength = 50)` | 字段 | 字符串长度 |
| `@Schema(pattern = "^[a-zA-Z]+$")` | 字段 | 正则表达式 |
| `@Operation(summary = "...")` | 方法 | 接口摘要 |
| `@Parameter(description = "...")` | 参数 | 参数描述 |
#### 完整示例
**Entity 类:**
```java
package com.reading.platform.entity;
import com.baomidou.mybatisplus.annotation.*;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.time.LocalDateTime;
@Data
@TableName("courses")
@Schema(description = "课程信息")
public class Course {
@Schema(description = "课程 ID", requiredMode = Schema.RequiredMode.READ_ONLY)
@TableId(type = IdType.AUTO)
private Long id;
@Schema(description = "租户 ID", requiredMode = Schema.RequiredMode.READ_ONLY)
private Long tenantId;
@Schema(description = "课程名称", example = "绘本阅读入门", requiredMode = Schema.RequiredMode.REQUIRED)
private String name;
@Schema(description = "课程编码", example = "READ001")
private String code;
@Schema(description = "课程描述")
private String description;
@Schema(description = "封面图片 URL")
private String coverUrl;
@Schema(description = "分类", example = "language")
private String category;
@Schema(description = "适用年龄段", example = "5-6 岁")
private String ageRange;
@Schema(description = "难度等级", example = "beginner")
private String difficultyLevel;
@Schema(description = "课程时长(分钟)", example = "30")
private Integer durationMinutes;
@Schema(description = "状态", example = "published")
private String status;
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.READ_ONLY)
@TableField(fill = FieldFill.INSERT)
private LocalDateTime createdAt;
@Schema(description = "更新时间", requiredMode = Schema.RequiredMode.READ_ONLY)
@TableField(fill = FieldFill.INSERT_UPDATE)
private LocalDateTime updatedAt;
}
```
**DTO 类:**
```java
package com.reading.platform.dto.request;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size;
@Data
@Schema(description = "课程创建请求")
public class CourseCreateRequest {
@Schema(description = "课程名称", example = "绘本阅读入门", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "课程名称不能为空")
@Size(max = 100, message = "课程名称不能超过 100 个字符")
private String name;
@Schema(description = "课程描述", example = "适合大班幼儿的绘本阅读课程")
private String description;
@Schema(description = "分类", example = "language")
private String category;
@Schema(description = "适用年龄段", example = "5-6 岁")
private String ageRange;
}
```
#### 代码审查要点
- [ ] Entity 类是否添加了 `@Schema(description = "...")`
- [ ] Entity 字段是否添加了 `@Schema` 注解描述字段含义
- [ ] DTO/VO 类是否添加了 `@Schema(description = "...")`
- [ ] DTO/VO 字段是否添加了 `@Schema` 注解
- [ ] Controller 方法是否添加了 `@Operation` 注解
- [ ] Controller 参数是否添加了 `@Parameter` 注解
- [ ] 必填字段是否标注了 `requiredMode = REQUIRED`
- [ ] 只读字段ID、时间戳是否标注了 `requiredMode = READ_ONLY`
- [ ] 是否有合适的 `example` 示例值
#### 注意事项
1. **导入正确的包**
```java
import io.swagger.v3.oas.annotations.media.Schema; // Swagger 3.x
```
2. **Lombok 与 Schema 的配合**
- `@Data` 生成的 getter 方法会自动继承字段上的 `@Schema` 注解
- 但建议字段和方法都加上注解以确保兼容性
3. **必填校验**
- `requiredMode = REQUIRED` 仅用于文档说明
- 实际校验需要配合 `@NotNull`、`@NotBlank` 等校验注解
4. **枚举类型**
```java
@Schema(description = "状态", example = "active", allowableValues = {"active", "inactive"})
private String status;
```
### 8. 前端接口校验规范
#### 基于 OpenAPI + orval + TypeScript 的强制校验链路
本项目前端采用**从接口文档到页面代码的强制类型校验链路**,确保前后端接口一致性和类型安全。
**技术栈:**
- **OpenAPI 3.0**:统一的 API 接口规范
- **orval**:从 OpenAPI 规范生成 TypeScript 类型和 API 客户端
- **TypeScript**:静态类型检查
- **ESLint**:代码规范约束
- **axios**HTTP 请求(由 orval 自动生成)
**工作流程:**
```
后端 Controller (带 @Schema 注解)
Knife4j/Swagger
api-spec.yml (OpenAPI 规范)
orval (npm run api:gen)
生成的 TypeScript 类型 + API 客户端
Vue 组件使用 (强制类型校验)
```
#### 配置说明
**orval 配置 (`orval.config.ts` 或 `vite.config.ts`)**
```typescript
export default {
'api': {
input: {
target: './api-spec.yml',
filters: {
tags: ['default'], // 只生成指定标签的接口
},
},
output: {
mode: 'split', // 分离模式:每个接口一个文件
target: './src/api/generated/client.ts',
schemas: './src/api/generated/schemas',
client: 'axios',
mock: false,
override: {
fetch: {
includeHttpRequestHeader: true,
},
useTypeOverInterfaces: true, // 优先使用 type
useDate: true,
},
},
},
};
```
#### 使用规范
**1. 后端必须添加 @Schema 注解**
```java
@Operation(summary = "获取用户信息")
@GetMapping("/{id}")
public Result<UserInfoResponse> getUser(@PathVariable Long id) {
return Result.success(userService.getUser(id));
}
```
**2. 前端必须使用生成的类型和客户端**
```typescript
// ✅ 正确:使用生成的类型和 API
import { getUser } from '@/api/generated/client';
import type { UserInfoResponse } from '@/api/generated/schemas';
const user: UserInfoResponse = await getUser(id);
// ❌ 错误:不要手写类型或手动调用 axios
interface ManualUser { id: number; name: string; }
const user = await axios.get(`/api/users/${id}`);
```
**3. ESLint 约束规则**
```typescript
// .eslintrc.cjs 中添加
rules: {
// 禁止手动调用 axios必须使用生成的 API 客户端
'no-restricted-imports': [
'error',
{
patterns: ['axios', '!@/api/generated/*'],
},
],
// 强制使用生成的类型定义
'@typescript-eslint/no-explicit-any': 'error',
// 禁止使用 any 类型(特殊情况需 eslint-disable 注释)
}
```
**4. 运行时校验(可选)**
使用 `zod``yup` 进行运行时数据校验:
```typescript
import { UserInfoSchema } from '@/api/generated/schemas';
import { z } from 'zod';
// 运行时校验响应数据
const parsedData = UserInfoSchema.parse(apiResponse);
```
#### 开发命令
```bash
cd reading-platform-frontend
# 从后端更新 API 规范并生成客户端
npm run api:gen
# 或者完整流程(包含从后端导出 swagger
npm run api:update
```
#### 代码审查要点
- [ ] 前端是否使用了 orval 生成的类型,而非手写 interface
- [ ] 是否使用生成的 API 客户端,而非手动 axios 调用
- [ ] TypeScript 编译是否通过(无类型错误)
- [ ] 后端 Controller 是否正确添加 @Schema 注解
- [ ] API 变更后是否重新运行了 `npm run api:gen`
#### 常见问题
**Q: 为什么要强制使用生成的类型?**
A: 手写类型容易与后端实际返回不一致,导致运行时错误。生成类型确保前后端一致性。
**Q: 如何添加自定义逻辑?**
A: 在生成的客户端外封装业务逻辑层,不要修改生成的文件。
**Q: API 变更后忘记更新怎么办?**
A: CI/CD 中可添加类型检查步骤,类型不通过则构建失败。
## 开发命令
### 后端
```bash
# 使用 Docker Compose 运行(推荐)
docker compose up --build
# 本地运行(需要 MySQL 已启动)
cd reading-platform-java
mvn spring-boot:run
# 构建
mvn clean package -DskipTests
```
### 前端
```bash
cd reading-platform-frontend
npm install
npm run dev
npm run build
# 从后端规范更新 API 客户端
npm run api:update
```
### 数据库迁移
- 将新的迁移脚本添加到 `reading-platform-java/src/main/resources/db/migration/V{n}__description.sql`
- Flyway 会在后端启动时自动运行(仅开发模式)
## 数据库表结构27张表
- **租户**: tenants, tenant_courses
- **用户**: admin_users, teachers, students, parents, parent_students
- **班级**: classes, class_teachers, student_class_history
- **课程**: courses, course_versions, course_resources, course_scripts, course_script_pages, course_activities
- **课时**: lessons, lesson_feedbacks, student_records
- **任务**: tasks, task_targets, task_completions, task_templates
- **成长**: growth_records
- **资源**: resource_libraries, resource_items
- **日程**: schedule_plans, schedule_templates
- **系统**: system_settings, notifications, operation_logs, tags
## 测试账号
| 角色 | 用户名 | 密码 |
|------|--------|------|
| 管理员 | admin | admin123 |
| 学校 | school | 123456 |
| 教师 | teacher1 | 123456 |
| 家长 | parent1 | 123456 |
## API 文档
- 访问地址http://localhost:8080/doc.html后端启动后
## 近期补充的接口和字段2026-03-10
### 实体类新增字段
**StudentRecord** - 学生评价记录
- `focus` - 专注力评分 (1-5)
- `participation` - 参与度评分 (1-5)
- `interest` - 兴趣评分 (1-5)
- `understanding` - 理解度评分 (1-5)
**LessonFeedback** - 课时反馈
- `design_quality` - 设计质量评分 (1-5)
- `participation` - 参与度评分 (1-5)
- `goal_achievement` - 目标达成度评分 (1-5)
- `step_feedbacks` - 环节反馈 JSON
- `pros` - 优点
- `suggestions` - 建议
- `activities_done` - 完成的活动 JSON
**Lesson** - 课时
- `actual_duration` - 实际时长(分钟)
- `overall_rating` - 整体评分
- `participation_rating` - 参与度评分
- `completion_note` - 完成说明
**Student** - 学生
- `class_id` - 班级 ID
- `parent_name` - 家长姓名
- `parent_phone` - 家长手机号
- `reading_count` - 阅读次数
- `lesson_count` - 课时数
**ClassTeacher** - 班级教师
- `is_primary` - 是否主教
- `sort_order` - 排序
**StudentClassHistory** - 学生班级历史
- `reason` - 调班原因
### 新增 Service 方法
**ClassService**
- `getClassList(Long tenantId)` - 获取班级列表(无分页)
- `getClassStudents(Long classId, ...)` - 获取班级学生分页
- `getClassTeachers(Long classId)` - 获取班级教师列表
- `addClassTeacher(...)` - 添加班级教师
- `updateClassTeacher(...)` - 更新班级教师角色
- `removeClassTeacher(...)` - 移除班级教师
**LessonService**
- `finishLesson(...)` - 结束课时
- `saveStudentRecord(...)` - 保存学生评价记录
- `getStudentRecords(Long lessonId)` - 获取课程所有学生记录
- `batchSaveStudentRecords(...)` - 批量保存学生评价记录
- `saveLessonFeedback(...)` - 提交课程反馈
- `getLessonFeedback(Long lessonId)` - 获取课程反馈
**StudentService**
- `transferStudent(...)` - 学生调班
- `getStudentClassHistory(Long studentId)` - 获取学生调班历史
**TaskService**
- `getTaskCompletion(Long taskId, Long studentId)` - 获取任务完成记录
### 新增 Controller 接口
**学校端 (/api/v1/school/*)**
- `GET /classes/list` - 获取班级列表(无分页)
- `GET /classes/{id}/students` - 获取班级学生分页
- `GET /classes/{id}/teachers` - 获取班级教师列表
- `POST /classes/{id}/teachers` - 添加班级教师
- `PUT /classes/{id}/teachers/{teacherId}` - 更新班级教师角色
- `DELETE /classes/{id}/teachers/{teacherId}` - 移除班级教师
- `POST /students/{id}/transfer` - 学生调班
- `GET /students/{id}/history` - 获取学生调班历史
**教师端 (/api/v1/teacher/*)**
- `GET /courses/classes` - 获取教师的班级列表
- `GET /courses/students` - 获取教师所有学生分页
- `GET /courses/classes/{classId}/students` - 获取班级学生分页
- `GET /courses/classes/{classId}/teachers` - 获取班级教师列表
- `POST /lessons/{id}/finish` - 结束课时
- `POST /lessons/{lessonId}/students/{studentId}/record` - 保存学生评价记录
- `GET /lessons/{lessonId}/student-records` - 获取课程所有学生记录
- `POST /lessons/{lessonId}/student-records/batch` - 批量保存学生评价记录
- `POST /lessons/{lessonId}/feedback` - 提交课程反馈
- `GET /lessons/{lessonId}/feedback` - 获取课程反馈
- `GET /schedules/timetable` - 获取课表(按日期范围)
- `GET /schedules/today` - 获取今日课表
- `POST /schedules` - 创建课表计划
- `PUT /schedules/{id}` - 更新课表计划
- `DELETE /schedules/{id}` - 取消课表计划
**家长端 (/api/v1/parent/*)**
- `GET /children` - 获取我的孩子(增强返回格式)
- `GET /children/{id}` - 获取孩子详情(增强返回格式)
- `GET /children/{childId}/lessons` - 获取孩子的课时记录
- `GET /children/{childId}/tasks` - 获取孩子的任务(带完成状态)
- `PUT /children/{childId}/tasks/{taskId}/feedback` - 提交任务家长反馈
### 数据库迁移
- 迁移脚本:``
- 包含上述所有实体类新增字段的 ALTER TABLE 语句