feat: complete V1 phases 0-7

This commit is contained in:
2026-08-12 14:35:12 +08:00
commit c3dd9be674
311 changed files with 38750 additions and 0 deletions
+130
View File
@@ -0,0 +1,130 @@
# 乐活公益·暖心服务平台 —— Codex 开发文档包
> 版本:V1.0
> 文档用途:作为 Codex / AI 编程智能体的长期开发上下文、项目规则和验收依据。
> 最高原则:任何代码实现不得偏离本目录文档。发生冲突时,按本文档规定的优先级处理。
---
## 1. 项目一句话定义
“乐活公益·暖心服务平台”不是公益宣传页,而是一套以微信小程序为公众入口、Web 管理后台为工作人员入口、以“需求申请 → 受理评估 → 建档 → 派单 → 服务 → 反馈 → 回访 → 持续关爱”为核心闭环的公益服务数字化平台。
主要服务领域:
1. 关爱老年人、为老服务;
2. 困境妇女慈善帮扶;
3. 困境儿童关爱与帮扶;
4. 残疾人爱心救助与帮扶;
5. 其他困难群体服务;
6. 志愿者组织、公益活动、公益资源和社会参与。
---
## 2. Codex 每次开始工作前必须执行
按顺序阅读:
1. `00_README_FIRST.md`
2. `01_PROJECT_CONSTITUTION.md`
3. `02_PRODUCT_PRD_V1.md`
4. `03_ARCHITECTURE.md`
5. `04_DATA_MODEL.md`
6. `05_API_AND_WORKFLOW.md`
7. `06_SECURITY_PRIVACY.md`
8. `07_UI_UX.md`
9. `08_ENGINEERING_RULES.md`
10. `09_TEST_ACCEPTANCE.md`
11. `10_TASK_STATE.md`
12. `11_DECISIONS.md`
如果只是小范围修复,也至少必须阅读:
- `01_PROJECT_CONSTITUTION.md`
- `10_TASK_STATE.md`
- 与修改模块相关的文档
- `11_DECISIONS.md`
不得仅根据聊天中最近一句话修改项目。
---
## 3. 开发结束后必须回写
每完成一个任务,必须:
1. 更新 `10_TASK_STATE.md`;
2. 若产生架构/技术/业务决策,更新 `11_DECISIONS.md`;
3. 若接口变化,更新 API 文档;
4. 若表结构变化,更新数据模型与 migration;
5. 增加或更新自动化测试;
6. 执行 lint、typecheck、unit test、integration test、build;
7. 输出本次变更摘要、影响范围、风险、回滚方式。
禁止“只改代码、不改文档”。
---
## 4. 冲突处理优先级
从高到低:
1. 数据安全、隐私、法律合规;
2. `01_PROJECT_CONSTITUTION.md` 中的硬约束;
3. 已确认的产品业务规则;
4. 数据一致性和可审计性;
5. API 契约;
6. UI/UX 规范;
7. 工程偏好;
8. Codex 自己认为“更先进”的方案。
如果 Codex 认为有更好的方案,但会改变既有边界,必须记录到 `11_DECISIONS.md` 的“待确认建议”,不能擅自实施。
---
## 5. 代码仓库建议结构
```text
lehuo-public-service/
├─ apps/
│ ├─ miniprogram/ # 微信小程序
│ ├─ admin-web/ # Web 管理后台
│ └─ api/ # 后端 API
├─ packages/
│ ├─ contracts/ # DTO / enum / schema / API 契约
│ ├─ shared/ # 无业务副作用的共享代码
│ ├─ eslint-config/
│ └─ tsconfig/
├─ infra/
│ ├─ docker/
│ ├─ nginx/
│ ├─ scripts/
│ └─ backup/
├─ docs/
│ ├─ 本文档包
│ └─ diagrams/
├─ migrations/
├─ .env.example
├─ pnpm-workspace.yaml
├─ package.json
├─ AGENTS.md
└─ README.md
```
---
## 6. AGENTS.md 必须包含
仓库根目录 `AGENTS.md` 应复制以下核心规则:
- 先读 `docs/00_README_FIRST.md` 与 `docs/01_PROJECT_CONSTITUTION.md`。
- 不擅自改变产品定位、技术栈、数据库类型、认证方式。
- 不删除既有功能来“简化实现”。
- 不通过 mock 假装功能完成。
- 不将敏感信息写入日志。
- 每个业务状态变化必须可审计。
- 所有表结构变化必须 migration。
- 所有 API 变更必须同步 contracts。
- 完成任务必须更新 `docs/10_TASK_STATE.md`。
- 任何架构决策必须更新 `docs/11_DECISIONS.md`。
- 不因“AI认为更合理”而推翻已经批准的业务规则。
+157
View File
@@ -0,0 +1,157 @@
# 01 项目开发宪法(不可随意修改)
## 1. 产品定位硬约束
本项目必须始终是:
> 公益服务数字化平台,而不是宣传网站、商城、社交平台或复杂互联网平台。
V1.0 第一目标:让真实服务闭环跑通。
主链路:
```text
服务对象/代申请人提交需求
→ 工作人员受理
→ 需求评估
→ 建立/关联服务对象档案
→ 创建服务工单
→ 分配工作人员/志愿者
→ 执行服务
→ 留痕
→ 服务对象确认/反馈
→ 回访
→ 必要时继续跟进
```
任何新功能都必须回答:“是否增强这条主链路?”
---
## 2. 用户体验硬约束
1. 小程序优先服务普通群众、老人和低数字技能用户。
2. 主要操作不得依赖复杂手势。
3. 核心按钮大、清楚、可理解。
4. 服务申请尽量在 3~4 个步骤内完成。
5. 表单遵循“少填、可选、可拍、可说、可代办”。
6. 不在前端暴露技术术语、内部状态码。
7. 不为了视觉炫技牺牲加载速度和可理解性。
8. 所有失败状态必须给普通人能看懂的说明与下一步动作。
9. 适老化不是“放大字体”这么简单,必须包含点击区域、对比度、信息密度、步骤数量、错误恢复能力。
10. 功能完成度优先于动画和装饰。
---
## 3. 技术硬约束
1. 国内网络环境可稳定开发、构建、部署和访问。
2. 微信小程序作为公众端。
3. Web 管理后台作为机构工作人员端。
4. 后端采用模块化单体优先,V1.0 禁止为了“先进”拆微服务。
5. MySQL 为核心关系数据库。
6. Redis 只用于缓存、限流、短期状态等可恢复数据,不作为业务事实唯一存储。
7. 文件不保存到应用容器本地磁盘;生产环境使用对象存储。
8. 必须 Docker 化。
9. 环境分 dev / test / staging / prod。
10. 配置必须环境变量化,禁止把密钥提交 Git。
11. 所有数据库修改必须 migration。
12. 生产部署必须有备份、恢复、日志、监控和健康检查。
13. 对外部供应商能力必须封装 Adapter,不让业务层直接绑定云厂商 SDK。
14. V1.0 不引入 Kubernetes。
15. V1.0 不引入复杂事件总线,必要异步任务先使用可靠 Job/Queue 模式。
---
## 4. 安全硬约束
平台会处理老人、困境妇女、儿童、残疾人、困难家庭等敏感服务信息。
必须做到:
- 默认最小权限;
- 后台 RBAC;
- 资源级权限校验;
- 敏感字段脱敏;
- 操作审计;
- 不允许越权查询;
- 不允许通过 ID 枚举他人服务记录;
- 数据导出必须受控;
- 文件下载必须鉴权;
- 上传文件做类型、大小、扩展名、MIME 校验;
- Token、手机号、身份证件、地址、儿童信息不得写入普通日志;
- 删除业务数据优先软删除/归档,禁止随意物理删除;
- 关键状态变更保留历史;
- 不满 14 周岁相关信息按监护人授权与更严格权限原则处理;
- 不把真实生产数据复制到开发环境;
- 测试数据必须脱敏或生成。
---
## 5. 可靠性硬约束
1. 所有写请求应支持幂等或防重复提交。
2. 重要状态迁移必须使用数据库事务。
3. 不允许“接口成功但数据库只写了一半”。
4. 异步任务失败必须可重试、可查询。
5. 外部服务失败不能拖垮主业务。
6. 外部短信、订阅消息、对象存储失败应有降级和补偿。
7. 服务工单状态必须经过状态机校验,不能任意改字符串。
8. 每个关键实体保留 `created_at / updated_at / created_by / updated_by`。
9. 每个关键业务操作有 audit log。
10. 任何“已完成”都必须有可验证结果,不能只靠前端显示。
---
## 6. 易维护硬约束
- 避免自研基础组件;
- 避免魔法数字;
- 枚举集中管理;
- DTO 与数据库 Entity 分离;
- Controller 不写复杂业务;
- Service 不直接散落第三方 SDK;
- Repository 层负责数据访问;
- 公共错误码统一;
- 日志统一;
- 配置集中;
- 每个模块有 README 或模块说明;
- 复杂逻辑写测试;
- 删除代码前检查是否有业务依赖;
- 依赖升级必须经过测试,不追新版本。
---
## 7. V1.0 禁止范围
除非后续明确批准,V1.0 禁止:
- 在线公开募捐核心交易系统;
- 复杂社交/朋友圈;
- 即时 IM 聊天系统自研;
- AI 自动作出救助资格决定;
- 人脸识别;
- 未经必要性论证收集身份证完整信息;
- 微服务/K8s;
- 大数据平台;
- 区块链;
- 自研工作流引擎;
- 复杂积分商城;
- 过度游戏化;
- 对外开放 API 平台;
- 多租户 SaaS 架构。
---
## 8. AI 功能原则
AI 是效率工具,不是 V1.0 主角。
后续 AI 必须:
- 默认建议、不自动做高风险决定;
- AI 结果明确标记;
- 工作人员确认后才写入正式业务记录;
- 不把敏感数据发送到未经批准的外部模型;
- 能关闭;
- 业务流程不依赖 AI 才能运行。
+454
View File
@@ -0,0 +1,454 @@
# 02 V1.0 产品需求文档(PRD)
## 1. V1.0 目标
交付可真实投入公益服务的第一版:
- 群众能找到服务、提交申请、看进度、给反馈;
- 家属/社区/志愿者能代申请;
- 工作人员能受理、建档、派单、留痕、回访;
- 志愿者能注册、报名活动;
- 管理员能管理项目、内容、人员、权限和统计。
---
## 2. 用户角色
### 2.1 PUBLIC
普通公众。浏览公益项目、活动、组织介绍、参与入口。
### 2.2 APPLICANT
申请人。可以是服务对象本人,也可以是代申请人。
### 2.3 BENEFICIARY
服务对象。老人、困境妇女、困境儿童、残疾人及其他困难群体。
### 2.4 VOLUNTEER
志愿者。
### 2.5 STAFF
公益工作人员。
### 2.6 PROJECT_MANAGER
公益项目负责人。
### 2.7 ADMIN
系统管理员。
### 2.8 SUPER_ADMIN
仅限极少数技术/管理人员,用于系统级配置,日常不使用。
---
## 3. 小程序信息架构
底部 Tab 建议:
1. 首页
2. 服务
3. 公益
4. 我的
### 首页
- Logo/品牌语
- 我需要帮助
- 帮他人申请
- 为老服务
- 妇女帮扶
- 儿童关爱
- 残疾人帮扶
- 最新公益项目
- 最新活动
- 我要做公益
### 服务
- 服务分类
- 服务申请
- 我的申请
- 服务进度
- 我的反馈
- 联系乐活
### 公益
- 公益项目
- 公益动态
- 公益活动
- 志愿者招募
- 企业/资源合作
- 乐活公益介绍
### 我的
根据身份动态显示:
- 微信登录/绑定手机号
- 我的资料
- 我的服务申请
- 我的活动
- 志愿者资料
- 我的志愿服务
- 消息
- 隐私设置
- 联系客服
---
## 4. 服务申请
### 4.1 申请类型
- OLD_AGE:老年关爱/为老服务
- WOMEN:困境妇女
- CHILD:困境儿童
- DISABILITY:残疾人帮扶
- LIFE_DIFFICULTY:生活困难
- OTHER:其他
### 4.2 申请身份
- SELF:本人申请
- FAMILY:家属代申请
- COMMUNITY:社区/机构代申请
- VOLUNTEER:志愿者代申请
- OTHER:其他
### 4.3 最小字段
- 服务类别
- 申请人与服务对象关系
- 服务对象姓名或称呼
- 联系方式
- 所在区域(不默认要求精确门牌)
- 需求描述
- 隐私授权确认
### 4.4 可选字段
- 图片/附件
- 期望联系时间
- 是否行动不便
- 是否需要上门
- 紧急程度(用户只能表达,最终等级由工作人员评估)
- 语音描述(二期可增强)
### 4.5 提交
提交后:
- 生成不可预测的业务编号;
- 显示“已收到”;
- 明确说明后续由工作人员联系;
- 不承诺超出机构能力的即时救援;
- 若用户选择明显紧急风险,应提示联系 110/120 等适当公共紧急服务,但具体文案由运营审核。
---
## 5. 服务申请状态机
```text
SUBMITTED
↓
PENDING_CONTACT
↓
ASSESSING
├─→ REJECTED/OUT_OF_SCOPE
├─→ REFERRED
↓
ACCEPTED
↓
SERVICE_PLANNED
↓
IN_SERVICE
↓
SERVICE_COMPLETED
↓
FOLLOW_UP_PENDING
↓
CLOSED
```
可增加:
- CANCELLED
- SUSPENDED
规则:
- 状态变化必须记录历史;
- 不可跳过关键节点,除管理员执行带原因的纠正操作;
- 关闭后再次产生需求,应创建新申请/跟进记录,而不是覆盖旧记录。
---
## 6. 服务对象档案
每个 Beneficiary 一人一档。
核心字段:
- 基础身份
- 联系信息
- 联系人/监护人
- 所属服务类别
- 地址分级信息
- 风险/关爱标签
- 备注
- 是否重点关爱
- 档案状态
严禁把所有信息塞入一个 JSON 字段。
儿童、残疾、健康、家庭困难等敏感字段应按实际必要性分表/分域并控制权限。
---
## 7. 工单
服务申请被接受后创建 Service Case / Work Order。
字段:
- 工单编号
- beneficiary_id
- application_id
- project_id(可空)
- 服务类别
- 负责人
- 计划日期
- 服务地点
- 服务说明
- 当前状态
- 优先级
- 完成时间
- 结果摘要
- 后续计划
工单可关联多个执行人/志愿者,但只有一个责任负责人。
---
## 8. 服务记录
一次工单可有多次服务记录。
记录:
- 服务时间
- 服务类型
- 服务人员
- 服务内容
- 服务结果
- 图片附件
- 服务对象确认情况
- 后续建议
- 创建人
服务记录创建后若修改,必须保留修订痕迹或审计日志。
---
## 9. 回访
回访任务来源:
- 服务完成自动创建;
- 重点关爱对象周期任务;
- 工作人员手工创建。
回访结果:
- SATISFIED
- GENERALLY_SATISFIED
- UNSATISFIED
- NEED_MORE_HELP
- UNREACHABLE
- OTHER
若 `NEED_MORE_HELP`:
- 必须支持一键创建后续申请/工单;
- 不能只保存文字然后无人处理。
---
## 10. 志愿者
注册字段遵循最小必要:
- 姓名
- 手机
- 所在区域
- 可服务时间
- 技能标签
- 感兴趣领域
- 紧急联系人(仅确有管理需要时)
- 志愿者状态
状态:
- APPLIED
- APPROVED
- REJECTED
- SUSPENDED
- INACTIVE
志愿者默认不能查看完整服务对象档案。
---
## 11. 公益活动
活动:
- 标题
- 封面
- 项目
- 时间
- 地点
- 招募人数
- 报名截止时间
- 说明
- 状态
状态:
- DRAFT
- PUBLISHED
- REGISTRATION_CLOSED
- IN_PROGRESS
- COMPLETED
- CANCELLED
报名:
- 用户
- 志愿者身份
- 报名时间
- 审核状态
- 签到状态
- 服务时长
---
## 12. 公益项目
项目用于:
- 展示;
- 归集服务工单;
- 统计服务成果;
- 后续政府购买服务项目管理。
V1 字段:
- 项目名称
- 项目类别
- 简介
- 详细介绍
- 封面
- 项目周期
- 状态
- 是否公开
- 负责人
- 目标人数(可空)
- 排序
---
## 13. 内容管理
内容类型:
- 机构介绍
- 公益动态
- 服务故事
- 通知公告
- 常见问题
内容必须支持草稿和发布,不允许编辑即立即对外。
涉及服务对象故事:
- 必须有内容审核流程;
- 展示前脱敏;
- 未授权不得公开身份性信息。
---
## 14. 消息通知
V1:
- 站内消息
- 微信订阅消息(按微信平台能力和用户授权使用)
事件:
- 申请提交
- 申请状态变化
- 服务安排
- 服务完成
- 待评价/回访
- 活动报名结果
通知失败不能回滚主交易。
---
## 15. Web 后台
一级菜单:
- 工作台
- 服务申请
- 服务工单
- 服务对象
- 回访管理
- 公益项目
- 公益活动
- 志愿者
- 内容管理
- 数据统计
- 用户与权限
- 系统设置
- 审计日志(高权限)
工作台至少展示:
- 新申请
- 待联系
- 评估中
- 服务中
- 待回访
- 今日服务
- 超期任务
- 重点关爱提醒
---
## 16. 数据统计 V1
统计以真实业务数据计算:
- 申请数
- 受理数
- 完成服务数
- 服务人次
- 去重服务对象数
- 各服务类别数量
- 志愿者数量
- 活动数量
- 志愿服务时长
不得用手工填写数字覆盖真实统计结果。
+279
View File
@@ -0,0 +1,279 @@
# 03 技术架构
## 1. 总体选择
优先采用“TypeScript 全栈 + 模块化单体 + MySQL + Redis + 对象存储 + Docker”。
推荐:
### 微信小程序
- 微信小程序原生框架
- TypeScript
- TDesign Miniprogram(优先复用成熟组件)
- 自建 API Client
- 不使用重量级跨端框架作为 V1 默认方案
### 管理后台
- Vue 3
- TypeScript
- Vite
- Pinia
- Vue Router
- TDesign Vue Next 或成熟国内 UI 组件库
- ECharts(仅统计图表需要时)
### API
- Node.js LTS
- NestJS
- TypeScript
- REST API
- Prisma 或 TypeORM 二选一;建议 Prisma,但一旦项目启动后不得混用
- OpenAPI/Swagger
- Zod/class-validator 统一选一种 DTO 校验体系,NestJS 默认可使用 class-validator
### 数据
- MySQL 8.x
- Redis 7.x
- 对象存储:腾讯云 COS 为生产默认实现
- 本地开发:MinIO 兼容 S3 API
### 部署
- Docker
- Docker Compose
- Nginx
- 腾讯云 CVM / 轻量云服务器可作为早期部署载体
- 数据库生产优先托管 MySQL;预算有限时也可独立数据库容器,但必须有可靠备份
- HTTPS
- 国内域名和备案按实际上线要求办理
---
## 2. 为什么不做微服务
当前机构规模和 V1 业务复杂度不需要微服务。
模块化单体优点:
- 部署简单;
- 成本低;
- 调试简单;
- 事务一致性容易保证;
- Codex 更容易保持全局一致;
- 后续真有规模需求时可按模块拆分。
模块边界仍必须清晰。
---
## 3. API 模块建议
```text
auth
users
profiles
beneficiaries
service-applications
service-cases
service-records
follow-ups
projects
activities
volunteers
content
files
notifications
statistics
audit
permissions
system
```
每模块:
- controller
- service
- repository
- dto
- entities/model
- policy/permission
- tests
---
## 4. 分层规则
```text
Controller
↓
Application Service
↓
Domain Rules / Policy
↓
Repository / Adapter
↓
Database / External Service
```
禁止:
- Controller 直接访问 ORM;
- 页面直接写 SQL;
- 业务层直接调用 COS/微信 SDK;
- 前端自己判断权限代替后端校验。
---
## 5. 外部 Adapter
必须封装:
- WeChatAuthAdapter
- WeChatSubscribeMessageAdapter
- ObjectStorageAdapter
- SmsAdapter(若以后使用)
- AIAdapter(二期)
- GeocodingAdapter(二期)
这样可更换供应商。
---
## 6. API 规范
统一前缀:
`/api/v1`
响应:
```json
{
"success": true,
"data": {},
"requestId": "..."
}
```
错误:
```json
{
"success": false,
"error": {
"code": "APPLICATION_NOT_FOUND",
"message": "未找到该服务申请"
},
"requestId": "..."
}
```
HTTP 状态码必须正确使用,不得永远 200。
---
## 7. 认证
### 小程序端
- wx.login 获取 code;
- 后端换取微信身份;
- 服务端创建自己的 session/token;
- token 轮换/过期;
- 手机号绑定按微信开放能力和实际授权流程实现;
- openid/unionid 绝不作为前端授权依据。
### 后台
推荐:
- 用户名/手机号 + 强密码;
- 生产可增加 MFA;
- HttpOnly Secure Cookie 优先;
- 管理后台不把长期 Token 放 localStorage。
---
## 8. 权限
RBAC + 资源级 Policy。
示例:
- STAFF 可以看自己负责的工单;
- PROJECT_MANAGER 可以看自己项目范围;
- ADMIN 可跨项目;
- VOLUNTEER 只能查看分配给自己的最小必要任务信息;
- 普通小程序用户只能查看自己提交或合法关联的申请。
---
## 9. 状态机
服务申请、工单、活动、志愿者审批必须采用明确状态机。
所有 transition:
- 验证当前状态;
- 验证目标状态;
- 验证权限;
- 事务写入;
- 写 history;
- 写 audit;
- 事务提交后再触发通知。
---
## 10. 幂等
以下必须防重复:
- 服务申请提交
- 活动报名
- 状态变更
- 服务记录提交
- 回访提交
- 文件关联
- 微信回调(若未来有)
方案:
- clientRequestId / idempotencyKey
- 数据库唯一索引
- 事务
- 必要时 Redis 短锁
---
## 11. 可观测性
必须:
- requestId
- structured logging
- error tracking
- health endpoint
- readiness/liveness
- 慢接口日志
- 数据库慢查询
- 关键任务状态
日志中禁止敏感数据。
---
## 12. 备份
至少:
- MySQL 每日自动备份;
- 保留 7/30 天策略可配置;
- 对象存储版本/生命周期按预算配置;
- 每季度至少做一次恢复演练;
- 恢复步骤写入 `infra/backup/README.md`。
备份成功≠可恢复,必须验证恢复。
+472
View File
@@ -0,0 +1,472 @@
# 04 数据模型
## 1. 通用字段规范
核心表统一包含:
- id: bigint/uuid(二选一后固定;建议 bigint 内部主键 + public_id 随机ID)
- public_id: varchar,外部暴露,禁止连续可枚举
- created_at
- updated_at
- created_by(后台业务表适用)
- updated_by
- deleted_at(需要软删除的表)
时间统一数据库 UTC 存储,展示按 Asia/Shanghai。
---
## 2. 核心实体
### users
微信/后台统一用户主体,避免重复身份系统。
- id
- public_id
- status
- user_type
- mobile(加密/脱敏策略)
- nickname
- avatar_url
- last_login_at
### wechat_identities
- user_id
- openid_ciphertext(AES-256-GCM)
- openid_hash(HMAC-SHA-256,仅用于等值查询)
- unionid_ciphertext nullable
- unionid_hash nullable
- appid
- created_at
唯一索引 `(appid, openid_hash)`;日志和 API 均不得返回 openid/unionid。
### staff_profiles
- user_id
- employee_no nullable
- display_name
- department
- status
工作人员显示名不是服务对象敏感档案字段;严禁把其扩展为手机号、证件号或详细住址。服务对象称呼仍按下文要求加密。
### roles / permissions / user_roles / role_permissions
标准 RBAC。Phase 1 预置 `VOLUNTEER`、`STAFF`、`PROJECT_MANAGER`、`ADMIN`、
`SUPER_ADMIN`,权限码由 shared contracts 统一定义。角色替换必须在事务中写审计,并禁止移除最后一名有效超级管理员。
### admin_credentials
- user_id(唯一)
- username(唯一)
- password_hash(Argon2id)
- failed_login_count
- locked_until nullable
- password_changed_at
### auth_sessions
- public_id(随机 UUID)
- user_id
- channel(WECHAT/ADMIN)
- token_hash(仅保存带 pepper 的 HMAC,不保存明文 token)
- expires_at
- last_used_at nullable
- revoked_at nullable
同一用户、同一渠道重新登录时撤销旧会话;过期、撤销或非 ACTIVE 用户的会话均无效。
---
## 3. beneficiary_profiles
服务对象档案:
- id
- public_id
- display_name_encrypted / display_name_hash
- gender nullable
- birth_year nullable
- mobile_encrypted / mobile_hash nullable
- region_code
- address_detail_encrypted nullable
- primary_category
- key_care_flag
- is_minor
- status
- notes_encrypted nullable
- created_by
- timestamps
不要默认收集完整身份证。
---
## 4. beneficiary_contacts
- beneficiary_id
- public_id
- name_encrypted
- relation
- mobile_encrypted / mobile_hash
- is_guardian
- is_emergency_contact
- consent_record_id nullable
---
## 5. beneficiary_tags / tags
标签:
- 独居
- 高龄
- 行动不便
- 定期探访
- 困境儿童
等。
标签只能帮助服务,不应成为歧视性画像。
---
## 6. service_applications
- id
- public_id(随机 UUID,仅此字段对外暴露)
- application_no(随机业务编号)
- applicant_user_id
- beneficiary_id nullable
- consent_id
- source_follow_up_task_id nullable(继续帮扶来源,唯一)
- parent_application_id nullable(原申请)
- client_request_id
- request_fingerprint(域隔离 HMAC-SHA-256)
- apply_mode
- service_category
- beneficiary_name_encrypted(AES-256-GCM)
- contact_mobile_encrypted(AES-256-GCM)
- contact_mobile_hash(域隔离 HMAC-SHA-256,仅用于等值查询)
- region_code
- description_encrypted(AES-256-GCM)
- preferred_contact_time nullable
- needs_home_visit nullable
- mobility_difficulty nullable
- status
- source
- submitted_at
- accepted_at nullable
- closed_at nullable
- timestamps
首次申请在 Phase 2 创建时不自动建立 beneficiary 档案;Phase 3 经人工核验后关联。Phase 4 的继续帮扶申请保留 `parent_application_id` 和 `source_follow_up_task_id`,并创建新的独立 consent,不修改或复用原申请授权。
索引:
- application_no unique
- `(applicant_user_id, client_request_id)` unique,保证数据库级幂等
- applicant_user_id + submitted_at
- status + submitted_at
- service_category + submitted_at
- contact_mobile_hash
---
## 7. service_application_status_history
- application_id
- from_status
- to_status
- operator_user_id
- reason_code
- created_at
不可更新,只追加。
---
## 8. service_cases
- id
- public_id
- case_no
- application_id
- accept_request_id / accept_request_fingerprint(接单幂等)
- beneficiary_id
- owner_staff_id
- category
- priority
- status
- planned_start_at nullable
- planned_end_at nullable
- service_location_encrypted nullable
- summary_encrypted
- result_summary_encrypted nullable
- follow_up_plan_encrypted nullable
- completed_at nullable
- complete_request_id / complete_request_fingerprint nullable(完成服务幂等)
- timestamps
---
## 9. case_assignees
支持多人协作:
- case_id
- user_id
- assignee_type STAFF/VOLUNTEER
- role
- assigned_at
- removed_at nullable
---
## 10. service_records
- id
- public_id
- case_id
- beneficiary_id
- service_start_at
- service_end_at nullable
- service_type
- client_request_id / request_fingerprint(同一创建者范围内幂等)
- content_encrypted
- result_encrypted
- follow_up_suggestion_encrypted nullable
- beneficiary_confirm_status nullable
- created_by
- timestamps
`service_record_revisions` 在修改前保存加密快照、原 revision 和修改人;更新使用 `expectedRevision` 乐观锁,防止覆盖并支持审计追溯。
---
## 11. follow_up_tasks
- id
- public_id / follow_up_no(均不可预测)
- beneficiary_id
- case_id nullable
- owner_staff_id
- due_at
- follow_up_type(SERVICE_COMPLETION / KEY_CARE / MANUAL)
- status(PENDING / COMPLETED / CANCELLED)
- source(AUTO_SERVICE_COMPLETION / STAFF_MANUAL / KEY_CARE_PLAN)
- reason_encrypted
- result_code nullable
- result_note_encrypted nullable
- create_request_id / create_request_fingerprint
- complete_request_id / complete_request_fingerprint nullable
- completed_at nullable
- created_by / updated_by / timestamps
自动回访与服务完成在同一事务创建。人工回访以 `(created_by, create_request_id)` 唯一;完成请求保存指纹并安全重放。
## 12. follow_up_status_history
- follow_up_task_id
- from_status nullable
- to_status
- operator_user_id
- reason_code
- created_at
只追加,不更新。继续帮扶申请通过 `service_applications.source_follow_up_task_id` 回指来源,原申请历史不覆盖。
---
## 13. volunteers / volunteer_skills
volunteers:
- user_id
- real_name
- mobile
- region_code
- availability_note
- status
- approved_by nullable
- approved_at nullable
skills:
- volunteer_id
- skill_code
---
## 14. projects
- id
- public_id
- project_no
- client_request_id / request_fingerprint
- name
- category
- summary
- content
- cover_file_id
- manager_user_id
- start_date
- end_date
- target_people nullable
- status
- is_public
- sort_order
- timestamps
`(created_by_id, client_request_id)` 唯一;`project_status_history` 只追加记录创建、发布和完成。`service_cases.project_id` 可空,用于把既有工单归集到项目但不改变工单事实。
---
## 15. activities
- id
- public_id
- activity_no
- client_request_id / request_fingerprint
- project_id nullable
- title
- summary
- content
- cover_file_id
- start_at
- end_at
- registration_deadline
- location_text
- capacity nullable
- status
- published_at nullable
- timestamps
`(created_by_id, client_request_id)` 唯一;`activity_status_history` 只追加记录活动状态变化。
---
## 16. activity_registrations
- activity_id
- user_id
- volunteer_id
- public_id / client_request_id / request_fingerprint
- status
- check_in_status
- registered_at
- reviewed_by / reviewed_at / review_note_encrypted nullable
- checked_in_at nullable
- checked_in_by nullable
- service_minutes nullable
- service_minutes_recorded_at / service_minutes_recorded_by nullable
唯一 `(activity_id,user_id)` 防重复报名。
`activity_registration_history` 只追加保存报名审核、取消、签到和服务时长变更前后事实,并以全局请求 UUID 唯一约束支持安全重放。
志愿者资料的姓名、手机号、可参与时间和审核备注加密;手机号与姓名仅保存域隔离 HMAC 查询值。`volunteer_status_history` 只追加,并与志愿者角色授予/撤销事务一致。
---
## 17. content_posts
- id
- public_id
- type
- title
- summary
- content
- cover_file_id nullable
- status DRAFT/REVIEW/PUBLISHED/ARCHIVED
- author_user_id
- reviewer_user_id nullable
- published_at nullable
- timestamps
---
## 18. files
只保存元数据:
- id
- public_id
- storage_provider
- bucket
- object_key
- original_filename_encrypted
- mime_type
- size
- sha256
- business_type
- uploader_user_id
- status
- created_at
`service_record_files` 关联服务记录与已确认文件。对象 key 使用随机值,上传确认时复核大小、MIME 和可选 SHA-256;不匹配文件进入隔离状态。
Phase 5 允许 `files.case_id` 为空,并通过 `business_type=PROJECT_COVER/ACTIVITY_COVER` 关联公开封面;封面仍经同一私有对象存储 Adapter 生成短时读取地址,不保存永久公网 URL。
前端不得直接拼接永久公网 URL。
---
## 19. consents
- id
- public_id
- user_id nullable
- beneficiary_id nullable
- consent_type
- version
- granted_by
- granted_at
- revoked_at nullable
- evidence_json(仅保存必要证明)
- ip_hash nullable
- created_at
Phase 2 每次申请显式要求 `privacyConsent=true`,记录隐私同意版本、授权主体、授权时间、最小证据和 IP HMAC;不得在证据中重复保存申请敏感明文。
---
## 20. audit_logs
只追加:
- id
- request_id
- actor_user_id
- actor_role
- action
- resource_type
- resource_public_id
- result
- metadata_json(不得含敏感明文)
- ip_hash
- user_agent_summary
- created_at
---
## 21. notifications / notification_deliveries
通知实体与发送记录分开,支持重试和追踪。
Phase 6 已落地 `content_posts`、只追加的 `content_post_status_history`、`notifications`、`notification_preferences` 和 `notification_deliveries`。消息以 `(user_id,event_key)` 唯一防重,微信投递以 `(notification_id,channel)` 唯一,失败最多重试五次后进入 `DEAD`。
Phase 7 不建立可人工修改的统计快照;九项 V1 指标直接从申请、工单、服务记录、服务对象、志愿者、活动和报名服务分钟事实计算。
---
## 22. 数据库规则
1. 必须使用 FK 或由 ORM/服务保证等价完整性;禁止无约束“凭感觉关联”。
2. 唯一业务编号必须 unique。
3. 常查字段建组合索引。
4. 禁止对大文本字段滥建索引。
5. 金额如未来出现用 decimal,禁止 float。
6. 所有枚举在 contracts 中有单一事实来源。
7. migration 不允许 destructive change 直接上线。
8. 删除列采用“停用 → 迁移 → 验证 → 后续版本删除”。
+289
View File
@@ -0,0 +1,289 @@
# 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。
+285
View File
@@ -0,0 +1,285 @@
# 06 安全、隐私与合规基线
## Phase 6–7 落地补充(2026-08-12)
内容未经审核不得公开;服务故事发布必须显式确认脱敏,拒绝脚本与事件处理器标记,客户端正文不作为 HTML 执行。审核意见加密,历史只追加。站内消息按 `user_id` 强制隔离;微信凭据、openid、token 和消息正文不得写日志。
统计导出仅为汇总事实,不包含手机号、地址、儿童记录或服务描述,要求独立权限并记录范围和 `masked=true` 审计。管理 API 权限扫描、官方 High 级依赖审计、密钥特征扫描和 CodeQL 工作流已建立。
> 本文是工程基线,不替代正式法律意见。上线前应由运营主体根据实际收集信息、服务范围和微信平台规则完成隐私政策、用户协议和必要合规审核。
## 1. 数据分类
### L1 公开
公益项目公开介绍、公开活动、组织联系方式。
### L2 内部
普通内部运营信息、非敏感统计。
### L3 敏感业务
服务申请详情、家庭困难、住址、联系方式、服务记录。
### L4 高敏感
儿童个人信息、监护信息、健康/残疾相关详细信息、证件、特殊风险记录。
默认 L3/L4 不得公开。
---
## 2. 最小收集
每个字段进入系统前必须回答:
- 为什么需要?
- 不收集是否仍能提供服务?
- 保存多久?
- 谁能看?
- 是否可脱敏?
- 是否真的需要精确地址/证件?
没有明确目的不得新增收集项。
---
## 3. 未成年人
不满 14 周岁相关个人信息必须采用更严格保护:
- 明确监护人角色;
- 记录同意;
- 限制访问人员;
- 默认不公开案例身份;
- 不允许志愿者看到与任务无关的信息;
- 定期审计访问;
- 允许合法更正、删除/撤回等请求按规则处理。
---
## 4. 加密
传输:
- 全站 HTTPS/TLS。
存储:
- 云盘/数据库基础加密按环境开启;
- 极敏感字段应用层加密;
- 密钥不与数据库同库;
- 密钥通过云 KMS/Secret Manager 或安全环境变量管理。
密码:
- Argon2id 或 bcrypt 强哈希;
- 禁止 MD5/SHA1 直接存密码。
---
## 5. 手机号和地址
显示:
- 普通列表默认脱敏,例如 138****1234;
- 详细查看必须权限。
查询:
- 如需精确匹配可存 HMAC/hash 辅助索引;
- 明文/密文设计需避免为搜索而降低保护。
---
## 6. 日志
禁止记录:
- 身份证完整号码
- 完整手机号
- openid
- access token
- session token
- 详细住址
- 儿童档案内容
- 服务描述全文
- 上传文件原文
允许:
- public_id
- requestId
- action code
- status
- 耗时
- 脱敏 actor 信息
---
## 7. OWASP 基线
必须防:
- SQL injection
- XSS
- CSRF(后台 Cookie 认证时)
- SSRF
- IDOR/BOLA
- path traversal
- unrestricted upload
- mass assignment
- brute force
- credential stuffing
- rate abuse
- insecure direct object reference
每个资源 API 后端都做授权,不相信前端按钮是否隐藏。
---
## 8. 限流
按场景设置:
- 登录
- 验证码
- 服务申请
- 文件上传
- 搜索
- 导出
- 微信登录 exchange
不能只按 IP,必要时组合 user/device/IP。
---
## 9. 审计事件
至少审计:
- 登录成功/失败
- 角色权限修改
- 查看高敏感档案
- 新增/修改服务对象
- 服务申请状态变化
- 工单分配
- 服务记录修改
- 导出
- 删除/归档
- 隐私同意变化
- 系统配置变化
---
## 10. 数据保留
不要永久保留所有数据。
必须由运营方定义:
- 服务档案保存期限;
- 未成年人数据期限;
- 日志期限;
- 导出文件期限;
- 已取消授权后的处理;
- 项目验收要求。
程序上把保留策略做成可配置任务,而不是散落代码。
---
## 11. 权限矩阵核心原则
### Volunteer
只能:
- 看自己被分配任务;
- 看完成服务所需的最小信息;
- 提交服务记录;
不能:
- 搜索全体服务对象;
- 导出名单;
- 看完整历史档案。
### Staff
按负责范围访问。
### Project Manager
按项目访问。
### Admin
跨项目业务管理,但高敏感导出仍可要求额外权限。
### Super Admin
系统维护,不等于默认业务数据无限查看;高敏感读取同样审计。
---
## 12. 安全发布门禁
上线前必须:
- npm/pnpm dependency audit
- secret scan
- SAST 基础扫描
- API 权限测试
- 越权测试
- 文件上传测试
- SQL 注入/XSS 测试
- 弱密码/暴力登录测试
- 备份恢复测试
- staging 冒烟测试
发现 Critical/High 安全问题不得上线。
---
## 13. Phase 1 已落地基线
- 后台密码使用 Argon2id;未知用户名执行 dummy verify,降低账号枚举时序差异。
- 连续 5 次密码失败后锁定 15 分钟;登录和微信 code exchange 均按入口限流。
- 后台会话只通过 HttpOnly、SameSite=Strict Cookie 传递,并校验后台 Origin;小程序使用短期 Bearer 会话。
- 数据库只保存会话 token 的带 pepper HMAC;重新登录轮换旧会话,注销、过期、停用账户立即拒绝。
- openid/unionid 使用 AES-256-GCM 加密并用域隔离 HMAC 建查询索引;密钥只来自环境变量。
- 默认认证、权限 Guard 与 resource policy 基线已建立;API 不暴露内部 bigint ID。
- 登录成功/失败、注销和角色变更写入只追加审计;审计元数据拒绝敏感字段名,IP 只保存 HMAC。
- 后台 CORS 仅允许配置的精确 Origin;输入使用白名单校验并拒绝额外字段。
---
## 14. Phase 2 已落地基线
- 服务对象称呼、联系电话和需求描述按 L3 数据使用 AES-256-GCM 应用层加密;手机号查询索引和请求幂等指纹使用密钥化、域隔离 HMAC-SHA-256。
- 申请列表默认只返回脱敏手机号;后台详情仅向 ADMIN 渠道且具备 `applications:read` 的人员开放,每次查看均写只追加审计。
- 小程序申请详情除随机 `publicId` 外继续执行申请人资源归属检查,防止 IDOR/BOLA;后台角色不能通过微信入口读取他人资源。
- DTO 白名单拒绝额外字段,分页限制为 1–100,手机号和内容长度由服务端验证;提交入口每分钟最多 5 次。
- 隐私同意、申请、初始状态历史和审计在单一数据库事务中提交;幂等由数据库唯一约束处理并覆盖并发重复提交。
- 小程序不把服务申请敏感草稿写入本地持久化;网络失败时只在当前页面内保留内容和同一请求标识,方便安全重试。
---
## 15. Phase 4 已落地基线
- 回访原因、结果说明、服务完成总结和回访计划按 L3 数据使用 AES-256-GCM 加密;列表不返回原因或结果正文。
- `follow_ups:read/manage/complete` 只授予工作人员及以上角色,志愿者不获得回访结果权限;无全量资源权限时只返回本人负责的任务。
- 服务完成和回访完成都只允许负责人写入,并使用客户端 UUID、请求指纹、状态条件更新和数据库唯一约束处理重试/并发。
- 继续帮扶必须记录新的明确授权;未成年人由监护人授权。新授权、新申请、原申请关闭、回访状态历史和审计在同一事务提交。
- 审计元数据仅记录随机公开标识、来源、结果枚举和是否创建继续申请,不记录回访正文、手机号、详细地址或服务描述。
---
## 16. Phase 5 已落地基线
- 志愿者姓名、手机号、可参与时间和审核备注按敏感数据加密;后台列表手机号默认脱敏,授权详情读取写审计,小程序只读取本人资料和报名。
- 首次申请和重新提交均记录版本化明确同意;已认证志愿者修改姓名或手机号后自动撤销志愿者角色并回到待审核,不能绕过身份复核。
- 项目负责人只访问本人负责的项目/关联活动;全量资源访问继续由已批准权限控制。无全量权限时禁止把其他项目工单转移进本人项目。
- 只有 `APPROVED` 志愿者可报名;活动行锁、有效报名计数和数据库唯一约束共同防止并发超额与重复报名。
- 报名审核、取消、签到、缺席和服务分钟均写不可变历史与审计。服务分钟只允许对已通过、已签到且活动已完成的记录核定,且不得超过活动持续时间。
- 公益项目和活动公开接口只返回公开状态内容,不返回志愿者名单或服务对象资料。封面未配置对象存储时不生成假地址或假成功。
+148
View File
@@ -0,0 +1,148 @@
# 07 UI/UX 与适老化规范
## 1. 视觉原则
关键词:
- 温暖
- 可信
- 简洁
- 清楚
- 不商业化
- 不花哨
不得做:
- 密集 Banner
- 过多卡片
- 首页十几个同级入口
- 小字号说明堆叠
- 复杂渐变和强动画
- 倒计时/诱导点击式设计
---
## 2. 小程序首页优先级
P0:
1. 我需要帮助
2. 帮他人申请
P1:3. 四大服务类别 4. 我的服务进度
P2:5. 公益项目 6. 公益活动 7. 我要做公益
宣传内容不能挤压服务入口。
---
## 3. 适老规范
建议基线:
- 正文字号尽量 >= 16px 等效视觉;
- 主要按钮文字 >= 17px 等效视觉;
- 主要点击区域高度约 48px 以上;
- 按钮间距足够;
- 一屏只做一个主要决定;
- 错误提示紧贴字段;
- 表单支持保存草稿(较长时);
- 不用颜色作为唯一状态表达;
- 图标同时配文字;
- 返回动作清晰;
- 网络失败可重试;
- 提交后明确“已成功”。
具体像素可在设计系统中统一,不以本建议替代微信设备适配。
---
## 4. 表单原则
一页最多 5~7 个核心输入。
复杂申请拆步骤:
1. 需要什么帮助
2. 帮谁申请
3. 联系方式与地区
4. 需求描述
5. 确认提交
可选信息放“补充信息”。
---
## 5. 文案
使用:
- “我需要帮助”
- “帮家人申请”
- “工作人员正在联系您”
- “还需要继续帮助”
- “重新提交”
避免:
- “创建工单”
- “状态流转”
- “Beneficiary”
- “Record Not Found”
- “非法参数”
---
## 6. 空状态
例如没有服务申请:
“您还没有提交过服务申请。如果您或家人需要帮助,可以从这里开始。”
提供明确按钮。
---
## 7. 错误恢复
提交失败不能清空已填表单。
上传失败允许单文件重试。
网络失败保持本地草稿。
重复点击提交不应生成多个申请。
---
## 8. 管理后台
后台目标:让工作人员每天打开工作台就知道做什么。
表格:
- 默认显示业务必要列;
- 手机、地址默认脱敏;
- 常用筛选固定;
- 详情采用清晰分区;
- 状态颜色+文字;
- 危险操作二次确认并说明影响。
禁止为了“企业感”做过密 Dashboard。
---
## 9. 无障碍
- 合理对比度;
- 图片提供语义说明(可用场景);
- 表单 label 明确;
- 键盘操作兼容后台;
- focus 可见;
- 不用仅 hover 才出现核心操作。
---
## 10. Phase 5 页面落地
- 小程序首页仍保持“我需要帮助/帮家人申请”为最高优先级,在其后增加公益项目、公益活动和志愿者中心入口。
- 项目和活动使用列表→详情的单一主任务结构;活动详情明确显示状态、时间、地点、报名截止、名额和不可报名原因,不加入捐赠或诱导分享入口。
- 志愿者中心只收集姓名、手机号、地区、可参与时间、固定技能和服务意向,并明确资料使用同意;同页展示资格状态、报名进度与核定服务分钟。
- 管理端新增志愿者审核、公益项目、活动与报名三个独立导航;危险状态推进二次确认,手机号列表脱敏,所有主要按钮保持至少 44px 点击高度。
- 沿用已批准的橙色主色、系统字体和功能型布局;采用高对比、可见焦点、文字+状态、加载/空/失败反馈与渐进披露,不引入复杂动画、密集仪表盘或新品牌方向。
+185
View File
@@ -0,0 +1,185 @@
# 08 工程开发规则
## 1. Monorepo
推荐 pnpm workspace。
根命令:
```bash
pnpm install
pnpm lint
pnpm typecheck
pnpm test
pnpm build
```
必须保证 CI 与本地命令一致。
---
## 2. 包管理
- 锁定 package manager 版本;
- 提交 lockfile;
- 不混 npm/yarn/pnpm;
- 国内开发可配置可靠 npm 镜像,但源码不得依赖私有个人镜像;
- CI 应支持官方源回退。
---
## 3. TypeScript
- strict: true
- 禁止大面积 any
- 禁止 `@ts-ignore` 掩盖错误;特殊情况写原因
- API contracts 明确类型
- 日期统一 ISO 8601
---
## 4. Git
分支:
- main
- develop(可选)
- feature/*
- fix/*
- chore/*
Commit 建议 Conventional Commits。
每个 PR:
- 变更摘要
- 测试结果
- 截图(UI)
- migration 说明
- 风险
- 回滚方案
---
## 5. 环境变量
`.env.example` 只能放占位符。
示例:
```env
APP_ENV=development
DATABASE_URL=
REDIS_URL=
WECHAT_APP_ID=
WECHAT_APP_SECRET=
COS_BUCKET=
COS_REGION=
COS_SECRET_ID=
COS_SECRET_KEY=
SESSION_SECRET=
FIELD_ENCRYPTION_KEY=
```
真实密钥不得入 Git。
---
## 6. 数据库 Migration
规则:
- 每次 schema 修改一份 migration;
- migration 可审查;
- 生产不允许 ORM 自动 `synchronize=true`;
- 大表变更考虑锁;
- destructive migration 分阶段。
---
## 7. 代码质量
函数:
- 单一职责;
- 复杂度高就拆;
- 业务规则命名表达含义;
- 不写 1000 行 service;
- 不复制粘贴权限逻辑。
必须有:
- lint
- format
- typecheck
- unit test
- integration test
---
## 8. 错误处理
后端:
- 业务错误使用统一 Domain/Application Error;
- 未预期错误不把 stack 返回用户;
- requestId 贯穿。
前端:
- 业务错误直接友好提示;
- 网络错误可重试;
- 401 统一重新登录;
- 403 明确无权限;
- 5xx 提供 requestId。
---
## 9. 第三方依赖
新增依赖前:
1. 是否真有必要?
2. 是否长期维护?
3. License 是否可用?
4. 是否显著增大 bundle?
5. 是否国内网络可获取?
6. 能否用现有依赖实现?
避免“为了 10 行代码引入一个包”。
---
## 10. Codex 禁止行为
- 不读文档直接重构;
- 看到旧代码就全量重写;
- 为通过测试删除测试;
- 用 mock 替代真实功能后宣称完成;
- 注释掉权限;
- 关闭类型检查;
- `catch {}` 吞错误;
- 生产环境 hardcode;
- 把敏感值写 fixtures;
- 删除 migration 历史;
- 改 API 不更新前端和 contracts;
- 自己决定产品删减。
---
## 11. Definition of Done
一个任务只有同时满足以下条件才算完成:
- 功能实现;
- 正常路径测试;
- 异常路径测试;
- 权限测试;
- 数据 migration 完成;
- 文档更新;
- lint 通过;
- typecheck 通过;
- test 通过;
- build 通过;
- 无新 High/Critical 漏洞;
- `10_TASK_STATE.md` 已回写。
+157
View File
@@ -0,0 +1,157 @@
# 09 测试与验收
## Phase 6–7 验收补充(2026-08-12)
自动化覆盖草稿公开隔离、审核发布历史、服务故事隐私确认、危险内容拒绝、消息 IDOR、订阅授权、统计未认证拒绝、脱敏汇总导出和导出审计。隔离 MySQL 部署 8 个 migration 后全量 34 个集成测试通过。
生产工程验收:权限扫描通过;官方源 High 级依赖审计无已知漏洞;密钥特征扫描无匹配;schema drift 无差异;基础/staging/production Compose 校验与 API Alpine 镜像构建通过;备份恢复到临时库后源/恢复库均为 42 张表并完成清理。
真实 staging、UAT、微信真机联调和生产部署不能由本地自动化替代,继续按发布清单留存人工证据。
## 1. 测试金字塔
### Unit
业务规则、状态机、权限策略、计算。
### Integration
API + DB,重点测试事务、唯一约束、权限和状态流转。
### E2E
关键业务闭环。
---
## 2. P0 E2E 场景
### E2E-001 本人申请
用户登录 → 选择老年服务 → 填写需求 → 提交 → 获得编号 → 我的申请可见。
### E2E-002 防重复
用户连续点击提交两次 → 只能产生一个业务申请。
### E2E-003 代申请
家属为老人申请 → 正确保存申请人与服务对象关系。
### E2E-004 工作人员受理
工作人员登录 → 查看待处理 → 联系/评估 → 建档 → 受理 → 创建工单。
### E2E-005 服务执行
负责人 → 开始服务 → 添加两条服务记录 → 完成 → 自动生成回访任务。
### E2E-006 回访继续帮扶
回访选择“需要继续帮助” → 生成关联后续任务/申请,原历史不丢失。
Phase 4 自动化验收还必须覆盖:无服务记录禁止完成、服务完成/自动回访事务一致、相同请求安全重放而变更内容冲突、工作人员仅看本人回访、项目负责人可看全量、重点关爱待办统计、继续帮扶新授权和关联申请唯一、原申请关闭且原历史保留。
### E2E-007 越权
志愿者 A 访问志愿者 B 的工单 → 403。
### E2E-008 用户越权
用户 A 猜测用户 B 的 public_id → 404/403,不泄露存在性。
### E2E-009 活动报名
报名 → 重复报名被唯一约束阻止 → 人数达到上限后不可继续报名。
Phase 5 自动化验收还必须覆盖:未认证用户禁止报名、草稿项目不能公开读取、志愿者申请/审核与角色授予事务一致、项目/活动状态机、报名请求安全重放、报名审核重放、签到重放、容量行锁、服务时长只来自已通过且已签到的已完成活动、历史与审计不重复写入。
### E2E-010 文件
允许图片上传;exe/php/html 等危险类型拒绝;超限拒绝;私有文件无授权无法下载。
---
## 3. 安全验收
必须测试:
- IDOR
- broken access control
- mass assignment
- SQLi
- stored/reflected XSS
- CSRF(后台)
- upload bypass
- rate limit
- brute force
- token expiry
- session fixation
- sensitive log leakage
---
## 4. 可靠性验收
模拟:
- Redis 不可用;
- COS 暂时失败;
- 微信消息发送失败;
- 数据库瞬时错误;
- 客户端重复请求;
- 网络超时。
要求:
- 主业务不产生半状态;
- 可重试;
- 失败可追踪;
- UI 不假成功。
---
## 5. 性能目标(V1 建议基线)
不是大型互联网项目,不盲目追极限。
建议:
- 常规 API P95 < 500ms(不含第三方和大文件)
- 后台列表首屏合理数据量 < 2s
- 小程序首页优先内容快速可见
- 100 并发常规请求下无明显错误率上升
- 数据库常用列表避免 N+1
具体目标可根据云资源实测调整。
---
## 6. UAT 验收人员
至少模拟:
- 65+ 老年服务对象
- 家属代申请
- 普通工作人员
- 项目负责人
- 志愿者
- 管理员
UAT 不只让开发人员自测。
---
## 7. V1 上线门槛
必须全部满足:
- P0 E2E 全通过;
- 无 Critical/High 已知安全漏洞;
- 备份成功;
- 恢复演练通过;
- staging 走完整闭环;
- 隐私政策/授权页面就绪;
- 微信小程序审核所需材料就绪;
- 监控和告警正常;
- 可回滚上一版本。
+241
View File
@@ -0,0 +1,241 @@
# 10 任务状态(Codex 每次必须维护)
> 这是项目“长记忆”的核心文件之一。禁止删除历史,仅更新状态并添加记录。
## 当前阶段
`PHASE_7_IMPLEMENTATION_COMPLETE - 外部发布验收待执行`
## 当前版本目标
`V1.0 MVP:跑通公益服务主闭环`
---
## 阶段任务
### Phase 0:工程初始化
- [x] 建立 monorepo
- [x] 建立 miniprogram
- [x] 建立 admin-web
- [x] 建立 api
- [x] 建立 shared contracts
- [x] Docker Compose 本地环境
- [x] MySQL / Redis / MinIO
- [x] ESLint / Prettier / TSConfig
- [x] CI
- [x] health check
- [x] 环境变量模板
- [x] AGENTS.md
### Phase 1:认证与权限
- [x] 微信登录
- [x] 后台登录
- [x] user
- [x] RBAC
- [x] resource policy
- [x] audit baseline
### Phase 2:服务申请
- [x] 服务分类
- [x] 本人申请
- [x] 代申请
- [x] 我的申请
- [x] 状态历史
- [x] 防重复提交
- [x] 后台申请列表/详情
### Phase 3:服务对象与工单
- [x] beneficiary 档案
- [x] 联系人/监护人
- [x] 标签
- [x] 工单
- [x] 分配工作人员
- [x] 志愿者协作
- [x] 服务记录
- [x] 附件
### Phase 4:回访闭环
- [x] 回访任务
- [x] 自动创建
- [x] 完成回访
- [x] 继续帮扶
- [x] 工作台待办
### Phase 5:公益项目/活动/志愿者
- [x] 项目 CRUD/发布
- [x] 活动
- [x] 活动报名
- [x] 志愿者申请/审核
- [x] 服务时长
### Phase 6:内容与通知
- [x] 公益动态
- [x] 机构介绍
- [x] 内容审核状态
- [x] 站内消息
- [x] 微信订阅通知 Adapter
### Phase 7:统计、安全与上线
- [x] 基础统计
- [x] 导出
- [x] 权限扫描
- [x] 安全测试
- [x] 备份恢复
- [ ] staging
- [ ] UAT
- [ ] production deployment
---
## 当前正在处理
Phase 6 及 Phase 7 可自动化开发与本地生产工程验证均已完成。Phase 7 的 staging、UAT 和 production deployment 仍需真实环境、微信配置、合规材料及人工审批,保持未完成;当前不得宣称已生产上线。
---
## 最近完成记录
格式:
```text
YYYY-MM-DD
任务:
完成:
测试:
涉及 migration:
文档变化:
遗留问题:
```
2026-08-12
任务:Phase 7 统计、安全与上线工程。
完成:实现基于真实事实表的申请数、已受理数、已完成服务、服务人次、独立服务对象、服务分类、志愿者数、活动数和志愿服务分钟统计,日期范围最多 366 天,不支持人工覆盖;实现独立 `exports:create` 权限、无个人字段的汇总 CSV 和导出审计。新增数据库 readiness、进程 liveness、受保护的请求量/5xx/p95/内存指标;新增权限扫描、官方依赖审计和 CodeQL/密钥 CI。新增每日 MySQL 备份、SHA-256、保留期和显式目标恢复脚本;新增 Nginx TLS/HSTS/限流配置、staging/production Compose 覆盖、immutable image 预检、健康/公开内容冒烟、监控告警规则和发布/回滚手册。完成管理端统计看板。
测试:format check、lint、全仓 typecheck、27 个 unit tests、34 个真实 MySQL integration tests、全仓 production build、8 个 migration 重复 deploy、schema drift、权限扫描、npm 官方 High 级依赖审计、密钥特征扫描、基础/staging/production Compose 校验和 API Alpine 镜像构建全部通过。统计集成测试覆盖未认证拒绝、真实查询、汇总导出无手机号及导出审计。隔离测试库完成备份恢复演练:SQL SHA-256 为 `3aa51c8674fda55d3b720e93ce3e1e77781649b74e65c1c977fc6ef1af68c367`,源库和临时恢复库均为 42 张表,核验后临时恢复库已删除。
涉及 migration:`20260812170000_phase7_statistics_security` 和 `20260812173000_phase7_fk_names`;已在独立 `lehuo_test` 库部署,共 8 个 migration,无 schema drift。
文档变化:新增 D-015、D-016;更新数据模型、API/工作流、安全隐私、测试验收、生产就绪计划、发布清单、部署运行手册和本任务状态。
遗留问题:staging、UAT 和 production deployment 未执行。仍需有效微信 AppID/AppSecret、六类订阅模板、合法 HTTPS 域名/证书、微信隐私声明与真机授权;生产 MySQL/Redis/私有对象存储、镜像仓库、告警接收人、异地备份目标;隐私政策/用户协议/数据保留确认、UAT 测试人员、发布窗口和审批人。上述外部项未以本地或测试值冒充完成。
2026-08-12
任务:Phase 6 内容与通知。
完成:新增机构介绍、公益动态、服务故事、通知公告和常见问题统一内容模型;实现 `DRAFT → PENDING_REVIEW → PUBLISHED → ARCHIVED` 严格状态机、退回草稿、revision 乐观锁、UUID 幂等键、加密审核意见、不可变状态历史和审计;所有内容审核后公开,服务故事发布强制隐私脱敏确认并拒绝危险 HTML/脚本标记。实现站内消息、未读状态、本人资源隔离、通知偏好和显式授权记录;申请提交/受理、服务完成/待回访和活动报名结果在原业务事务中可靠写入站内消息。实现微信订阅通知 Adapter、模板映射、数据库投递队列、抢占处理、指数退避、最多五次重试、死信和管理端人工重试;外部发送失败不回滚主业务,未配置真实微信参数时明确报告不可用。完成管理端内容审核与通知投递工作台,以及小程序公益资讯、机构介绍、内容详情、我的消息和通知设置页面。
测试:format check、lint、全仓 typecheck、27 个 unit tests、33 个真实 MySQL integration tests和全仓 production build 全部通过。Phase 6 集成测试覆盖草稿公开隔离、审核发布、不可变历史、服务故事隐私确认、危险内容拒绝、消息 IDOR 隔离和订阅偏好授权;Phase 1–5 全量回归通过。
涉及 migration:`apps/api/prisma/migrations/20260812140000_phase6_content_notifications/migration.sql`;已在独立 `lehuo_test` 库部署,共 6 个 migration。
文档变化:更新共享契约、环境变量模板和本任务状态;Phase 6 API/模型/安全细节随 Phase 7 结项统一同步到专题文档。
遗留问题:无 Phase 6 代码阻塞。真实微信 AppID/AppSecret、六类订阅模板、用户微信平台弹窗授权、合法 HTTPS 域名和真机联调按用户安排后期提供;Adapter 未以测试值冒充真实发送完成。
2026-08-11
任务:Phase 5 公益项目、活动与志愿者。
完成:新增志愿者资料/技能/意向/状态历史、公益项目及状态历史、活动及状态历史、活动报名及不可变事实历史、项目工单归集、项目/活动封面业务类型和 Phase 5 权限 migration;实现志愿者申请、显式同意、revision 乐观锁、审核/暂停/恢复与角色事务同步,身份字段变更自动回待审;实现项目 CRUD、负责人范围、`DRAFT → PUBLISHED → COMPLETED`、公开边界与工单归集;实现活动 CRUD、发布/关报名/进行/完成/取消状态机;实现仅认证志愿者报名、活动行锁容量校验、截止时间、数据库唯一约束和幂等重放;实现报名审核、本人取消、签到/缺席、完成后服务分钟核定及历史审计。项目/活动封面复用真实 S3 兼容 Adapter,未配置时明确不可用。完成管理端志愿者审核、项目、活动与报名工作台,以及小程序公开项目/活动、在线报名、志愿者中心和个人服务事实页面。未进入 Phase 6。
测试:format check、lint、全仓 typecheck、27 个 unit tests、30 个真实 MySQL integration tests、全仓 production build、Docker Compose 示例配置校验、migration 重复 deploy、schema drift 检查、npm 官方 High 级 dependency audit、密钥特征扫描和 API Alpine Docker 镜像构建全部通过。Phase 5 集成测试覆盖项目/活动状态机、草稿公开隔离、未认证报名拒绝、重复报名安全重放、容量边界、报名审核/签到重放、完成后服务时长、不可变历史和审计;Phase 1–4 全量回归通过。
涉及 migration:`apps/api/prisma/migrations/20260812010000_phase5_participation/migration.sql`;已在独立 `lehuo_test` 库部署,重复 deploy 无待执行 migration,无 schema drift。
文档变化:更新应用 README、数据模型、API/工作流、UI/UX、安全隐私、测试验收、生产就绪计划、ADR 和本任务状态;新增 D-014。
遗留问题:无 Phase 5 代码阻塞。真实微信 AppID/AppSecret、合法 HTTPS 域名、生产私有对象存储密钥/CORS、微信开发者工具/真机、staging/UAT 和隐私法务配置按用户安排后期提供,未用测试值冒充完成。生产仍被 Phase 6–7、监控告警、备份恢复演练和发布审批阻断;详见 `17_PRODUCTION_READINESS_PLAN.md`。
2026-08-11
任务:Phase 4 回访闭环与生产就绪差距规划。
完成:新增回访任务、状态历史、继续帮扶来源关系、案件完成幂等字段及 `follow_ups:read/manage/complete` 权限 migration;实现负责人完成服务、至少一条服务记录前置校验,以及工单完成、申请 `IN_SERVICE → SERVICE_COMPLETED → FOLLOW_UP_PENDING`、自动回访和审计的单事务提交;实现人工/重点关爱回访、负责人/全量资源范围、今日/逾期/未来 7 日/重点关爱工作台、加密回访原因与结果、幂等完成;实现 `NEED_MORE_HELP` 新的显式授权、关联 `SUBMITTED` 申请、原申请关闭、历史和审计的单事务提交,不跳过既有评估/受理流程;完成管理端工单完结表单与回访工作台。新增生产就绪差距和 Phase 4–7 路线文档,未进入 Phase 5。
测试:format check、lint、全仓 typecheck、27 个 unit tests、28 个真实 MySQL integration tests、全仓 production build、Docker Compose 示例环境配置校验、migration 重复 deploy、schema drift 检查和 npm 官方 high-level dependency audit 全部通过;Phase 4 集成测试覆盖无记录禁止完成、事务自动回访、幂等冲突、资源范围和继续帮扶独立授权/关联申请。
涉及 migration:`apps/api/prisma/migrations/20260811220000_phase4_follow_up_closure/migration.sql`;已在独立 `lehuo_test` 库部署,无待执行 migration,无 schema drift。
文档变化:新增 `17_PRODUCTION_READINESS_PLAN.md`;更新数据模型、API/工作流、安全隐私、测试验收、ADR 和本任务状态;修正 staff/beneficiary 显示名及接单幂等字段在数据模型文档中的归属错误;新增 D-013。
遗留问题:无 Phase 4 代码阻塞。生产仍被 Phase 5–7、真实微信 AppID/AppSecret 与合法 HTTPS 域名、生产数据库/Redis/私有对象存储、监控告警、隐私法务确认、staging/UAT、备份恢复演练和发布审批阻断;详见 `17_PRODUCTION_READINESS_PLAN.md`。这些外部项未用测试值冒充完成。管理端截图级浏览器验收沿用已知本机隔离限制,本阶段通过类型检查、自动化测试和 production build 验证。
2026-08-11
任务:Phase 3 服务对象与工单。
完成:新增服务对象、联系人/监护授权、标签、工单、多人指派、工单/申请状态历史、服务记录、记录修订和私有文件模型及 migration;实现 `SUBMITTED → PENDING_CONTACT → ASSESSING` 严格受理、事务化幂等接单、手机号 HMAC + 人工确认关联档案、未成年人监护授权、资源范围和志愿者最小字段策略、负责人启动服务、幂等服务记录和 revision 乐观锁;实现 S3 兼容私有对象存储 Adapter、短期上传/下载签名和对象元数据确认;完成管理端申请受理、档案、工单、指派、记录及照片 UI,以及小程序权限感知的协作任务、最小详情和记录 UI。未实现 Phase 4 的完成服务和自动回访。
测试:format check、lint、全仓 typecheck、26 个 unit tests、25 个真实 MySQL integration tests、全仓 production build、Docker Compose config、npm 官方 high-level dependency audit、密钥特征扫描、API Alpine Docker 镜像构建全部通过;Phase 3 migration 已在独立 `lehuo_test` 库部署且重复 deploy 无待执行 migration。
涉及 migration:`apps/api/prisma/migrations/20260811180000_phase3_case_management/migration.sql`。
文档变化:更新 API/工作流、数据模型、ADR、环境模板、API/管理端/小程序/Docker 运行说明和本任务状态;新增 D-012。
遗留问题:无 Phase 3 代码阻塞。真实微信 AppID/AppSecret、合法 HTTPS 域名、对象存储私有 Bucket/最小权限密钥/CORS 以及微信开发者工具与真机联调按用户安排后期提供;生产对象存储未配置时附件 API 会明确返回不可用,不以测试 Adapter 冒充生产。管理端截图级浏览器验收沿用已知本机隔离网络限制,本轮通过类型检查、自动化测试和生产构建验证。
2026-08-11
任务:Phase 2 服务申请。
完成:建立服务分类、申请方式与完整申请状态共享契约;新增 consents、service_applications、只追加状态历史和 applications:read migration;实现本人/代申请、五步表单、提交成功、我的申请与状态时间线;实现事务化同意/申请/初始历史/审计、AES-256-GCM 敏感字段加密、域隔离 HMAC 查询索引及请求指纹、数据库唯一约束与并发幂等、申请人资源归属校验、提交限流;实现后台权限筛选、分页脱敏列表和详情查看审计。未实现 Phase 3 档案、受理、状态流转、工单或分配。
测试:format check、lint、全仓 typecheck、26 个 unit tests、17 个真实 MySQL integration tests、全仓 production build、Docker Compose config、pnpm high-level dependency audit、密钥特征扫描、API Alpine Docker 镜像构建全部通过;Phase 2 migration 已在独立 `lehuo_test` 库成功部署。最终重复执行 migration 检查时 Prisma Windows schema engine 被本机策略以 EPERM 拦截,已在同一已迁移隔离库直接重跑全部集成测试并通过。应用内浏览器无法从隔离网络访问仅绑定回环地址的本地服务器;出于安全考虑未将管理接口暴露到 `0.0.0.0`,开发服务器均已停止。
涉及 migration:`apps/api/prisma/migrations/20260811100000_phase2_service_applications/migration.sql`。
文档变化:更新小程序、管理端、API 与 Docker README;更新数据模型、API/工作流、安全隐私、ADR 和本任务状态;新增 D-011。
遗留问题:无 Phase 2 代码阻塞。真实微信 AppID/AppSecret、合法 HTTPS 域名、微信开发者工具/真机联调按用户安排后期提供;管理端截图级浏览器验收受本机隔离网络限制,自动化逻辑测试和生产构建已通过。
2026-08-10
任务:Phase 1 认证与权限。
完成:建立 Prisma 7/MySQL 认证数据模型和 migration;实现统一用户、微信 code exchange Adapter、后台 Argon2id 登录、数据库 opaque session、小程序 Bearer 会话、后台 HttpOnly Cookie、会话轮换/注销/过期与停用校验、登录锁定和限流;实现 RBAC、权限 Guard、resource policy 基线、角色事务替换和最后一名超级管理员保护;实现敏感字段 AES-256-GCM/HMAC、统一响应/错误/requestId、审计基线、首次管理员安全初始化;完成管理端登录/恢复/注销 UI 和小程序登录/重试 UI;CI 增加隔离 MySQL 集成测试,并修复 js-yaml High 漏洞。
测试:format check、lint、typecheck、19 个 unit tests、9 个真实 MySQL integration tests、全仓 build、API Alpine Docker 镜像构建、Docker Compose config、pnpm high-level dependency audit、密钥特征扫描全部通过;migration 在独立 `lehuo_test` 库成功部署。应用内浏览器视觉核验因本机 Browser 运行时路径权限被环境阻止,开发服务器已停止;自动化 UI 逻辑测试和生产构建通过。
涉及 migration:`apps/api/prisma/migrations/20260810130000_phase1_auth_baseline/migration.sql`。
文档变化:更新根 README、客户端与 Docker 运行说明、数据模型、API/工作流、安全隐私、ADR 和本任务状态;新增 D-009、D-010。
遗留问题:无 Phase 1 代码阻塞。真实微信平台 exchange 仍需在具备有效 AppID/AppSecret、合法 HTTPS 域名和微信环境时做联调;本机应用内浏览器权限问题导致本轮未获得登录页截图级视觉验收。
2026-08-10
任务:Phase 0 仓库初始化与技术基线。
完成:初始化 Git main 分支与 pnpm monorepo;创建原生 TypeScript 微信小程序、Vue 3 管理后台、NestJS API、共享 contracts;建立统一 ESLint/Prettier/TypeScript/测试/构建命令;创建 MySQL 8.4.8、Redis 7.4、MinIO 本地 Compose;创建 API Dockerfile、GET /health、.env.example、根 AGENTS.md、CI 和模块说明。
测试:format check、lint、typecheck、4 个 unit tests、1 个 integration test、build、dependency audit 全部通过;Docker Compose 配置通过,MySQL/Redis/MinIO 均 healthy;本机 API 与容器化 API 的 /health 冒烟测试通过。
涉及 migration:无(Phase 0 未创建业务 schema)。
文档变化:更新 docs/10_TASK_STATE.md、docs/05_API_AND_WORKFLOW.md;新增根 README.md 与 infra/docker/README.md。
遗留问题:无 Phase 0 阻塞问题。尚未开始任何 Phase 1 认证、权限或业务功能。
---
## 已知问题
无已知 Phase 5 代码问题。生产阻断项和人工配置见 `17_PRODUCTION_READINESS_PLAN.md`。
---
## 下一步
等待用户提供或确认外部生产资源后,依次执行 staging 全闭环、非开发人员 UAT、真实微信联调和 production deployment;不得跳过发布清单或审批。
+211
View File
@@ -0,0 +1,211 @@
# 11 架构与产品决策日志(ADR 简化版)
> Codex 不得删除已批准决策。新决策追加。
## D-001 产品架构
状态:ACCEPTED
决定:
V1 使用“微信小程序 + Web 管理后台 + 单体 API + MySQL + Redis + 对象存储”。
原因:
低复杂度、易部署、易维护、适合当前组织规模。
---
## D-002 后端架构
状态:ACCEPTED
决定:
模块化单体,不采用微服务。
触发重新评估条件:
- 单体部署已形成明确性能瓶颈;
- 团队规模显著扩大;
- 某模块有独立扩容/安全隔离的客观需求。
---
## D-003 主技术语言
状态:ACCEPTED
决定:
优先 TypeScript 全栈。
原因:
前后端共享类型、Codex 开发一致性高、维护人员切换成本较低。
---
## D-004 数据库
状态:ACCEPTED
决定:
MySQL 作为业务事实数据库。
Redis 不保存不可恢复的唯一业务事实。
---
## D-005 文件
状态:ACCEPTED
决定:
生产文件进入私有对象存储,通过授权临时访问;不持久化在应用容器本地盘。
---
## D-006 V1 范围
状态:ACCEPTED
决定:
V1 首先实现服务闭环、志愿者、项目活动、内容和基础统计,不做复杂 AI、地图、公开募捐、自研 IM。
---
## D-007 隐私
状态:ACCEPTED
决定:
个人敏感信息采取最小收集、最小权限、默认脱敏、操作审计;儿童相关信息更严格。
---
## D-008 UI
状态:ACCEPTED
决定:
优先普通群众与适老使用,不追求炫技。
---
## D-009 数据访问与迁移
状态:ACCEPTED
决定:
Phase 1 使用 Prisma 7 与 MariaDB/MySQL driver adapter 访问 MySQL;所有 schema 变化通过 Prisma migration SQL 提交,运行时不使用自动同步。
原因:
保持类型安全、显式迁移和模块化单体的一致性,并确保 CI 与部署可重复执行 migration。
---
## D-010 认证与会话
状态:ACCEPTED
决定:
微信登录通过可替换 Adapter 调用官方 code exchange;后台密码使用 Argon2id。会话采用数据库支持的随机 opaque token,数据库只保存带 pepper 的 HMAC。小程序使用短期 Bearer token,后台使用 HttpOnly、SameSite=Strict Cookie 并校验 Origin。
原因:
V1 不引入额外身份供应商或复杂 token 基础设施,同时支持主动注销、轮换、停用和审计,且避免前端持久化后台凭据。
---
## D-011 服务申请隐私与幂等
状态:ACCEPTED
决定:
Phase 2 使用 PRD 已批准的六类服务分类和本人/代申请方式。申请敏感字段采用 AES-256-GCM,查询索引及规范化请求指纹采用域隔离 HMAC-SHA-256;以申请人和客户端请求 UUID 的数据库唯一约束实现幂等。隐私同意、申请、初始状态历史和审计必须事务一致。
原因:
在不提前引入 Phase 3 档案和工单的前提下,确保弱网重试不会重复建单,并降低数据库泄露后联系方式、需求内容或可枚举请求摘要被还原的风险。
---
## D-012 Phase 3 接单、记录与文件一致性
状态:ACCEPTED
决定:
申请接单采用数据库事务和客户端 UUID 幂等:从评估状态建立或关联服务对象、写监护授权、生成工单、指派人员、追加申请/工单历史及审计必须原子完成。已有档案只允许在手机号 HMAC 精确匹配且工作人员明确确认后关联。服务记录创建幂等,修改使用 revision 乐观锁并保存加密修订快照。文件通过 S3 兼容 Adapter 进入私有对象存储,后端只签发短期 URL 并在确认时校验元数据。
Phase 3 只开放 `ASSIGNED → IN_SERVICE`;完成服务与自动回访保持为 Phase 4 的事务边界,禁止提前拆开实现。
原因:
避免弱网重试重复建档/建单、同名误合并、并发覆盖服务记录、对象存储永久公开,以及在回访能力尚未实现时产生无法闭环的“已完成”工单。
---
## D-013 Phase 4 回访与继续帮扶一致性
状态:ACCEPTED
决定:
完成服务要求至少一条服务记录,并由工单负责人以客户端 UUID 幂等提交。工单完成、申请进入待回访、状态历史、自动回访和审计必须原子提交。回访结果为“需要继续帮扶”时,不直接生成工单;必须先取得新的显式授权,创建保留原申请和来源回访关系的 `SUBMITTED` 新申请,再沿用既有评估/受理流程。新授权、新申请、回访完成、原申请关闭、历史和审计必须在同一事务提交。
人工和重点关爱回访使用同一任务模型;重点关爱回访仅适用于已标记对象。回访正文加密,列表最小化,志愿者不获得回访权限;普通工作人员只访问本人负责任务,具有全量资源权限的管理角色可查看工作台全量范围。
原因:
防止服务完成但回访丢失、弱网重试产生重复任务、继续帮扶覆盖原历史或绕过评估受理,同时降低回访结论和脆弱人群信息泄露风险。
---
## D-014 Phase 5 志愿参与状态机与服务事实
状态:ACCEPTED
决定:
项目采用 V1 最小状态 `DRAFT → PUBLISHED → COMPLETED`;活动采用已批准的 `DRAFT/PUBLISHED/REGISTRATION_CLOSED/IN_PROGRESS/COMPLETED/CANCELLED`;报名采用 `PENDING/APPROVED/REJECTED/CANCELLED`,签到独立采用 `NOT_CHECKED_IN/CHECKED_IN/ABSENT`。每个业务状态变化均以客户端 UUID 幂等,在同一事务写条件更新、不可变历史和审计。
只有 `APPROVED` 志愿者可报名。报名事务锁定活动事实后校验发布状态、截止时间、容量和 `(activity,user)` 唯一约束。服务分钟只从已通过、已签到且活动已完成的报名记录产生,保留修改前后历史;志愿者修改姓名或手机号后必须重新审核并暂时撤销志愿者角色。
项目类别复用既有服务分类;项目可归集既有服务工单,但无全量权限的负责人不能转移其他项目工单。项目/活动封面复用 S3 兼容对象存储 Adapter 和短时 URL;外部存储未配置时允许无封面业务继续运行,但不得伪造上传或公开地址。Phase 5 不创建通知、证书、培训、团队、复杂排班或公开募捐能力。
原因:
保持 V1 范围最小且与既有服务事实一致,防止并发超额、重复报名、资格绕过、不可追溯服务时长和跨项目资源转移,同时把外部对象存储配置与核心志愿参与链路解耦。
---
## D-015 Phase 6 内容审核与可靠通知
状态:ACCEPTED
决定:
V1 五类内容共用 `DRAFT → PENDING_REVIEW → PUBLISHED → ARCHIVED` 状态机;退回进入草稿,已发布内容只能归档,不允许编辑后直接公开。所有变更使用 UUID 幂等、revision 乐观锁、不可变历史和审计。服务故事发布必须显式确认隐私脱敏,正文仅按纯文本/Markdown 保存,不执行用户 HTML。
站内消息与外部投递分离。业务状态变化在原数据库事务创建幂等站内消息;微信订阅通知仅在用户明确开启偏好后创建数据库投递任务,由 Adapter 异步发送并指数退避,最多五次后进入死信。微信失败不得回滚主业务,未配置平台参数时明确不可用。
原因:
避免草稿或未经隐私审核的个案内容泄露,保证通知事实不因外部平台故障丢失,并维持外部供应商与业务服务解耦。
---
## D-016 Phase 7 统计、导出与发布工程
状态:ACCEPTED
决定:
V1 统计直接从业务事实表计算,不建立可人工覆盖的统计表。统计查询最多 366 天;导出仅提供汇总且默认不包含个人字段,使用独立权限并记录审计。运行面提供 liveness、数据库 readiness 和受保护的请求量/5xx/p95/资源指标。
生产发布使用不可变镜像标签,固定执行 staging、migration/备份预检、冒烟、UAT、生产备份、部署、健康检查、观察与按上一镜像回滚。MySQL 每日备份、SHA-256 校验、异地留存和季度独立库恢复演练。真实 staging、UAT、微信联调和生产发布必须等待对应环境、资质与人工审批,不以本地检查冒充。
原因:
确保公益服务数据口径可追溯,降低导出泄露面,并把可自动验证的生产工程与必须由真实环境/责任人完成的发布审批清晰分开。
---
## 待确认建议
Codex 若有会改变已批准架构的建议,只能写在这里,不得直接实施:
```text
[PENDING]
日期:
建议:
原因:
收益:
风险:
迁移成本:
需要用户确认:
```
+153
View File
@@ -0,0 +1,153 @@
# 12 可直接交给 Codex 的总指令
你现在是“乐活公益·暖心服务平台”的主开发工程师、架构维护者和测试负责人。
你的目标不是一次生成大量代码,而是在整个项目周期中持续、准确、可验证地完成系统。
## 一、第一原则
在写任何代码之前,必须完整阅读 `docs/` 中的项目文档,特别是:
- 00_README_FIRST.md
- 01_PROJECT_CONSTITUTION.md
- 10_TASK_STATE.md
- 11_DECISIONS.md
项目文档是当前事实来源。聊天上下文只能补充,不能覆盖已批准规则,除非用户明确要求修改。
## 二、记忆协议
每次任务开始:
1. 读取项目开发宪法;
2. 读取当前任务状态;
3. 读取决策日志;
4. 检查 Git diff;
5. 确定任务属于哪个 Phase;
6. 输出本次实现范围,不扩大范围。
每次任务结束:
1. 运行 lint;
2. 运行 typecheck;
3. 运行 unit tests;
4. 运行 integration tests;
5. 运行 build;
6. 需要时运行 E2E;
7. 更新 `10_TASK_STATE.md`;
8. 更新 `11_DECISIONS.md`(如有);
9. 更新 API/DB 文档;
10. 汇报“完成内容 / 未完成内容 / 测试结果 / 风险 / 下一步”。
如果上下文不足:
优先从仓库文档和代码中恢复,而不是凭空假设。
## 三、禁止行为
你绝对不能:
- 擅自改产品方向;
- 删除业务需求来降低开发难度;
- 重写整个项目只因为你更喜欢另一套技术;
- 擅自换数据库;
- 擅自改认证方案;
- 跳过权限;
- 跳过 migration;
- 跳过测试;
- 用 mock 冒充生产功能;
- 写死生产密钥;
- 把敏感信息写日志;
- 把所有业务逻辑堆在 Controller;
- 让前端权限判断代替后端鉴权;
- 使用连续 ID 作为面向用户的资源标识;
- 对服务对象数据做无授权公开;
- 开发未批准的 AI 自动决策能力。
## 四、编码优先级
顺序永远是:
1. 正确性
2. 安全
3. 数据一致性
4. 用户可理解
5. 可维护
6. 可测试
7. 性能
8. 开发速度
9. 技术“先进程度”
## 五、实现策略
不要一次开发所有功能。
严格按 `10_TASK_STATE.md` Phase 执行。
一个 Phase 的 P0 测试不通过,不进入下一个 Phase。
## 六、发生冲突时
如果新需求与项目宪法冲突:
- 不静默修改;
- 说明冲突点;
- 在 `11_DECISIONS.md` 建 PENDING 项;
- 等用户明确批准后再改变。
如果是不会改变边界的小实现细节,可自行采用最简单可靠方案,并记录重要决定。
## 七、安全要求
本项目处理弱势群体和未成年人相关信息。
任何时候都按:
- 最小收集
- 最小权限
- 默认脱敏
- 完整审计
- 私有文件
- 后端鉴权
- 不信任客户端
- 不信任用户输入
- 不信任第三方回调
- 不信任 AI 输出
执行。
## 八、完成标准
“页面能打开”不是完成。
“接口返回 200”不是完成。
“我写了代码但没运行测试”不是完成。
完成必须符合 `08_ENGINEERING_RULES.md` 的 Definition of Done 和 `09_TEST_ACCEPTANCE.md`。
## 九、第一次任务
请从 Phase 0 开始:
1. 初始化 monorepo;
2. 创建 `apps/miniprogram`;
3. 创建 `apps/admin-web`;
4. 创建 `apps/api`;
5. 创建 `packages/contracts`;
6. 建立本地 Docker Compose:MySQL、Redis、MinIO;
7. 建立统一 lint/typecheck/test/build;
8. 创建 `/health`;
9. 创建 `.env.example`;
10. 创建根目录 `AGENTS.md`;
11. 创建 CI;
12. 运行全部命令并修复问题;
13. 更新 `docs/10_TASK_STATE.md`;
14. 不开发业务功能,等待 Phase 1。
完成后只汇报:
- 新增/修改文件
- 本地启动方式
- 测试命令和结果
- 已知问题
- 下一步 Phase 1 计划
不要自行开始 Phase 1。
+155
View File
@@ -0,0 +1,155 @@
# 13 国内环境部署与运维
## 1. 目标
- 中国大陆访问稳定;
- 微信小程序合法域名可配置;
- TLS;
- 低维护成本;
- 可迁移;
- 可备份;
- 可回滚。
---
## 2. 推荐生产拓扑(初期)
```text
微信小程序
│ HTTPS
▼
Nginx / API Domain
│
▼
NestJS API (Docker)
├── MySQL
├── Redis
└── Tencent COS
管理后台
│ HTTPS
└────────► Nginx / API
```
管理后台静态资源可由 Nginx 或对象存储/CDN 托管。
---
## 3. 云厂商
优先腾讯云并非代码强绑定要求,而是微信生态和国内运维便利性考虑。
代码必须通过 Adapter 保持:
- COS 可替换 S3 兼容存储;
- Redis 可替换其他标准 Redis;
- MySQL 可迁移标准 MySQL;
- Nginx/Docker 不绑定专有 PaaS。
---
## 4. 国内依赖获取
开发机可根据实际环境配置:
- npm 国内镜像;
- Docker 镜像加速;
- 操作系统软件源镜像。
但:
- lockfile 必须提交;
- CI 至少验证标准 registry 可构建;
- 不依赖个人私服;
- 不在代码写死镜像地址。
---
## 5. 环境
### dev
开发者本机 Docker Compose。
### test
CI 自动化测试。
### staging
与生产拓扑尽量一致,使用测试小程序/测试账号。
### prod
真实用户。
严禁 dev 直连 prod 数据库。
---
## 6. 发布
建议:
1. CI build;
2. 生成 immutable image tag;
3. staging deploy;
4. migration precheck;
5. smoke test;
6. production backup;
7. production deploy;
8. health check;
9. E2E smoke;
10. 观察;
11. 出现严重问题回滚应用版本。
数据库 migration 必须设计可前后兼容,避免应用回滚后数据库不兼容。
---
## 7. 监控
至少:
- API availability
- 5xx rate
- P95 latency
- CPU/memory
- disk
- MySQL connection
- Redis connectivity
- job failures
- backup failures
告警进入实际有人查看的渠道。
---
## 8. 容灾
初期无需昂贵双活,但必须:
- 自动数据库备份;
- 异地/云端备份;
- IaC/部署脚本;
- Docker 镜像可重建;
- 文档化恢复;
- 定期演练。
---
## 9. 微信小程序上线准备
实际申请和上线阶段需要根据微信公众平台最新规则核对:
- 小程序主体
- 服务类目
- 隐私保护指引
- 用户信息/手机号等接口使用说明
- request/download/upload 合法域名
- HTTPS 证书
- 备案/域名要求
- 订阅消息模板
- 审核材料
微信平台规则可能变化,因此上线前必须重新查官方文档,不得只依赖本文件。
+68
View File
@@ -0,0 +1,68 @@
# 14 发布检查清单
## 代码
- [ ] main branch clean
- [ ] lockfile committed
- [x] lint pass
- [x] typecheck pass
- [x] unit pass
- [x] integration pass
- [ ] E2E P0 pass
- [x] build pass
## 数据库
- [x] migration reviewed
- [ ] backup done
- [x] rollback compatibility checked
- [x] indexes reviewed
## 安全
- [x] secrets scan
- [x] dependency scan
- [x] auth test
- [x] IDOR test
- [x] export permission test
- [x] file upload test
- [ ] logs checked for PII
## 隐私
- [ ] privacy policy version correct
- [x] consent flow correct
- [x] children/guardian flow checked
- [x] sensitive list fields masked
- [ ] retention configuration checked
## 微信
- [ ] legal domains
- [ ] HTTPS
- [ ] privacy declarations
- [ ] API permissions
- [x] subscribe message handling
- [ ] real device test
## 运维
- [x] health
- [x] monitor
- [x] alert
- [ ] backup
- [x] restore procedure
- [ ] rollback image available
## UAT
- [ ] 本人申请
- [ ] 代申请
- [ ] 受理
- [ ] 建档
- [ ] 派单
- [ ] 服务
- [ ] 回访
- [ ] 继续帮扶
- [ ] 志愿者
- [ ] 活动报名
File diff suppressed because it is too large Load Diff
+52
View File
@@ -0,0 +1,52 @@
# Codex 前端开发启动指令
你现在负责“乐活公益·暖心服务平台”的前端实现。
开始前必须阅读:
- docs/00_README_FIRST.md
- docs/01_PROJECT_CONSTITUTION.md
- docs/02_PRODUCT_PRD_V1.md
- docs/07_UI_UX.md
- docs/10_TASK_STATE.md
- docs/11_DECISIONS.md
- docs/15_FRONTEND_DESIGN_SPEC.md
并查看:
- docs/ui_reference.png
执行规则:
1. 不得自行改变已确认视觉方向;
2. 不得把公益平台做成商城、资讯门户、社交平台或科技大屏;
3. 小程序优先普通群众和适老使用;
4. 后台优先工作人员高频任务;
5. 每个页面必须包含 loading / empty / error / permission 状态;
6. 前端只隐藏按钮不能代替后端鉴权;
7. 不得写死敏感数据;
8. 不得为了页面好看增加未经批准的业务字段;
9. 不得提前开发 AI、地图、捐赠交易能力;
10. 每完成一个 Sprint,运行 lint、typecheck、tests、build,并更新 docs/10_TASK_STATE.md。
第一次前端任务仅执行:
Sprint UI-01:
- 建立 Design Tokens;
- 建立小程序底部导航;
- 完成小程序首页;
- 完成 EmptyState / ErrorState / LoadingSkeleton;
- 完成后台基础 Layout;
- 使用 mock 数据仅做视觉开发时,必须明确标注 mock,并在接入真实 API 后删除;
- 完成后截图并与 ui_reference.png 对照;
- 不开始 UI-02。
完成后汇报:
- 文件变化;
- 页面截图;
- 视觉差异;
- 测试结果;
- 已知问题;
- 下一步。
+99
View File
@@ -0,0 +1,99 @@
# 17 生产就绪差距与阶段计划
> 评估日期:2026-08-11
> 事实来源:`01_PROJECT_CONSTITUTION.md`、`02_PRODUCT_PRD_V1.md`、`09_TEST_ACCEPTANCE.md`、`10_TASK_STATE.md`、`13_DEPLOYMENT_CHINA.md`、`14_RELEASE_CHECKLIST.md`。
## 1. 当前结论
Phase 0–7 的可自动化开发与本地生产工程验证已完成。当前仍不满足生产发布条件,剩余差距来自真实环境与人工审批:
1. Phase 6 内容审核、站内消息和微信通知 Adapter 已完成,真实微信模板发送待平台配置;
2. Phase 7 统计、脱敏汇总导出、安全扫描、备份恢复演练、监控规则和可回滚部署配置已完成,真实 staging、UAT 和 production deployment 待执行;
3. 微信、域名备案、TLS、对象存储和运营合规材料需要人工账号与真实环境。
在上述工作完成前,只能视为可持续开发的 MVP,不得标记为可生产发布。
## 2. 分阶段交付计划
### 阶段 A:Phase 4 回访闭环(已完成,2026-08-11)
- 服务完成与自动回访任务在同一事务中提交;
- 回访待办、今日/逾期/本周/重点关怀视图;
- 人工及重点关怀回访任务;
- 回访结果、完成历史和审计;
- `NEED_MORE_HELP` 原子创建关联后续申请,保留原历史;
- 完成 E2E-005、E2E-006 对应的集成验证。
退出条件:Phase 4 P0 测试、migration、文档和全仓质量门禁全部通过。
完成证据:Phase 4 migration 已部署到隔离测试库且无 schema drift;27 个单元测试、28 个真实 MySQL 集成测试、全仓类型检查和 production build 全部通过。
### 阶段 B:Phase 5 公益项目、活动与志愿者(已完成,2026-08-11)
- 志愿者资料、申请审核、状态机和最小权限;
- 公益项目与活动 CRUD/发布状态机;
- 活动报名、防重复、容量与截止时间校验;
- 签到和服务时长事实记录;
- E2E-009 及角色越权验证。
退出条件:V1 的志愿参与链路可在 staging 使用生成数据完整跑通。
完成证据:Phase 5 migration 已部署到隔离测试库且无 schema drift;真实 MySQL 集成测试覆盖项目/活动/报名/审核/签到/服务分钟、容量上限、幂等重放和公开边界。真实微信、合法域名、对象存储与 staging 仍按外部配置项保留,未用测试值冒充完成。
### 阶段 C:Phase 6 内容与通知(已完成,2026-08-12)
- 机构介绍、公益动态、草稿/审核/发布;
- 站内消息和投递记录;
- 微信订阅消息 Adapter、重试与失败补偿;
- 隐私政策、用户协议和授权页面接入可版本化内容;
- 外部通知失败不回滚主业务。
退出条件:公开内容审核、业务通知降级和隐私版本留痕通过测试。
完成证据:草稿公开隔离、审核状态机、服务故事隐私确认、危险内容拒绝、消息 IDOR 和订阅偏好已通过真实 MySQL 集成测试;真实微信发送保留为外部验收。
### 阶段 D:Phase 7 生产工程与发布(工程完成,外部发布待执行)
- 基础统计与受控脱敏导出;
- readiness/liveness、结构化运行日志、5xx/P95/资源/数据库/任务/备份监控;
- SAST、依赖/密钥扫描、IDOR、CSRF、SQLi、XSS、上传绕过和暴力登录测试;
- MySQL 自动备份、对象存储保护、恢复脚本和实际恢复演练;
- Nginx、TLS、immutable image、staging/prod Compose 或等价部署清单;
- migration precheck、发布、冒烟、观察和应用回滚流程;
- P0 E2E、性能基线和多角色 UAT。
退出条件:`14_RELEASE_CHECKLIST.md` 全部勾选,Critical/High 为零,恢复演练和 staging 闭环通过。
当前证据:统计/导出、health/metrics、权限扫描、官方依赖审计、密钥扫描、CodeQL 工作流、备份/恢复脚本、Nginx、immutable image Compose、预检/冒烟和告警规则已完成;本地恢复演练源库与恢复库均为 42 张表。真实 staging、UAT、告警接收和生产发布尚未执行,因此本退出条件仍未满足。
## 3. 需要人工或外部环境配合
以下内容不能用测试值替代正式验收:
- 微信小程序主体、类目、有效 AppID/AppSecret、接口权限和审核材料;
- 已备案域名、合法 request/upload/download HTTPS 域名和有效 TLS 证书;
- 生产 MySQL、Redis、私有对象存储 Bucket、最小权限密钥、CORS、生命周期/版本策略;
- 监控告警接收渠道和实际值班责任人;
- 数据保留期限、未成年人数据规则、隐私政策和用户协议的运营/法律确认;
- staging 测试账号、微信开发者工具、真机测试和非开发人员 UAT;
- 生产变更窗口、备份保留策略、回滚授权人与发布审批。
## 4. 发布阻断项
任一项未满足均阻断生产发布:
- Phase 6–7 本地 P0 功能或测试回归失败;
- P0 E2E 未全通过;
- 存在 Critical/High 安全漏洞或未修复越权;
- 未完成真实备份恢复演练;
- 无 staging 全闭环记录或可回滚镜像;
- 隐私/监护授权、微信合规材料或合法域名未就绪;
- 监控、告警无人接收;
- 使用测试 Adapter、测试密钥或本地 HTTP 冒充生产能力。
## 5. 执行规则
- 严格按 Phase 顺序推进,一个阶段 P0 未通过不得进入下一阶段;
- 外部配置缺失时保留真实 Adapter 和明确不可用状态,不伪造联调成功;
- 每阶段结束更新 `10_TASK_STATE.md`,架构或产品决定追加到 `11_DECISIONS.md`;
- 每阶段均执行 format、lint、typecheck、unit、integration 和 build,生产阶段另执行安全、恢复、E2E 与性能门禁。
+19
View File
@@ -0,0 +1,19 @@
# AGENTS.md
Before coding, read:
1. docs/00_README_FIRST.md
2. docs/01_PROJECT_CONSTITUTION.md
3. docs/10_TASK_STATE.md
4. docs/11_DECISIONS.md
5. task-related docs
Rules:
- Do not change approved product scope or architecture without explicit approval.
- Do not bypass authorization, migrations, tests, or audit requirements.
- Do not log sensitive beneficiary data.
- Do not expose sequential internal IDs.
- Update docs/10_TASK_STATE.md after every task.
- Update docs/11_DECISIONS.md for architecture/product decisions.
- Run lint, typecheck, tests and build before marking work complete.
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB