API 契约 v1(OpenAPI 3.0 · 2026-08-15 M0 D1 拍板)¶
作者:👤 Claude(执行副董事) 拍板:M0 D1 Claude 出全 3 份关键文档之一 目的:Codex 启动 M0 D2 写代码时直接按此契约开发,含 7 端点 + 参数 + 响应 关联:02-API接口规范.md(原型版基线)· 03-阶段计划.md · 06-数据模型.md · 07-5维评价详细设计.md
0. 基础约定¶
| 项 | 值 |
|---|---|
| Base URL | http://localhost:3000/api(开发) / https://zehu-prod.xxx.com/api(生产) |
| 协议 | HTTPS(生产) / HTTP(开发) |
| 认证 | JWT(Bearer Token),Header Authorization: Bearer <token> |
| 数据格式 | JSON,UTF-8 |
| 时间戳 | ISO 8601 字符串(2026-08-15T01:30:00+08:00) |
| 错误响应 | HTTP 4xx/5xx + { "code": "ERROR_CODE", "message": "..." } |
1. 7 大端点(OpenAPI 3.0)¶
1.1 POST /auth/login 三端登录¶
入参:
{
"platform": "wechat" | "dingtalk" | "web",
"accountType": "student" | "parent" | "teacher" | "schoolAdmin" | "educationAdmin" | "principal" | "partner",
"identifier": "<微信 openid / 钉钉 unionId / 学号 / 工号 / 教联体账号>"
}
响应(200):
{
"token": "eyJhbGciOiJIUzI1NiIs...",
"user": {
"id": "u_123",
"name": "张三",
"role": "student",
"classId": "c_456",
"schoolId": "s_789",
"avatar": "https://...",
"mustChangePassword": false
}
}
错误:
- 401 INVALID_CREDENTIALS — 账号或密码错误
- 403 NOT_APPROVED — 账号未审批(教师/教务等需校长审批)
- 404 USER_NOT_FOUND — 用户不存在
- 429 TOO_MANY_ATTEMPTS — 登录失败次数过多
1.2 GET /me 当前用户¶
Header:Authorization: Bearer <token>
响应(200):
{
"id": "u_123",
"name": "张三",
"role": "student",
"classId": "c_456",
"schoolId": "s_789",
"class": { "id": "c_456", "name": "初二(3)班", "grade": "8" },
"permissions": ["evaluation.read", "evaluation.write"]
}
1.3 GET /dashboard/summary 首页驾驶舱¶
响应(200):
{
"userRole": "teacher",
"classId": "c_456",
"todayTodos": [
{ "id": "t_1", "type": "evaluation", "title": "评价王小明 5 维", "dueAt": "2026-08-15T18:00:00+08:00" }
],
"classRadar": {
"moral": 85.5,
"academic": 78.2,
"health": 92.1,
"art": 80.5,
"practice": 88.3
},
"recentActivities": [
{ "id": "a_1", "type": "evaluation", "title": "李老师评价了王小明", "at": "2026-08-15T09:30:00+08:00" }
],
"weekStats": {
"evaluationsCount": 42,
"partiesAttendCount": 3,
"growthPercent": 5.2
}
}
1.4 GET /evaluation/dimensions 五维评价维度¶
响应(200):
{
"dimensions": [
{ "id": "moral", "name": "思想品德", "weight": 0.2, "points": 30 },
{ "id": "academic", "name": "学业水平", "weight": 0.3, "points": 30 },
{ "id": "health", "name": "身心健康", "weight": 0.2, "points": 30 },
{ "id": "art", "name": "艺术素养", "weight": 0.15, "points": 30 },
{ "id": "practice", "name": "劳动与社会实践", "weight": 0.15, "points": 30 }
]
}
1.5 POST /evaluation/records 提交/查询评价记录¶
Query(GET 模式):?studentId=u_123&term=2026-fall&limit=20&offset=0
Body(POST 模式):
{
"studentId": "u_123",
"dimension": "moral",
"point": "p_moral_3",
"level": "A",
"score": 95,
"comment": "主动帮助同学,品德表现突出",
"evaluatedAt": "2026-08-15T09:30:00+08:00",
"evidence": [ "https://.../photo1.jpg" ]
}
响应(200 POST):
{
"id": "e_12345",
"createdAt": "2026-08-15T09:30:05+08:00",
"evaluatorId": "u_teacher_1",
"evaluatorName": "李老师"
}
响应(200 GET):
{
"total": 156,
"records": [
{
"id": "e_1",
"dimension": "moral",
"point": "p_moral_3",
"level": "A",
"score": 95,
"comment": "...",
"evaluatorName": "李老师",
"evaluatedAt": "2026-08-15T09:30:00+08:00"
}
]
}
1.6 GET /students 学生列表(分页)¶
Query:?classId=c_456&grade=8&limit=20&offset=0&keyword=王
响应(200):
{
"total": 45,
"students": [
{
"id": "u_123",
"name": "王小明",
"studentNo": "20240815",
"classId": "c_456",
"className": "初二(3)班",
"avatar": "https://...",
"radar": {
"moral": 85, "academic": 78, "health": 92, "art": 80, "practice": 88
},
"lastEvaluatedAt": "2026-08-15T09:30:00+08:00"
}
]
}
1.7 GET /reports/term 学期报告单¶
Query:?studentId=u_123&term=2026-fall
响应(200):
{
"student": { "id": "u_123", "name": "王小明", "className": "初二(3)班" },
"term": "2026-fall",
"scores": {
"moral": { "score": 88, "level": "A", "breakdown": [ ... ] },
"academic": { "score": 78, "level": "B", "breakdown": [ ... ] },
"health": { "score": 92, "level": "A", "breakdown": [ ... ] },
"art": { "score": 80, "level": "B", "breakdown": [ ... ] },
"practice": { "score": 88, "level": "A", "breakdown": [ ... ] }
},
"overall": { "score": 85.2, "level": "A", "rank": 5 },
"comments": {
"classTeacher": "...",
"schoolAdmin": "..."
},
"pdfUrl": "https://.../reports/u_123_2026-fall.pdf"
}
2. 错误码完整表¶
| HTTP | code | 触发 |
|---|---|---|
| 400 | INVALID_PARAMS | 参数缺失或格式错 |
| 401 | UNAUTHORIZED | 未登录或 Token 过期 |
| 401 | INVALID_TOKEN | Token 无效 |
| 403 | FORBIDDEN | 权限不足 |
| 403 | NOT_APPROVED | 账号未审批 |
| 404 | NOT_FOUND | 资源不存在 |
| 409 | CONFLICT | 冲突(如重复提交) |
| 413 | PAYLOAD_TOO_LARGE | 上传文件过大 |
| 429 | RATE_LIMIT | 限流 |
| 500 | INTERNAL_ERROR | 服务异常 |
| 503 | SERVICE_UNAVAILABLE | 维护中 |
3. 角色权限矩阵(v1)¶
| 端点 | student | parent | teacher | schoolAdmin | educationAdmin | principal | partner |
|---|---|---|---|---|---|---|---|
| POST /auth/login | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| GET /me | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| GET /dashboard/summary | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| GET /evaluation/dimensions | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| POST /evaluation/records | ❌ | ❌ | ✅(仅本班) | ✅ | ✅ | ✅ | ❌ |
| GET /evaluation/records | ✅(自己) | ✅(自己孩子) | ✅(本班) | ✅ | ✅ | ✅ | ❌ |
| GET /students | ✅(本班) | ✅(自己孩子) | ✅(本班) | ✅ | ✅ | ✅ | ❌ |
| GET /reports/term | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ |
4. 频率限制¶
| 端点 | 限制 |
|---|---|
| POST /auth/login | 5 次/分钟/IP |
| POST /evaluation/records | 60 次/分钟/用户 |
| GET /students | 30 次/分钟/用户 |
| GET /reports/term | 10 次/分钟/用户 |
5. 共享类型¶
// 角色枚举
type Role = "student" | "parent" | "teacher" | "schoolAdmin" | "educationAdmin" | "principal" | "partner";
// 5 维评价维度
type Dimension = "moral" | "academic" | "health" | "art" | "practice";
// 评分等级
type Level = "A" | "B" | "C" | "D";
// 学期
type Term = "2026-fall" | "2026-spring" | "2025-fall" | ...;
6. 版本与部署¶
- API 版本:v1(路径不加版本段,通过 Header
X-API-Version: 1兼容) - 兼容政策:新增字段不破坏旧客户端;删除字段需 6 个月过渡
- OpenAPI 文件:
docs/05-API契约.yaml(Codex D3 补) - Mock:
http://localhost:3000/api/*用 JSON 文件 mock
Why / How to apply¶
Why:M0 D1 Claude 一次性出全 3 份关键文档之一,Codex D2 启动后直接按契约开发,不用等设计稿。
How to apply:
- Codex 写 Node API 时按此契约开发
- 写完用 OpenAPI 工具(Swagger CLI)生成 yaml
- 前端用 openapi-typescript 自动生成类型
- 灰度测试时用 Postman/Insomnia 验证 7 端点