226 lines
9.5 KiB
Markdown
226 lines
9.5 KiB
Markdown
# 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、微信联调和生产发布必须等待对应环境、资质与人工审批,不以本地检查冒充。
|
|
|
|
原因:
|
|
确保公益服务数据口径可追溯,降低导出泄露面,并把可自动验证的生产工程与必须由真实环境/责任人完成的发布审批清晰分开。
|
|
|
|
---
|
|
|
|
## D-017 参考界面还原与延期能力扩展边界
|
|
|
|
状态:ACCEPTED
|
|
|
|
决定:
|
|
小程序端和管理端以 2026-08-10 已确认参考图作为当前视觉基准,在不改变 V1 业务状态机、权限、数据口径和隐私边界的前提下完整还原其信息层级、色彩、卡片、导航、表格、图表和详情结构。界面统计只使用现有事实接口,不展示虚构人数、金额、满意度或成果。
|
|
|
|
爱心捐赠及微信/支付宝/银行卡支付、每月自动捐赠、捐赠记录与金额统计、物资订单、志愿者培训、证书和团队不进入当前版本,不注册页面或可操作入口,不新增数据库/API;通过集中能力清单、稳定模块边界和可扩展导航结构预留后续接入点,后续启用仍须独立产品、权限、审计、支付合规和迁移评审。
|
|
|
|
原因:
|
|
满足已批准视觉目标,同时避免用不可用入口或模拟数据冒充已交付功能,并防止支付、订单和志愿者扩展模块未经合规及架构评审进入 V1。
|
|
|
|
---
|
|
|
|
## 待确认建议
|
|
|
|
Codex 若有会改变已批准架构的建议,只能写在这里,不得直接实施:
|
|
|
|
```text
|
|
[PENDING]
|
|
日期:
|
|
建议:
|
|
原因:
|
|
收益:
|
|
风险:
|
|
迁移成本:
|
|
需要用户确认:
|
|
```
|