# 05 API 与业务流程规范 ## 1. API 命名 REST 为主。 示例: - POST `/api/v1/auth/wechat/login` - GET `/api/v1/me` - POST `/api/v1/service-applications` - GET `/api/v1/service-applications/:publicId` - POST `/api/v1/admin/service-applications/:publicId/transition` - POST `/api/v1/admin/service-cases` - POST `/api/v1/admin/service-cases/:publicId/records` - POST `/api/v1/admin/follow-ups/:publicId/complete` 不使用: - `/getAllXXX` - `/doSomething2` - `/updateStatusDirectly` ### Phase 1 认证与权限 API - `POST /api/v1/auth/wechat/login`:提交一次性 `code`,服务端通过微信 Adapter 换取身份;返回短期 Bearer 会话,不返回 openid/unionid。 - `GET /api/v1/me`:读取当前微信用户。 - `POST /api/v1/auth/logout`:撤销当前微信会话。 - `POST /api/v1/admin/auth/login`:后台账号密码登录;仅允许配置的后台 Origin,成功后设置 HttpOnly、SameSite=Strict Cookie,响应体不含 token。 - `GET /api/v1/admin/auth/me`:校验 ADMIN 渠道会话和 `admin:access` 权限。 - `POST /api/v1/admin/auth/logout`:撤销会话并清除 Cookie。 - `PUT /api/v1/admin/users/:publicId/roles`:需要 ADMIN 渠道与 `roles:manage`,事务替换角色并写审计。 ### Phase 2 服务申请 API - `GET /api/v1/service-categories`:公开读取 V1 已批准服务分类。 - `POST /api/v1/service-applications`:仅微信 Bearer 会话;每用户入口限流;提交本人或代申请。 - `GET /api/v1/service-applications?page=1&pageSize=20`:仅返回当前申请人的申请,手机号默认脱敏。 - `GET /api/v1/service-applications/:publicId`:仅申请人本人可读取;随机 `publicId` 之外仍执行资源归属检查。 - `GET /api/v1/admin/service-applications`:仅 ADMIN 渠道且具有 `applications:read`;支持申请编号、服务分类、状态及分页筛选。 - `GET /api/v1/admin/service-applications/:publicId`:同上;读取为提供服务所必需的详情并写审计。 Phase 2 不提供状态流转、受理或创建工单接口;这些属于 Phase 3,不能通过直接更新状态提前实现。 ### Phase 3 服务对象与工单 API - `POST /api/v1/admin/service-applications/:publicId/transition`:严格执行 `SUBMITTED → PENDING_CONTACT → ASSESSING`,每次变更事务写历史和审计。 - `POST /api/v1/admin/service-applications/:publicId/accept`:仅允许从 `ASSESSING` 接单;以 `clientRequestId` 幂等,事务建立或关联服务对象、生成 `ASSIGNED` 工单、指派负责人并将申请推进到 `SERVICE_PLANNED`。 - `GET /api/v1/admin/beneficiaries`、`GET /:publicId`、`PUT /:publicId`:分页筛选、详情审计和档案维护;列表手机号默认脱敏。 - `GET /api/v1/admin/beneficiaries/tags`:返回固定服务标签选项。 - `GET /api/v1/admin/service-cases`、`GET /:publicId`:按资源范围返回工单;无全量权限时仅返回本人被指派工单。 - `GET /api/v1/admin/service-cases/assignee-options`、`PUT /:publicId/assignees`:列出有效工作人员/志愿者并事务替换协作人员。 - `POST /api/v1/admin/service-cases/:publicId/start`:仅工单负责人可执行 `ASSIGNED → IN_SERVICE`,同时推进关联申请。 - `POST /api/v1/admin/service-cases/:publicId/records`、`PATCH /:publicId/records/:recordPublicId`:被指派人员写服务记录;创建幂等,修改使用 `expectedRevision` 乐观锁并保存加密修订快照。 - `GET /api/v1/service-cases`、`GET /:publicId`、`POST /:publicId/records`:微信渠道志愿者协作接口;只允许读取本人被指派工单,详情返回最小必要字段。 - `POST /api/v1/service-cases/:casePublicId/files/upload-intents`、`POST /api/v1/files/:publicId/confirm`、`GET /api/v1/files/:publicId/download-url`:私有对象存储短期上传、元数据确认和短期下载地址。 ### Phase 4 回访闭环 API - `POST /api/v1/admin/service-cases/:publicId/complete`:仅工单负责人可完成 `IN_SERVICE` 工单;要求至少一条服务记录,以 `clientRequestId` 幂等,并在一个事务内完成工单、申请状态历史和自动回访。 - `GET /api/v1/admin/follow-ups/summary`:按资源范围返回今日到期、逾期、未来 7 日和重点关爱待办计数。 - `GET /api/v1/admin/follow-ups`、`GET /:publicId`:按负责人或全量资源权限分页查看回访;原因和结果仅在授权详情中解密。 - `POST /api/v1/admin/follow-ups`:创建人工或重点关爱回访;重点关爱类型要求对象档案已设置 `keyCareFlag`。 - `POST /api/v1/admin/follow-ups/:publicId/complete`:仅任务负责人完成回访;结果为 `NEED_MORE_HELP` 时必须显式确认服务对象/监护人授权并填写新需求。 ### Phase 5 公益项目、活动与志愿者 API - `GET/PUT /api/v1/me/volunteer`:微信用户读取或提交本人志愿者资料;提交使用客户端 UUID 幂等和 `expectedRevision` 乐观锁。已认证志愿者修改姓名或手机号后自动回到待审核并撤销志愿者角色。 - `GET /api/v1/admin/volunteers`、`GET /:publicId`、`POST /:publicId/review`、`POST /:publicId/restore`:分页审核志愿者并执行 `APPLIED → APPROVED/REJECTED`、`APPROVED → SUSPENDED`、`SUSPENDED → APPROVED`;状态、角色、历史和审计事务一致。 - `GET /api/v1/public/projects`、`GET /:publicId`:匿名读取已公开且处于已发布/已完成状态的项目;草稿和内部项目不返回。 - `GET/POST /api/v1/admin/projects`、`GET/PATCH /:publicId`、`POST /:publicId/transition`:按负责人或全量资源权限维护项目;项目严格执行 `DRAFT → PUBLISHED → COMPLETED`,编辑使用 revision 乐观锁。 - `PUT /api/v1/admin/projects/:publicId/service-cases`:事务替换项目归集的服务工单;无全量权限时禁止把其他项目工单转移到当前项目。 - `GET /api/v1/admin/project-manager-options`:返回有效 `PROJECT_MANAGER` 工作人员作为受控负责人选项。 - `GET /api/v1/public/activities`、`GET /:publicId`:匿名读取非草稿活动及公开项目下活动。 - `GET/POST /api/v1/admin/activities`、`GET/PATCH /:publicId`、`POST /:publicId/transition`:维护活动并严格执行 `DRAFT → PUBLISHED → REGISTRATION_CLOSED → IN_PROGRESS → COMPLETED`,允许未完成活动转为 `CANCELLED`。 - `POST /api/v1/activities/:publicId/registrations`:仅已认证志愿者报名;事务锁定活动行后校验发布状态、截止时间、有效报名数、容量和 `(activity,user)` 唯一约束。 - `GET /api/v1/me/activity-registrations`、`POST /:publicId/cancel`:读取或取消本人报名,不暴露他人记录。 - `GET /api/v1/admin/activity-registrations`、`POST /:publicId/review`、`POST /:publicId/check-in`、`POST /:publicId/service-minutes`:审核报名、活动进行中签到/缺席、活动完成后核定服务分钟;每次写入均有幂等历史和审计。 - `POST /api/v1/admin/media/upload-intents`、`POST /api/v1/admin/media/:publicId/confirm`:项目/活动封面使用真实 S3 兼容 Adapter 的短期上传和元数据确认;对象存储未配置时明确返回 `STORAGE_UNAVAILABLE`。 业务接口默认需要认证;只有显式标注 Public 的接口可以匿名访问。角色授权之外,资源归属/负责范围必须继续通过 resource policy 判断,不能只依赖角色。 成功响应统一为 `{ data, requestId }`,失败响应统一为 `{ error: { code, message, details? }, requestId }`。 --- ## 2. 服务申请提交事务 伪代码: ```text validate input check idempotency key resolve applicant user create or leave beneficiary unlinked create service_application create initial status history create audit log commit enqueue notification return public_id + application_no ``` 客户端为一次提交生成 UUID v4 `clientRequestId`。数据库以 `(applicant_user_id, client_request_id)` 建唯一约束:同一标识和相同规范化内容返回原结果并标记 `idempotentReplay=true`;同一标识对应不同内容返回 `DUPLICATE_REQUEST`。请求内容指纹使用密钥化、域隔离 HMAC,不保存可离线枚举的原始摘要。 Phase 2 必填项为服务分类、申请方式、服务对象称呼、联系人手机号、所在地区、需求描述及显式隐私同意;可选项为方便联系时间、是否需要上门、是否行动不便。服务分类固定为关爱老人、困境妇女、儿童关爱、残障帮扶、生活困难和其他服务。 禁止在事务中等待第三方消息服务。 --- ## 3. 受理 工作人员: 1. 打开申请; 2. 权限检查; 3. 联系服务对象; 4. 评估; 5. 可关联已有档案或建立档案; 6. ACCEPTED; 7. 创建 service_case; 8. 指定负责人; 9. 创建后续任务; 10. 通知用户。 ### Phase 6 已实现接口 - 公开内容:`GET /api/v1/content`、`GET /api/v1/content/:publicId`,只返回已发布内容。 - 内容管理:`/api/v1/admin/content` 创建/查看/编辑草稿和 `transition` 审核迁移,权限为 `content:read/manage/review`。 - 站内消息:`/api/v1/me/notifications`、读消息和通知偏好,按当前用户强制隔离。 - 微信投递:`/api/v1/admin/notification-deliveries` 查询、重试、处理,权限为 `notifications:manage`。 ### Phase 7 已实现接口 - `GET /api/v1/admin/statistics/overview`:日期范围最多 366 天,权限 `statistics:read`。 - `GET /api/v1/admin/statistics/export.csv`:仅汇总无个人字段,权限 `exports:create` 并审计。 - `GET /health/live`、`GET /health/ready`;`GET /api/v1/admin/system/metrics` 需 `system:manage`。 Phase 3 实现中,“关联已有档案”必须同时满足手机号 HMAC 精确匹配和人工确认,不按姓名自动合并。新建未成年人档案必须包含监护人并记录独立授权。 --- ## 4. 服务执行 - 申请 `SERVICE_PLANNED → IN_SERVICE`,工单 `ASSIGNED → IN_SERVICE` - 新增 service_record - 上传附件 - 可多次服务 - 完成时填写 result_summary - `IN_SERVICE → SERVICE_COMPLETED` - 自动生成 follow_up_task Phase 4 已开放完成入口。工单 `IN_SERVICE → SERVICE_COMPLETED`、申请 `IN_SERVICE → SERVICE_COMPLETED → FOLLOW_UP_PENDING`、三类状态历史、自动回访和审计在单一事务完成;任一步失败则全部回滚。 --- ## 5. 回访 完成回访时: - 写结果; - 标记任务完成; - 如果需要继续帮助,创建 linked application(新工单仍须按既有评估/受理流程生成,不能跳过); - 记录来源关系; - 写 audit。 `NEED_MORE_HELP` 的事务同时创建新的 consent 和 `SUBMITTED` 申请、记录来源关系、完成回访并将原 `FOLLOW_UP_PENDING` 申请关闭。新申请不覆盖原申请、工单、服务记录或历史。普通完成回访只闭合原申请,不生成新申请。 --- ## 6. 文件上传 推荐流程: 1. 客户端申请上传凭证; 2. 后端检查业务权限和文件约束; 3. 生成短期上传签名或后端代理上传; 4. 上传完成后回调/确认; 5. 后端校验 object metadata; 6. files 表记录; 7. 业务表关联 file_id。 安全约束: - 文件大小限制; - MIME 白名单; - 扩展名白名单; - object key 随机; - 禁止使用原始文件名作路径; - 图片需要时进行安全转码; - 下载使用短时签名 URL; - 私有 Bucket 默认。 --- ## 7. 分页 统一 cursor 或 page/pageSize。V1 可使用: - page >= 1 - pageSize 默认 20,最大 100 返回: ```json { "items": [], "page": 1, "pageSize": 20, "total": 120 } ``` --- ## 8. 搜索 后台允许按: - 业务编号 - 姓名/称呼 - 脱敏手机号后四位(视实现) - 服务类别 - 状态 - 时间 - 项目 - 负责人 敏感全文搜索能力应谨慎开放。 --- ## 9. 导出 任何导出: - 必须权限校验; - 记录审计; - 限制数据范围; - 大数据量异步生成; - 文件有过期时间; - 默认脱敏; - 导出儿童等敏感信息需要更高权限。 --- ## 10. 错误码 至少: - AUTH_REQUIRED - FORBIDDEN - RESOURCE_NOT_FOUND - VALIDATION_ERROR - DUPLICATE_REQUEST - INVALID_STATE_TRANSITION - APPLICATION_NOT_FOUND - CASE_NOT_FOUND - VOLUNTEER_NOT_APPROVED - ACTIVITY_FULL - REGISTRATION_CLOSED - RESOURCE_CONFLICT - FILE_TYPE_NOT_ALLOWED - FILE_TOO_LARGE - RATE_LIMITED - INTERNAL_ERROR 用户端错误文案必须友好,日志保留 requestId 便于排障。 --- ## 11. 健康检查 Phase 0 提供: - `GET /health` 成功响应: ```json { "status": "ok", "service": "api", "timestamp": "2026-08-10T12:00:00.000Z" } ``` 健康检查不得返回配置值、数据库连接串、密钥或其他敏感信息。业务 API 仍统一使用 `/api/v1` 前缀;基础设施健康检查不属于业务 API。 --- ## 12. 财务公开文档 API 公众接口: - `GET /api/v1/financial-disclosures` - `GET /api/v1/financial-disclosures/:publicId` 只返回 `PUBLISHED` 文档,草稿和归档文档按不存在处理。 管理端接口: - `GET/POST /api/v1/admin/financial-disclosures` - `GET/PATCH /api/v1/admin/financial-disclosures/:publicId` - `POST /api/v1/admin/financial-disclosures/:publicId/transition` 创建、发布和归档使用客户端 UUID 幂等;编辑只允许草稿且要求 expectedRevision。状态为 `DRAFT → PUBLISHED → ARCHIVED`,状态变化与历史、审计事务一致。DOCX 在管理端浏览器转换为富文本,API 只接受并白名单清洗富文本,不执行 Office 文件。 --- ## 13. 旧物善用 Phase 1 API 公众只读接口: - `GET /api/v1/old-items/stats` - `GET /api/v1/old-items/needs`、`GET /api/v1/old-items/needs/:publicId` - `GET /api/v1/old-items/drop-off-points` 微信会话接口: - `POST /api/v1/old-items/media/upload-intents`、`POST /api/v1/old-items/media/:publicId/confirm` - `GET /api/v1/old-items/me/media/:publicId/download`(本人私有图片短期 URL) - `POST /api/v1/old-items/donations` - `GET /api/v1/old-items/me/donations`、`GET /api/v1/old-items/me/donations/:publicId` 管理端接口: - `GET /api/v1/admin/old-items/donations`、`GET /api/v1/admin/old-items/donations/:publicId` - `GET /api/v1/admin/old-items/assignees` - `GET /api/v1/admin/old-items/media/:publicId/download`(授权管理人员短期 URL) - `POST /api/v1/admin/old-items/donations/:publicId/transition` - `GET/POST /api/v1/admin/old-items/needs`、`GET/PATCH /api/v1/admin/old-items/needs/:publicId` - `POST /api/v1/admin/old-items/needs/:publicId/transition` - `POST /api/v1/admin/old-items/drop-off-points` 捐赠创建、需求创建及全部状态变化使用客户端 UUID 幂等。状态变化要求 `expectedRevision`,通过条件更新、只追加历史和审计在一个数据库事务中提交。本人接口按 donor user 强制隔离;管理端敏感详情查看单独审计。图片最多六张,使用私有对象前缀、短期预签名上传和对象元数据确认,不返回永久公开地址。 捐赠主流程为 `SUBMITTED → WAITING_PICKUP/WAITING_DROP_OFF → RECEIVED → PROCESSING → COMPLETED`;审核可进入 `REJECTED`,接收前可进入 `CANCELLED`。完成定向捐赠时在同一事务增加需求已满足数量。统计直接从已接收或已完成捐赠事实计算,不提供人工覆盖接口。 --- ## 14. 旧物善用 Phase 2 台账 API 管理端接口: - `GET/POST /api/v1/admin/old-items/inventory` - `GET /api/v1/admin/old-items/inventory/:publicId` - `POST /api/v1/admin/old-items/inventory/import` - `POST /api/v1/admin/old-items/inventory/:publicId/transition` - `GET /api/v1/admin/old-items/inventory-export/file` 权限拆分为 `old_item_inventory:read/manage/import/export`。手工入库和批量导入都创建 `IN_STOCK` 主记录与 `INBOUND` 事件;批量导入最多 500 行、全有或全无。状态只允许 `IN_STOCK → SORTED → DISINFECTED → OUTBOUND → DELIVERED`。出库必须绑定定向需求、有效受助对象或帮扶区域之一,落地必须填写实际帮扶人数。所有创建/导入/状态变更使用客户端 UUID、请求指纹、revision、条件更新、只追加事件和事务审计。 导出最多 5000 条,返回用于浏览器生成 `.xlsx` 的最小化结构化行,不包含联系人、手机号、详细地址、受助对象姓名和内部备注,并记录导出审计。小程序既有捐赠详情响应增加 `inventoryTrace`,仅包含状态、时间以及出库/落地的粗粒度地区。 --- ## 15. 旧物善用 Phase 3 荣誉 API 微信会话接口: - `GET /api/v1/old-items/me/rewards` - `GET /api/v1/old-items/me/certificates/:publicId` 管理端接口: - `GET /api/v1/admin/old-items/reward-config` - `POST /api/v1/admin/old-items/reward-config/activate` - `GET /api/v1/admin/old-items/reward-accounts` - `POST /api/v1/admin/old-items/reward-accounts/:userPublicId/adjust` - `GET /api/v1/admin/old-items/certificates` - `POST /api/v1/admin/old-items/donations/:publicId/certificate` - `POST /api/v1/admin/old-items/certificates/:publicId/revoke` 管理端权限拆分为 `old_item_rewards:read/manage`。规则激活、补发、撤销和积分调整使用客户端 UUID、请求指纹及事务审计;积分调整还要求账户 `expectedRevision`,不允许调整为负余额。证书模板仅允许固定纯文本占位符,由服务端渲染并作为快照保存,不接受 HTML。本人接口按用户资源归属隔离;不存在公众证书查询接口。 捐赠直接完成或关联物资台账落地时,证书与积分随 `COMPLETED` 状态在同一事务生成。证书补发不会重复计分;规则变更不追溯修改既有证书和流水。