MediLink Global 功能规格说明书(FSD)v1.0 · 总则
上游文档:prd/srs-medilink-v1.md(v1.1,需求唯一权威源)。本文档以代码实现为事实基准,还原系统真实运转规则;与 SRS 的差异以 ⚠ DIF 注记标出并登记 99-附录 差异台账。 功能 ID 规则:
F<m>.<两位序号>(m = 模块号 1~10,与代码域包对应)。ID 全局唯一、只增不改号。 技术设计(为什么这样实现)见 docs/tech-design.md(15 节);本文只记 as-is 行为。
0. 修订记录
| 版本 | 日期 | 对应 SRS 版本 | 修订说明 | 作者 |
|---|---|---|---|---|
| v1.0 | 2026-10-09 | srs-medilink-v1.1 | 首版:按代码实现还原全模块功能规格。P0 总则 + 50 功能 ID 分配冻结 | — |
0.1 文档定位
- SRS 管 to-be 契约(需求意图、验收口径唯一权威);FSD 记 as-is 实现(系统当前真实行为)。
- 每个 FSD 功能节标注「对应 SRS 需求 ID」;实现与 SRS 不一致处行内
> ⚠ DIF-F<m>-<序号>注记,并登记 99-附录差异台账(现状 file:line / SRS 期望 / 影响面 / 处置建议)。注:正文另有DIF-M<n> ①引用系 tech-design 里程碑批次差异编号(权威源 tech-design §14/开发任务总表),与 DIF-F 两套并存、不换算——见 99-附录 B 头注。 - SRS 有而未实现的功能照常占 ID,状态列标
未实现;代码有而 SRS 无的功能标代码先行(此类隐性规则正是本档最值钱部分)。MVP 已收口(M1~M12),当前全集为实现。 - 分册结构:功能详述按代码域拆分为 m01~m10 共 10 册 + 99-附录,
F<m>.<nn>位于m<m>-*.md;跨文件一律以 F-ID 纯文本引用,锚点不受拆分影响。 - 行内引用的技术背景(「为什么」)指 docs/tech-design.md §n,本文不重复论证。
1. 术语与数据字典
1.1 术语对照(SRS 叫法 / 本文统一叫法 = 代码字段名)
收录判据:SRS、界面文案、代码命名三方叫法不一致的词必收。
| SRS/口语 | 本文统一叫法 | 代码字段/表 |
|---|---|---|
| 工单 | 工单 | ticket(域内模型 ticket.Ticket) |
| 8 个状态 / 流程状态 | A 轴(办理环节) | ticket.status(8 态 + 3 回退边,见 2.2) |
| 诊疗 8 阶段 | C 轴(医疗旅程) | ticket.care_stage(8 阶段,见 2.2) |
| 患者进度条 8 步 | 派生八步 | DerivePatientSteps 纯函数(跨 A+C 投影,不反灌状态机) |
| 匿名咨询 | 访客会话 | chat_session + guest JWT claim gsid |
| 注册后转正 | 绑定(guest→patient) | chat_session.patient_id CAS 谓词更新(0=未绑定哨兵) |
| 两段式登录 / 2FA | TOTP 两段式 | POST /api/auth/login → mfa_token → POST /api/auth/mfa;user_account.totp_status 三态 |
| 病历直传 / 三步协议 | 直传三步 | presign → PUT 直传 → confirm(HeadObject 复核,见 2.5) |
| 支付残留单 | 残留单 | payment_order.status='PENDING' 且未回调的孤儿行(人工关单) |
| 注册卡片 | 注册卡片 | chat_message.msg_type='CARD',content={"type":"register"} 服务端构造 |
| 站内通知 / 待办 | INBOX | notification_outbox.channel='INBOX'(read_at 列标记已读,status 恒 PENDING) |
| 邮件队列 | outbox(EMAIL 通道) | notification_outbox.channel='EMAIL'(指数退避 3 败 FAILED) |
| 重新翻译 | 重译 | POST .../messages/:id/retranslate |
| 译文补推 | 译文回填 | SSE 事件 msgTranslated(worker 异步回填 chat_msg_ext) |
| 推荐专家 | 专家引用 | ticket.expert_id(选人)+ ticket.expert 文本快照(不可变) |
| 科室锚定 | dept 锚 | 医生选人按 hospital_dept.id(dept 全局唯一隐含院区) |
| 阶段资料版本 | 版本组 | medical_document.doc_group / version_no / is_current |
| 权限码 | 权限码 | permission.code(14 个,<domain>:<action>) |
| 生命周期视图 | 双日志轨 | entity_lifecycle_event(状态/阶段时间线)+ operation_log(操作审计) |
1.2 数据字典(按功能模块归组的表清单)
DDL 权威:medilink/migrations/full/medilink_full.sql(19 表,本文不复制字段,只给「表 → 功能节」挂点;字段级规则在各功能节 3 记录;全表逐表展开见 docs/数据库总览.md)。
| 模块 | 核心表 |
|---|---|
| m01 认证与权限 | user_account permission role_permission |
| m02 医院主数据 | hospital hospital_dept hospital_expert |
| m03 双语咨询 | chat_session chat_message(日志)chat_msg_ext |
| m04 注册与病历 | user_account patient_profile consent_record(日志)medical_document |
| m05 工单与看板 | ticket |
| m06 预诊断 | (无新表——写 ticket 列) |
| m07 支付 | payment_order payment_webhook_event(技术) |
| m08 诊疗过程 | medical_document(版本组复用) |
| m09 出行协助 | trip_record(detail JSON) |
| m10 系统与审计 | entity_lifecycle_event(日志)operation_log(日志)notification_outbox(技术) |
tech-design §5.1 记「21 张」为设计期口径,实施收敛为 19 张(translation_cache 改 Redis 实装不建表、care_stage_record/trip_arrangement 合并为 trip_record + lifecycle 行集——DIF-M3 ⑥/DIF-M7 ①),以 full.sql 实测为准,差异台账见 99-附录 B。
2. 全局规则
每批发现新全局规则必须回填本章,正文只引用不重复。
2.1 权限模型
- 三 issuer JWT 互不认(自实现 HMAC-SHA256,
gateway.Signer):/api面 iss=bo(claims uid/role/pv,exp 12h);/pt面 iss=pt(exp 7d);/pub面 iss=guest(claim gsid,exp 7d);另有第 4 issuermfa(5min、仅 uid,无业务权限——结构性过不了 bo 面必填 claim 校验)。 - 4 角色:
user_account.role=ADMIN / CONSULTANT / DOCTOR / PATIENT。PATIENT 不走权限码表——靠/pt路由面物理隔离 + service 层「只准读写自己数据」强制谓词;权限码只管 B 端三角色。 - 14 个权限码(
permission字典表 seed 幂等,gateway.NewDBPermissionSource消费):chat:read(1)chat:send(2)ticket:read(3)ticket:assign(4)ticket:transition(5)diag:write(6)hospital:manage(7)patient:manage(8)user:manage(9)payment:read(10)care:write(11)trip:write(12)ops:read(13)ops:manage(14)。 - 守卫方式:路由级
gateway.RequirePermission(code, permSrc, rdb, dbname, log)中间件(main.go 逐条挂载,模式 C);redis 权限集缓存 60s TTL(keyrbac:<库名>:perm:<role>:pv<pv>,JWT claimpv隔离版本);DB 错误 fail-closed 返回空集;未挂守卫的端点 = 登录即可(如/api/inbox——通知消费按角色谓词隔离,无权限码)。 - 「角色 × 权限码」矩阵(权威源
scripts/dev/seed.sql:127-141;语义:chat:send 属顾问操盘职责、diag:write 属医生临床行为,ADMIN 不代写不代发):
| 角色 | 权限码 |
|---|---|
CONSULTANT | chat:read chat:send ticket:read ticket:assign ticket:transition payment:read care:write trip:write ops:read(9 码——全程操盘) |
DOCTOR | chat:read ticket:read diag:write(3 码——只读 + 写预诊) |
ADMIN | 全 14 码 − {chat:send, diag:write}(12 码) |
PATIENT | 无权限码(/pt 面 + 谓词隔离) |
- 登录快照(⚠ DIF-M8 ⑤):
LoginResult.permissions[]登录时直查字典表一次(不走 redis 缓存);web 前端src/authz.ts纯函数has(code)做菜单/按钮显隐——权限漂移靠重新登录刷新,PV 不变。
2.2 状态机总览
各业务对象状态机的权威枚举汇总于此(共 8 组:ticket/payment/care_stage/trip + hospital·dept·expert 三同构计 7 组为 transition 白名单机,经 pure.go 转移表代码化+守卫测试锁定;user_account.status/TOTP 三态/translation_status 为 CAS 直写非白名单机,在 transition() 射程外);每个功能节 6 只画本功能触及的迁移,引用本章。
工单 ticket.status(A 轴)(ticket/pure.go:92,8 态 + 3 回退边):
| 状态 | 含义 |
|---|---|
CREATED | 已创建(注册事务链开单) |
PENDING_ASSIGN | 待分配(CREATED 自动流转至此) |
PREDIAGNOSING | 预诊断中(已分配医生) |
PLAN_CONFIRMING | 方案确认中(医生已提交预诊) |
PENDING_PAYMENT | 待支付(患者进入支付) |
PENDING_DEPARTURE | 待出行(支付成功回调) |
IN_TREATMENT | 就医中(C 轴自此推进) |
COMPLETED | 已完成(终态) |
COMPLETED终态不可迁;三条回退边是设计补充(边 1 由支付失败回调驱动、边 3 由医生拒绝驱动,边 2 手动触发权限待产品确认——tech-design §15 风险 3);迁移只准走TransitionInTx(status 谓词 CAS + lifecycle + op_log 同事务)。
支付单 payment_order.status(payment/pure.go:15):
SUCCEEDED→REFUNDED不入白名单(MVP 无自动退款,人工线下改库必走 operation_log 带 reason);FAILED不复活——重谈后新建支付单(PENDING 复用谓词:同工单已有 PENDING 单则复用重新 CreateCheckout,防残留单堆积,⚠ DIF-M8 ⑦)。
诊疗阶段 ticket.care_stage(C 轴)(care 域 stageTransitions,8 阶段单向链,无回退边;推进前置 status=IN_TREATMENT 由 service 层校验):
出行记录 trip_record.status(trip 域 tripTransitions):PLANNED → {BOOKED, CANCELLED};BOOKED → {COMPLETED, CANCELLED}。CANCELLED/COMPLETED 终态不可迁。
账号 user_account.status(SetUserStatusInTx):ACTIVE ⇄ DISABLED 双向(禁用/启用)。
医院/科室/专家 status(三处同构,hospital/pure.go:99/116/133):DRAFT → PUBLISHED → OFFLINE → PUBLISHED 单向环(无回 DRAFT——已发布语义不可撤销为草稿)。
TOTP user_account.totp_status 三态(user 域,⚠ DIF-M8 ①):NONE → PENDING(setup 生成密钥)→ ENABLED(验首码转正);ENABLED → NONE(disable 验现码解绑 / ADMIN 重置清密钥);PENDING 态不触发两段式登录(否则 setup 与登录互相锁死)。
chat_msg_ext.translation_status(非 transition 封装、worker CAS 回写):NONE(不投翻译:CARD/IMAGE)→ PENDING → DONE / FAILED(FAILED 可 retranslate 重投)。
2.3 通用校验与一致性(全系统不变量)
- 单库 DB 事务 + version CAS(tech-design §1 降级裁决,比模板三层补偿更强更简):写方法 service 层
WithTx包事务;状态表必带version列,状态变更走状态谓词 CAS(WHERE id=? AND status=?,SET version=version+1——from 漂移即ErrVersionConflict409)。 - 禁裸 UPDATE 状态列(AST 守卫强制):状态列 UPDATE 的字符串字面量只准出现在 transition 封装内;白名单函数全集 =
TransitionInTx(ticket)/TransitionOrderInTx(payment)/TransitionStageInTx(care_stage)/TransitionTripInTx(trip)/SetUserStatusInTx(user)/TransitionHospitalInTx/TransitionDeptStatusInTx/TransitionExpertStatusInTx(hospital 三同构);行内注释ast-status-guard:exempt申报豁免(非状态列回填如 ticket_no/receipt_object_key)。 - 迁移-日志同路径:每次状态变更 = transition 封装内同事务写
entity_lifecycle_event(from/to)+operation_log(actor/reason)——无独立日志通道。 - 读路径绝不加锁:全部业务读直查 dbmap,无任何串行化设施。
- 幂等:
payment_webhook_event(provider+event_id UNIQUE,INSERT 冲突=重复投递直接 200);注册绑定 CAS 谓词(WHERE patient_id=0)天然幂等;seed 幂等INSERT IGNORE。 - SSE 推送在事务 Commit 后(⚠ DIF-M5 ③):事务内推则回滚放假事件;失败仅 warn 不反压业务。
- NOT NULL + 哨兵值(原则六):全表基础类型列 NOT NULL + 哨兵(
''/0/'NONE',ENUM 必须显式 DEFAULT);NULL 豁免仅限「尚未发生」语义列(paid_at/read_at/prediagnosis_summary/plan/translated_text等)+ 守卫白名单两条(user_account.totp_secret、payment_order.refund_amount);not_null_guard / pointer_field_guard 双守卫防 stale。 - 守卫总表:9 类机器守卫全表见 tech-design §13.2(check_consistency / not_null / pointer_field / lifecycle 入口覆盖 / 迁移-日志 AST / 状态机白名单 / 翻译覆盖锁 / SSE 事件注册表 / e2e 十段断言)。
2.4 错误响应约定(纯 HTTP 状态码 + 哨兵错误映射)
- 机制:与模板的字符串错误码不同,本项目 handler 统一返回
echo.NewHTTPError(status)裸 HTTP 状态码(全仓零ErrResp调用——grep 盘点实证);业务语义由 service 层哨兵错误(errors.New包级单例)+ handlermapErr的errors.Is映射承载。响应体不携带业务码字符串,前端按状态码分流。 - 状态码分布(grep 实测全仓
NewHTTPError计数,domain+gateway):400×87 / 500×17 / 409×13 / 404×12 / 401×7 / 429×1 / 503×2 / 403×2。 - 哨兵错误 → 状态码映射惯例(权威映射在各域 handler mapErr;正面样例):
- 400:bind/校验失败、
ErrWeakPassword族、ErrBadMIME/ErrTooLarge、ErrInvalidStageTransition例外见下、ErrNotRetranslatab、ErrReasonRequired; - 401:
auth.ErrInvalidCredentials(三端登录统一——防枚举);403:ticket.ErrForbidden(归属谓词); - 404:
ErrNotFound族(ticket/patient/chat.ErrNotFound、ErrOrderNotFound、ErrExpertNotFound、ErrTicketNotFound——归属不符与不存在同语义不泄露存在性); - 409:
ErrVersionConflict(CAS)、ErrInvalidTransition(白名单)、ErrSessionBound、ErrEmailTaken、ErrDocQuota、ErrDocOwnership、ErrNotPayable、ErrReceiptNotReady、ErrNotInTreatment、ErrTOTPAlreadyEnabled、ErrDocGroupConflict、ErrInvalidHospitalTransition、ErrNotPatient; - 503:可选依赖未配置(jwt.secret 空→受保护面 401 例外、webhook_secret 空、master_key 空的 2FA 路径)。
- 400:bind/校验失败、
- 收敛方向(tech-design §2.4 同族):资源不存在=404、CAS 冲突/业务拒绝=409、可判定校验=400——现状 gorp 层错误多归 500 族(127 处中 15 处),是已知待收敛项不扩面。
- 哨兵错误清单全表:见 99-附录 C。
2.5 直传三步协议通用规则(病历 / 聊天图 / 医院图 / 阶段资料四处同构)
- 三步:①
POST .../presign(校验登录态+配额+size/mime 申报)→ 签发带 policy 的预签名 PUT URL(content-length-range 0..N MB+ mime 白名单 + 15min)——policy 签名在存储侧硬性拦截超限;②浏览器直传(不占后端带宽);③POST .../confirm:服务端 HeadObject 复核实际 size/mime(不信任客户端申报,第二道拦截)→ 配额复核 → 落库。 - 限制的执行点在服务端两道,存储只是执行器不是规则源;配额=第一道 presign 前 COUNT + confirm 二次 COUNT(⚠ DIF-M4 ⑭①:confirm 复核带
ticket_id=0谓词,已绑定历史文档不占新配额)。 - mime 白名单:病历 pdf/jpg/png 20MB;聊天图 jpg/png 10MB(mini 两步);医院图/阶段资料同病历口径。
- 对象存储:
storage.Store接口隔离——dev/e2e=minio S3 兼容(LAN 192.168.50.190:9000),单测=localfs 不连外部服务;S3 的「对象 mime」=上传方 Content-Type 元数据(presign 已锁死申报),真内容校验随生产 OSS driver 加服务端嗅探(⚠ DIF-M4 ① 已知局限)。
2.6 双日志轨与可选依赖降级
- 双日志轨分工:
entity_lifecycle_event(对象全时间线,A/C 两轴事件同表靠值区分)服务「对象经历了什么」;operation_log(标准列 actor_id/reason/trace_id/changes JSON)服务「谁在什么时候改了什么」——/api全部写方法经中间件统一记录 + 豁免注册表,关键操作 service 内显式补记带 reason。actor 落actor_id BIGINT(0=系统/匿名)——GDPR 匿名化自动传播到全部历史日志(⚠ DIF-M1)。 - 可选依赖降级矩阵(缺省=功能降级可见,不阻塞起服):jwt.secret 空→受保护面一律 401;master_key 空→TOTP 相关返
ErrKeyNotConfigured;webhook_secret 空→/webhooks/stripe一律 503;redis 缺→限流回落内存内核、RBAC 直查 DB、翻译缓存直查(不降级放行也不误杀);receiptIO 未注入→凭证生成跳过、下载 409;mailer=log 档(日志即送达)。 - 通知双通道:EMAIL(dispatcher 30s 扫描指数退避、3 败 FAILED 可人工重发)/ INBOX(常驻 PENDING + read_at 列,dispatcher 不消费——已读语义独立于投递语义)。
- SSE hub 单实例(进程内 map[sessionKey]map[connID]conn,buffer 8 慢消费者丢弃+失步标记,25s 心跳);多实例扩容换 Redis pub/sub,接口不变(tech-design §15 风险 7)。
3. 功能模块清单(ID 冻结 v1.0)
状态列:
实现/实现(代码先行)(代码有而 SRS 无)。 代码域 ↔ 功能模块映射:auth+gateway→m01;hospital→m02;chat→m03;patient→m04;ticket→m04(直传三步)+m05;diagnosis→m06;payment→m07;care→m08;trip→m09;user+audit+infra/notify→m10。
m01 账号认证与权限
| 功能 ID | 名称 | 对应 SRS | 状态 |
|---|---|---|---|
| F1.01 | B 端两段式登录(密码+TOTP) | SRS §4.2(机制细化) | 实现(代码先行) |
| F1.02 | 患者登录(email+密码) | —(DIF-001 待产品确认) | 实现(代码先行) |
| F1.03 | 访客会话签发 guest-session | —(获客漏斗前置件) | 实现(代码先行) |
| F1.04 | JWT 五面鉴权与路由矩阵 | SRS §4.2 | 实现(代码先行) |
| F1.05 | RBAC 权限码字典与路由守卫 | SRS §4.2 | 实现(代码先行) |
| F1.06 | /pub IP 限流(内存/Redis 双内核) | SRS §4.1(防滥用) | 实现(代码先行) |
m02 医院主数据与展示
| 功能 ID | 名称 | 对应 SRS | 状态 |
|---|---|---|---|
| F2.01 | 公开医院列表 | F-HOS-001 | 实现 |
| F2.02 | 公开医院详情 | F-HOS-002 | 实现 |
| F2.03 | B 端医院维护与状态流转 | F-ADMIN-001 | 实现 |
| F2.04 | 医院封面图直传 | F-ADMIN-001 | 实现 |
| F2.05 | 科室管理 | F-ADMIN-001 | 实现 |
| F2.06 | 专家库管理 | —(M10 扩展批次) | 实现(代码先行) |
m03 双语咨询
| 功能 ID | 名称 | 对应 SRS | 状态 |
|---|---|---|---|
| F3.01 | 创建匿名咨询会话 | F-CHAT-001 | 实现 |
| F3.02 | SSE 流与心跳重连 | F-CHAT-002 | 实现 |
| F3.03 | 发消息与异步翻译回填 | F-CHAT-002 | 实现 |
| F3.04 | 图片消息 | F-CHAT-002 | 实现 |
| F3.05 | 已读回执 | F-CHAT-002 | 实现 |
| F3.06 | B 端会话管理与回复 | F-CHAT-002 | 实现 |
| F3.07 | 注册卡片推送 | F-CHAT-003 | 实现 |
| F3.08 | 患者端聊天(/pt 转正+重译) | F-CHAT-002 | 实现 |
m04 患者注册与病历
| 功能 ID | 名称 | 对应 SRS | 状态 |
|---|---|---|---|
| F4.01 | 注册事务链(建账号+绑会话+开单+通知) | F-REG-001 / F-TICK-001 | 实现 |
| F4.02 | 病历直传三步协议 | F-REG-002 | 实现 |
| F4.03 | 注册完成通知(确认邮件+顾问 INBOX) | F-REG-003 | 实现 |
| F4.04 | 患者资料与进度派生(/pt/me、/pt/progress) | F-TICK-003(患者侧) | 实现 |
| F4.05 | GDPR 导出与抹除 | SRS §4.2(落地为 ADMIN 直触发) | 实现(细节代码先行) |
m05 工单与看板
| 功能 ID | 名称 | 对应 SRS | 状态 |
|---|---|---|---|
| F5.01 | 工单自动生成 | F-TICK-001 | 实现 |
| F5.02 | 工单分配与流转 | F-TICK-002 | 实现 |
| F5.03 | 状态机 transition() 与三条回退边 | F-TICK-002(状态机) | 实现(机制代码先行) |
| F5.04 | 病历下载与版本组读 | F-CARE-002(就医前部分) | 实现(部分代码先行) |
| F5.05 | 运营看板(聚合+三超时+对账 tab) | F-ADMIN-003 | 实现 |
m06 预诊断与方案
| 功能 ID | 名称 | 对应 SRS | 状态 |
|---|---|---|---|
| F6.01 | 医生工作台(预诊+专家选人 dept 锚) | F-DIAG-001 | 实现(专家选人代码先行) |
| F6.02 | 拒绝与重派 | F-TICK-002(医生确认/拒绝) | 实现(代码先行) |
| F6.03 | 患者方案确认 | F-DIAG-002 | 实现 |
m07 支付与对账
| 功能 ID | 名称 | 对应 SRS | 状态 |
|---|---|---|---|
| F7.01 | 定金支付(Stripe Checkout) | F-PAY-001 | 实现 |
| F7.02 | webhook 验签与幂等 | F-PAY-001 | 实现 |
| F7.03 | 支付凭证 PDF | F-PAY-001 | 实现(代码先行) |
| F7.04 | 后台支付管理与对账 | F-PAY-001(状态更新) | 实现(对账部分代码先行) |
| F7.05 | 残留单人工关单 | —(对账兜底) | 实现(代码先行) |
m08 诊疗过程
| 功能 ID | 名称 | 对应 SRS | 状态 |
|---|---|---|---|
| F8.01 | C 轴 8 阶段推进 | F-CARE-001 | 实现 |
| F8.02 | 阶段资料版本组 | F-CARE-002 | 实现 |
| F8.03 | 患者进度同步 | F-CARE-003 | 实现 |
m09 出行协助
| 功能 ID | 名称 | 对应 SRS | 状态 |
|---|---|---|---|
| F9.01 | 酒店安排 | F-TRIP-001 | 实现 |
| F9.02 | 交通安排 | F-TRIP-002 | 实现 |
| F9.03 | 患者只读拉取(/pt/trips) | F-TRIP(患者可见) | 实现(代码先行) |
m10 系统管理与审计
| 功能 ID | 名称 | 对应 SRS | 状态 |
|---|---|---|---|
| F10.01 | 用户管理(CRUD/禁用/改角色/重密) | F-ADMIN-002 | 实现 |
| F10.02 | TOTP 2FA 管理(三态机+重置) | SRS §4.2(细化) | 实现(代码先行) |
| F10.03 | 生命周期时间线查询 | F-TICK-003(后台日志) | 实现(代码先行) |
| F10.04 | 操作日志审计页 | SRS §4.2 | 实现(代码先行) |
| F10.05 | INBOX 待办与邮件对账重发 | F-REG-003(扩展) | 实现(代码先行) |
| F10.06 | outbox 投递与重试 | —(基础设施) | 实现(代码先行) |
4. 功能详述
一功能一节(
#### F<n>.<nn> 名称),固定 8 小节:1 功能定义 / 2 触发条件与前置状态 / 3 输入与校验 / 4 处理流程 / 5 输出与结果状态 / 6 状态流转 / 7 边界与异常 / 8 权限与数据规则。 节头元数据行:> 对应 SRS:… | 实现落点:file:line | 操作入口:…(操作入口 = 客户端词表 + 页面路由 + 关键操作;无 UI 节标注 API/定时任务/SSE)。 各节按模块分册:m01 · m02 · m03 · m04 · m05 · m06 · m07 · m08 · m09 · m10 · 99-附录