diff --git a/docs/API.md b/docs/API.md new file mode 100644 index 0000000..d4820a0 --- /dev/null +++ b/docs/API.md @@ -0,0 +1,1101 @@ +# 个人记账预算系统 API 接口文档 + +> **版本**: v1.0.0 +> **基础路径**: `http://localhost:3001/api` +> **技术栈**: Node.js + Express + Prisma (SQLite) +> **更新**: 2026-04-27 + +--- + +## 一、文档说明 + +本文档遵循 **OpenAPI 3.0** 规范,定义个人记账预算系统的所有 RESTful API 接口。文档与代码实现保持同步,可作为前后端开发、测试验证、接口调用的权威参考。 + +--- + +## 二、认证与鉴权 + +**MVP 阶段**: 当前所有接口通过 `userId` 查询参数实现数据隔离,生产环境需替换为 JWT Token 鉴权。 + +``` +Authorization: Bearer +``` + +**数据隔离规则**: 所有接口均需要传入 `userId` 参数,确保用户只能访问自己的数据。 + +--- + +## 三、全局约定 + +### 3.1 统一响应格式 + +所有接口均返回 JSON 格式,遵循统一结构: + +#### 成功响应 + +```json +{ + "success": true, + "data": { ... }, + "message": "操作成功" +} +``` + +#### 错误响应 + +```json +{ + "success": false, + "data": null, + "message": "错误信息描述" +} +``` + +### 3.2 HTTP 状态码 + +| 状态码 | 说明 | 触发场景 | +|--------|------|---------| +| 200 | 成功 | 请求成功处理 | +| 400 | 客户端错误 | 参数校验失败、必填字段缺失 | +| 404 | 资源不存在 | 请求的记录/账户/预算不存在 | +| 500 | 服务端错误 | 数据库异常、内部逻辑错误 | + +### 3.3 日期格式 + +| 字段类型 | 格式 | 示例 | +|---------|------|------| +| 日期 | `YYYY-MM-DD` | `2026-04-27` | +| 日期时间 | ISO 8601 | `2026-04-27T10:00:00.000Z` | +| 月份 | `YYYY-MM` | `2026-04` | + +### 3.4 金额处理 + +- 所有金额字段为 **Number** 类型,单位为 **元** +- 精度:保留两位小数 +- 示例:`168.50` 表示 168.5 元 + +### 3.5 分页约定 + +当前接口采用 **全量返回** 模式,前端负责分页逻辑(每页 10 条)。后续将接入后端分页。 + +--- + +## 四、核心业务模型 + +### 4.1 用户 (User) + +```typescript +interface User { + id: number; // 用户唯一标识 + name: string; // 用户名 + email: string; // 邮箱(唯一) + createdAt: string; // 创建时间 +} +``` + +### 4.2 账户 (Account) + +```typescript +interface Account { + id: number; // 账户唯一标识 + userId: number; // 所属用户 ID + name: string; // 账户名称(如"支付宝") + type: string; // 账户类型:payment/bank/cash + color: string; // UI 显示颜色(如 "#1890FF") + balance: number; // 当前余额(元) + createdAt: string; // 创建时间 + updatedAt: string; // 更新时间 +} +``` + +### 4.3 交易记录 (Record) + +```typescript +interface Record { + id: number; // 记录唯一标识 + userId: number; // 所属用户 ID + accountId: number; // 关联账户 ID + type: string; // 类型:income/expense + amount: number; // 金额(元) + category: string; // 分类(如"餐饮") + description?: string; // 备注 + date: string; // 交易日期 + account?: Account; // 关联账户详情(JOIN 查询填充) + createdAt: string; // 创建时间 + updatedAt: string; // 更新时间 +} +``` + +### 4.4 预算 (Budget) + +```typescript +interface Budget { + id: number; // 预算唯一标识 + userId: number; // 所属用户 ID + category: string; // 预算分类 + amount: number; // 预算金额上限(元) + month: string; // 预算月份(YYYY-MM) + createdAt: string; // 创建时间 + updatedAt: string; // 更新时间 +} +``` + +--- + +## 五、接口详情 + +### 5.1 健康检查与系统接口 + +#### 5.1.1 服务健康检查 + +**接口**: `GET /health` + +**说明**: 用于负载均衡/容器探针,不依赖数据库 + +**请求**: 无 + +**响应**: +```json +{ + "success": true, + "data": { + "timestamp": "2026-04-27T10:00:00.000Z" + }, + "message": "Personal Finance Backend is running" +} +``` + +#### 5.1.2 API 根路径 + +**接口**: `GET /api` + +**说明**: 返回版本信息,用于前端检测后端可达性 + +**响应**: +```json +{ + "success": true, + "data": { + "version": "1.0.0" + }, + "message": "Personal Finance API" +} +``` + +--- + +### 5.2 用户模块 `/api/users` + +> **说明**: MVP 阶段临时接口,生产环境应替换为注册/登录流程 + +#### 5.2.1 创建用户 + +**接口**: `POST /api/users` + +**请求体**: +```json +{ + "name": "测试用户", + "email": "test@example.com" +} +``` + +**参数说明**: +| 参数 | 类型 | 必填 | 说明 | 校验规则 | +|------|------|------|------|---------| +| name | string | 是 | 用户名 | 非空字符串 | +| email | string | 是 | 邮箱 | 唯一约束 | + +**成功响应** (200): +```json +{ + "success": true, + "data": { + "id": 1, + "name": "测试用户", + "email": "test@example.com", + "createdAt": "2026-04-27T10:00:00.000Z", + "updatedAt": "2026-04-27T10:00:00.000Z" + }, + "message": "用户创建成功" +} +``` + +**错误响应**: +```json +{ + "success": false, + "data": null, + "message": "该邮箱已被注册" +} +``` + +**错误码**: +| 状态码 | 错误码 | 说明 | +|--------|--------|------| +| 400 | P2002 | 邮箱重复 | +| 500 | INTERNAL_ERROR | 服务器内部错误 | + +#### 5.2.2 获取用户列表 + +**接口**: `GET /api/users` + +**请求**: 无 + +**响应** (200): +```json +{ + "success": true, + "data": [ + { + "id": 1, + "name": "测试用户", + "email": "test@example.com", + "createdAt": "2026-04-27T10:00:00.000Z", + "updatedAt": "2026-04-27T10:00:00.000Z" + } + ] +} +``` + +--- + +### 5.3 账户模块 `/api/accounts` + +#### 5.3.1 获取账户列表 + +**接口**: `GET /api/accounts` + +**查询参数**: +| 参数 | 类型 | 必填 | 位置 | 说明 | +|------|------|------|------|------| +| userId | number | 是 | query | 用户 ID | + +**请求示例**: +``` +GET /api/accounts?userId=1 +``` + +**响应** (200): +```json +{ + "success": true, + "data": [ + { + "id": 1, + "userId": 1, + "name": "支付宝", + "type": "payment", + "color": "#1890FF", + "balance": 5000, + "createdAt": "2026-04-27T10:00:00.000Z", + "updatedAt": "2026-04-27T10:00:00.000Z" + } + ] +} +``` + +#### 5.3.2 获取账户详情 + +**接口**: `GET /api/accounts/:id` + +**路径参数**: +| 参数 | 类型 | 必填 | 说明 | +|------|------|------|------| +| id | number | 是 | 账户 ID | + +**请求示例**: +``` +GET /api/accounts/1 +``` + +**响应** (200): +```json +{ + "success": true, + "data": { + "id": 1, + "userId": 1, + "name": "支付宝", + "type": "payment", + "color": "#1890FF", + "balance": 5000, + "createdAt": "2026-04-27T10:00:00.000Z", + "updatedAt": "2026-04-27T10:00:00.000Z" + } +} +``` + +**错误响应** (404): +```json +{ + "success": false, + "data": null, + "message": "账户不存在" +} +``` + +#### 5.3.3 创建账户 + +**接口**: `POST /api/accounts` + +**请求体**: +```json +{ + "userId": 1, + "name": "支付宝", + "type": "payment", + "color": "#1890FF", + "balance": 5000 +} +``` + +**参数说明**: +| 参数 | 类型 | 必填 | 默认值 | 说明 | +|------|------|------|--------|------| +| userId | number | 是 | - | 用户 ID | +| name | string | 是 | - | 账户名称 | +| type | string | 是 | - | 账户类型:payment/bank/cash | +| color | string | 否 | "#1890FF" | UI 颜色 | +| balance | number | 否 | 0 | 初始余额 | + +**成功响应** (200): +```json +{ + "success": true, + "data": { + "id": 2, + "userId": 1, + "name": "支付宝", + "type": "payment", + "color": "#1890FF", + "balance": 5000, + "createdAt": "2026-04-27T10:00:00.000Z", + "updatedAt": "2026-04-27T10:00:00.000Z" + }, + "message": "账户创建成功" +} +``` + +#### 5.3.4 更新账户 + +**接口**: `PUT /api/accounts/:id` + +**路径参数**: +| 参数 | 类型 | 必填 | 说明 | +|------|------|------|------| +| id | number | 是 | 账户 ID | + +**请求体** (部分更新,仅更新传入字段): +```json +{ + "name": "新名称", + "balance": 6000 +} +``` + +**响应** (200): +```json +{ + "success": true, + "data": { ... }, + "message": "账户更新成功" +} +``` + +#### 5.3.5 删除账户 + +**接口**: `DELETE /api/accounts/:id` + +**路径参数**: +| 参数 | 类型 | 必填 | 说明 | +|------|------|------|------| +| id | number | 是 | 账户 ID | + +**响应** (200): +```json +{ + "success": true, + "data": null, + "message": "账户删除成功" +} +``` + +--- + +### 5.4 交易记录模块 `/api/records` + +> **核心业务**: 创建/更新/删除记录时,使用 Prisma 事务联动更新账户余额,确保数据一致性。 + +#### 5.4.1 获取交易记录列表 + +**接口**: `GET /api/records` + +**查询参数**: +| 参数 | 类型 | 必填 | 说明 | +|------|------|------|------| +| userId | number | 是 | 用户 ID | +| accountId | number | 否 | 账户 ID 筛选 | +| type | string | 否 | 类型筛选:income/expense | +| category | string | 否 | 分类筛选 | +| startDate | string | 否 | 开始日期(YYYY-MM-DD) | +| endDate | string | 否 | 结束日期(YYYY-MM-DD) | + +**请求示例**: +``` +GET /api/records?userId=1&type=expense&startDate=2026-04-01&endDate=2026-04-30 +``` + +**排序规则**: 按 `createdAt` 倒序(最新记录在前) + +**关联查询**: 自动包含 `account` 对象,便于前端展示账户名 + +**响应** (200): +```json +{ + "success": true, + "data": [ + { + "id": 5, + "userId": 1, + "accountId": 1, + "type": "expense", + "amount": 68, + "category": "餐饮", + "description": "午饭", + "date": "2026-04-27T00:00:00.000Z", + "account": { + "id": 1, + "name": "支付宝", + "type": "payment", + "color": "#1890FF", + "balance": 4932 + }, + "createdAt": "2026-04-27T10:30:00.000Z", + "updatedAt": "2026-04-27T10:30:00.000Z" + } + ] +} +``` + +#### 5.4.2 获取交易记录详情 + +**接口**: `GET /api/records/:id` + +**路径参数**: +| 参数 | 类型 | 必填 | 说明 | +|------|------|------|------| +| id | number | 是 | 记录 ID | + +**响应** (200): +```json +{ + "success": true, + "data": { + "id": 5, + "userId": 1, + "accountId": 1, + "type": "expense", + "amount": 68, + "category": "餐饮", + "description": "午饭", + "date": "2026-04-27T00:00:00.000Z", + "account": { ... }, + "createdAt": "2026-04-27T10:30:00.000Z", + "updatedAt": "2026-04-27T10:30:00.000Z" + } +} +``` + +#### 5.4.3 创建交易记录 + +**接口**: `POST /api/records` + +**请求体**: +```json +{ + "userId": 1, + "accountId": 1, + "type": "expense", + "amount": 68, + "category": "餐饮", + "description": "午饭", + "date": "2026-04-27" +} +``` + +**参数说明**: +| 参数 | 类型 | 必填 | 说明 | 校验规则 | +|------|------|------|------|---------| +| userId | number | 是 | 用户 ID | 正整数 | +| accountId | number | 是 | 账户 ID | 正整数 | +| type | string | 是 | 交易类型 | 枚举:income/expense | +| amount | number | 是 | 金额(元) | 必须大于 0 | +| category | string | 是 | 分类名称 | 非空字符串 | +| description | string | 否 | 备注说明 | 最大长度 200 | +| date | string | 是 | 交易日期 | 格式:YYYY-MM-DD | + +**业务逻辑**: +``` +1. 校验必填字段和金额合法性 +2. 安全解析日期(本地时区,避免 UTC 偏移) +3. 开启 Prisma 事务 + ├─ 3.1 创建交易记录 + ├─ 3.2 查询当前账户余额 + ├─ 3.3 根据类型计算新余额(income 加,expense 减) + └─ 3.4 更新账户余额 +4. 提交事务,返回创建记录 +5. 任何步骤失败则整体回滚 +``` + +**成功响应** (200): +```json +{ + "success": true, + "data": { + "id": 6, + "userId": 1, + "accountId": 1, + "type": "expense", + "amount": 68, + "category": "餐饮", + "description": "午饭", + "date": "2026-04-27T00:00:00.000Z", + "createdAt": "2026-04-27T10:30:00.000Z", + "updatedAt": "2026-04-27T10:30:00.000Z" + }, + "message": "交易记录创建成功" +} +``` + +**错误响应**: +```json +{ + "success": false, + "data": null, + "message": "必填字段缺失" +} +``` + +#### 5.4.4 更新交易记录 + +**接口**: `PUT /api/records/:id` + +**路径参数**: +| 参数 | 类型 | 必填 | 说明 | +|------|------|------|------| +| id | number | 是 | 记录 ID | + +**请求体** (部分更新): +```json +{ + "type": "expense", + "amount": 100, + "category": "交通", + "description": "打车", + "date": "2026-04-27" +} +``` + +**业务逻辑**: +``` +1. 查询原记录 +2. 反向冲销原金额对余额的影响 + ├─ 原收入:减去原金额 + └─ 原支出:加回原金额 +3. 更新记录字段(仅更新传入字段) +4. 按新 type/amount 重新计算余额 +5. 更新账户余额 +6. 提交事务 +``` + +**响应** (200): +```json +{ + "success": true, + "data": { ... }, + "message": "交易记录更新成功" +} +``` + +#### 5.4.5 删除交易记录 + +**接口**: `DELETE /api/records/:id` + +**路径参数**: +| 参数 | 类型 | 必填 | 说明 | +|------|------|------|------| +| id | number | 是 | 记录 ID | + +**业务逻辑**: +``` +1. 查询原记录 +2. 反向冲销余额(撤销记录对余额的影响) + ├─ 原收入:减去金额 + └─ 原支出:加回金额 +3. 更新账户余额 +4. 删除记录 +5. 提交事务 +``` + +**响应** (200): +```json +{ + "success": true, + "data": null, + "message": "交易记录删除成功" +} +``` + +--- + +### 5.5 预算模块 `/api/budgets` + +#### 5.5.1 获取预算列表 + +**接口**: `GET /api/budgets` + +**查询参数**: +| 参数 | 类型 | 必填 | 说明 | +|------|------|------|------| +| userId | number | 是 | 用户 ID | +| month | string | 否 | 月份筛选(YYYY-MM) | + +**请求示例**: +``` +GET /api/budgets?userId=1&month=2026-04 +``` + +**排序规则**: 按 `createdAt` 倒序 + +**响应** (200): +```json +{ + "success": true, + "data": [ + { + "id": 1, + "userId": 1, + "category": "餐饮", + "amount": 1500, + "month": "2026-04", + "createdAt": "2026-04-27T10:00:00.000Z", + "updatedAt": "2026-04-27T10:00:00.000Z" + } + ] +} +``` + +#### 5.5.2 获取预算详情 + +**接口**: `GET /api/budgets/:id` + +**路径参数**: +| 参数 | 类型 | 必填 | 说明 | +|------|------|------|------| +| id | number | 是 | 预算 ID | + +#### 5.5.3 创建预算 + +**接口**: `POST /api/budgets` + +**请求体**: +```json +{ + "userId": 1, + "category": "餐饮", + "amount": 1500, + "month": "2026-04" +} +``` + +**参数说明**: +| 参数 | 类型 | 必填 | 说明 | 校验规则 | +|------|------|------|------|---------| +| userId | number | 是 | 用户 ID | 正整数 | +| category | string | 是 | 预算分类 | 非空字符串 | +| amount | number | 是 | 预算金额(元) | 必须大于 0 | +| month | string | 是 | 预算月份 | 格式:YYYY-MM | + +#### 5.5.4 更新预算 + +**接口**: `PUT /api/budgets/:id` + +**请求体** (部分更新): +```json +{ + "amount": 2000 +} +``` + +#### 5.5.5 删除预算 + +**接口**: `DELETE /api/budgets/:id` + +--- + +### 5.6 统计分析模块 `/api/statistics` + +#### 5.6.1 月度统计 + +**接口**: `GET /api/statistics/monthly` + +**说明**: 获取指定月份的总收入、总支出、结余,以及各支出分类的汇总金额(用于饼图) + +**查询参数**: +| 参数 | 类型 | 必填 | 说明 | +|------|------|------|------| +| userId | number | 是 | 用户 ID | +| month | string | 是 | 月份(YYYY-MM) | + +**请求示例**: +``` +GET /api/statistics/monthly?userId=1&month=2026-04 +``` + +**响应** (200): +```json +{ + "success": true, + "data": { + "totalIncome": 9000, + "totalExpense": 520, + "balance": 8480, + "categoryStats": [ + {"category": "餐饮", "amount": 68}, + {"category": "交通", "amount": 25}, + {"category": "购物", "amount": 299}, + {"category": "娱乐", "amount": 128} + ] + } +} +``` + +#### 5.6.2 趋势统计 + +**接口**: `GET /api/statistics/trend` + +**说明**: 获取按日期聚合的日级收支数据(用于折线图/柱状图) + +**查询参数**: +| 参数 | 类型 | 必填 | 说明 | +|------|------|------|------| +| userId | number | 是 | 用户 ID | +| startDate | string | 否 | 开始日期(不传则返回所有数据) | +| endDate | string | 否 | 结束日期 | + +**请求示例**: +``` +GET /api/statistics/trend?userId=1&startDate=2026-04-01&endDate=2026-04-30 +``` + +**排序规则**: 按 `date` 正序 + +**响应** (200): +```json +{ + "success": true, + "data": [ + {"date": "2026-04-25", "income": 0, "expense": 128}, + {"date": "2026-04-26", "income": 0, "expense": 299}, + {"date": "2026-04-27", "income": 0, "expense": 93} + ] +} +``` + +#### 5.6.3 月度对比 + +**接口**: `GET /api/statistics/compare` + +**说明**: 获取当前月与上月的收支对比数据(用于环比分析) + +**查询参数**: +| 参数 | 类型 | 必填 | 说明 | +|------|------|------|------| +| userId | number | 是 | 用户 ID | +| month | string | 是 | 月份(YYYY-MM) | + +**请求示例**: +``` +GET /api/statistics/compare?userId=1&month=2026-04 +``` + +**响应** (200): +```json +{ + "success": true, + "data": { + "currentMonth": { + "label": "4月", + "income": 9000, + "expense": 520 + }, + "lastMonth": { + "label": "3月", + "income": 8500, + "expense": 1200 + } + } +} +``` + +--- + +### 5.7 仪表盘模块 `/api/dashboard` + +#### 5.7.1 仪表盘汇总数据 + +**接口**: `GET /api/dashboard/summary` + +**说明**: 聚合多源数据(账户余额/本月收支/预算使用率),为首页提供一次性数据,减少前端请求次数 + +**查询参数**: +| 参数 | 类型 | 必填 | 说明 | +|------|------|------|------| +| userId | number | 是 | 用户 ID | + +**请求示例**: +``` +GET /api/dashboard/summary?userId=1 +``` + +**性能优化**: 使用 `Promise.all` 并行查询三类数据(账户、交易、预算) + +**响应** (200): +```json +{ + "success": true, + "data": { + "totalBalance": 18000, + "monthIncome": 9000, + "monthExpense": 520, + "accounts": [ + { + "id": 1, + "userId": 1, + "name": "支付宝", + "type": "payment", + "color": "#1890FF", + "balance": 4932 + }, + { + "id": 2, + "userId": 1, + "name": "微信钱包", + "type": "payment", + "color": "#52C41A", + "balance": 2975 + } + ], + "budgetUsage": [ + { + "id": 1, + "userId": 1, + "category": "餐饮", + "amount": 1500, + "month": "2026-04", + "spent": 68, + "percentage": 4.53 + }, + { + "id": 2, + "userId": 1, + "category": "交通", + "amount": 500, + "month": "2026-04", + "spent": 25, + "percentage": 5 + } + ] + } +} +``` + +--- + +### 5.8 工具接口 + +#### 5.8.1 初始化测试数据 + +**接口**: `GET /api/init-test-data` + +**说明**: 仅开发环境使用,用于快速创建测试数据。具有幂等性(已有数据则跳过) + +**安全警告**: 生产环境必须移除此接口 + +**请求示例**: +``` +GET /api/init-test-data +``` + +**响应** (200): +```json +{ + "success": true, + "data": { + "userId": 1 + }, + "message": "数据初始化成功" +} +``` + +**初始化数据**: +- 1 个测试用户(测试用户) +- 3 个账户(支付宝/微信钱包/招商银行) +- 6 笔交易记录(2 收入 + 4 支出) +- 4 笔预算(餐饮/交通/购物/娱乐) + +--- + +## 六、业务逻辑说明 + +### 6.1 余额联动机制 + +交易记录的创建/更新/删除均会联动更新账户余额,使用 Prisma 事务确保一致性: + +| 操作 | 账户余额变化 | +|------|------------| +| 创建收入记录 | `balance += amount` | +| 创建支出记录 | `balance -= amount` | +| 更新记录 | 先冲销原金额,再应用新金额 | +| 删除记录 | 反向冲销原金额影响 | + +### 6.2 日期处理机制 + +**问题**: `new Date("YYYY-MM-DD")` 在 JavaScript 中会被当作 UTC 时间解析,导致 UTC+8 时区下出现 8 小时偏移。 + +**解决方案**: 使用安全日期解析函数 + +```javascript +function parseDate(dateStr) { + if (dateStr.includes('T')) { + return new Date(dateStr); // 完整时间戳直接解析 + } + + const parts = dateStr.split('-'); + if (parts.length === 3) { + // 按本地时区构造日期,月份从 0 开始 + return new Date( + parseInt(parts[0]), + parseInt(parts[1]) - 1, + parseInt(parts[2]) + ); + } + + return new Date(dateStr); // 兜底 +} +``` + +### 6.3 排序字段选择 + +**规则**: 使用 `createdAt` 而非 `date` 进行记录排序 + +**原因**: `date` 字段存储业务日期,可能存在 UTC 转换问题;`createdAt` 是系统自动生成的创建时间戳,更准确反映记录顺序。 + +--- + +## 七、错误码汇总 + +### 7.1 HTTP 状态码 + +| 状态码 | 说明 | 常见场景 | +|--------|------|---------| +| 200 | 成功 | 请求成功处理 | +| 400 | 客户端错误 | 参数缺失、校验失败 | +| 404 | 资源不存在 | 记录/账户/预算不存在 | +| 500 | 服务端错误 | 数据库异常 | + +### 7.2 Prisma 错误码 + +| 错误码 | 说明 | 处理策略 | +|--------|------|---------| +| P2002 | 唯一约束冲突 | 返回友好提示(如"邮箱已被注册") | +| P2025 | 记录不存在 | 返回 404 状态 | + +--- + +## 八、前端调用示例 + +### 8.1 获取账户列表 + +```typescript +import { apiClient } from '@/services/apiClient'; +import type { Account, ApiResponse } from '@/types'; + +const response: ApiResponse = await apiClient.get('/accounts', { + userId: 1 +}); + +if (response.success) { + console.log('账户列表:', response.data); +} +``` + +### 8.2 创建交易记录 + +```typescript +const response: ApiResponse = await apiClient.post('/records', { + userId: 1, + accountId: 3, + type: 'expense', + amount: 68, + category: '餐饮', + description: '午饭', + date: '2026-04-27' +}); + +if (response.success) { + console.log('记录创建成功:', response.data); +} +``` + +### 8.3 获取仪表盘数据 + +```typescript +const response: ApiResponse = await apiClient.get( + '/dashboard/summary', + { userId: 1 } +); + +if (response.success) { + const { totalBalance, monthIncome, monthExpense, budgetUsage } = response.data; + console.log(`总余额: ¥${totalBalance}`); +} +``` + +--- + +## 九、API 变更记录 + +| 日期 | 版本 | 变更人 | 变更内容 | 影响范围 | +|------|------|--------|---------|---------| +| 2026-04-27 | v1.0.0 | 架构师 | 初始版本,定义所有核心接口 | 全模块 | +| 2026-04-27 | v1.0.1 | 后端 | 修复排序字段(date → createdAt) | /api/records | +| 2026-04-27 | v1.0.2 | 后端 | 增加日期安全解析逻辑 | POST /api/records | + +--- + +## 十、安全规范 + +### 10.1 当前状态 (MVP) + +- 所有接口通过 `userId` 参数做数据隔离 +- CORS 允许所有来源(仅开发环境) +- 无请求频率限制 + +### 10.2 生产环境要求 + +- [ ] 接入 JWT 鉴权,从 Token 解析 userId,禁止客户端传入 +- [ ] CORS 限制为前端域名 +- [ ] 增加请求频率限制(Rate Limit) +- [ ] 移除 `/api/init-test-data` 等开发接口 +- [ ] 增加 SQL 注入防护(Prisma 已提供基础防护) +- [ ] 增加请求体大小限制(防止 DoS 攻击) +- [ ] 增加 HTTPS 强制 + +--- + +**文档版本**: v1.0.2 +**最后更新**: 2026-04-27 +**维护人**: 架构师 +**反馈渠道**: 提交 Issue 至项目仓库 \ No newline at end of file