FSD 99 · 附录
A. SRS 需求 ID → FSD 功能节 权威对照表
SRS §3 共 22 个功能 ID;一个 SRS 功能可拆多个 FSD 节(实现粒度),一个 FSD 节可承载多个 SRS 功能(事务链)。FSD 50 节中 28 节直接对应 SRS,22 节为代码先行(基础设施/扩展批次)。
| SRS ID | SRS 功能名 | FSD 功能节 |
|---|---|---|
| F-HOS-001 | 医院列表展示 | F2.01 |
| F-HOS-002 | 医院详情页 | F2.02 |
| F-CHAT-001 | 聊天入口 | F3.01 |
| F-CHAT-002 | 实时双语聊天 | F3.02 / F3.03 / F3.04 / F3.05 / F3.06 / F3.08 |
| F-CHAT-003 | 注册登记推送 | F3.07(卡片)+ F4.03(完成通知) |
| F-REG-001 | 患者注册 | F4.01 |
| F-REG-002 | 病历资料上传 | F4.02 |
| F-REG-003 | 注册完成确认 | F4.03(通知)+ F4.01 响应(成功页/工单号语义) |
| F-TICK-001 | 工单自动生成 | F5.01(F4.01 事务链内) |
| F-TICK-002 | 工单分配与流转 | F5.02 / F5.03 / F6.02(医生拒绝) |
| F-TICK-003 | 工单状态跟踪 | F4.04(患者进度)+ F5.05(后台看板)+ F10.03(时间线) |
| F-DIAG-001 | 医生工作台 | F6.01 |
| F-DIAG-002 | 诊疗方案确认 | F6.03 |
| F-PAY-001 | 定金支付 | F7.01 / F7.02 / F7.03 / F7.04 |
| F-TRIP-001 | 酒店安排 | F9.01 |
| F-TRIP-002 | 交通安排 | F9.02 |
| F-CARE-001 | 8 个标准阶段定义 | F8.01 |
| F-CARE-002 | 阶段信息上传 | F8.02(就医前部分=F5.04/F4.02) |
| F-CARE-003 | 患者进度同步 | F8.03 |
| F-ADMIN-001 | 医院信息管理 | F2.03 / F2.04 / F2.05 / F2.06 |
| F-ADMIN-002 | 用户管理 | F10.01 / F10.02 |
| F-ADMIN-003 | 工单监控 | F5.05 |
代码先行 22 节(SRS 无对应条目):F1.01-F1.06(认证与权限基础设施)、F2.06(专家库 M10 扩展)、F6.01 专家选人部分、F7.03(凭证 PDF)/F7.05(关单)、F9.03(患者只读)、F10.02(2FA 三态细化)/F10.04(审计页)/F10.05(INBOX 对账)/F10.06(outbox 基础设施)。
B. 实现差异与疑似缺陷登记
编号规则
DIF-F<m>-<序号>(正文行内注记同号;DIF-全局-1 口径差类仅登记于本台账)——与DIF-M<n> ①体系的关系:DIF-M 系 tech-design 里程碑批次差异编号(权威源docs/tech-design.md§14 与docs/开发任务总表.md,正文各册大量行内引用),DIF-F 系本 FSD 自有编号(权威源本台账),两套并存不换算。「疑似缺陷」= 实现与注释/常识意图不符且无裁决记录者——修复需用户裁决,本文档只登记现状。
| 编号 | 类型 | 现状(file:line) | SRS/意图期望 | 影响面 | 处置建议 |
|---|---|---|---|---|---|
| DIF-F2-1 | 已修复(2026-10-09 用户裁决完整修复,M13) | 原状:医院编辑置空富文本——Update SQL 硬编码 intro_intl=NULL, services=NULL, visit_process=NULL, image_object_key='',且 web 无编辑入口;UpdateHospitalInput 注释「保留现值」与实现矛盾 | F-ADMIN-001 编辑应保留未提交字段;富文本应有维护入口 | 修复:三列 *string 三态(缺省=保留,SQL COALESCE(?, col) 兜底)+封面图剔除出编辑语句(只走三步协议)+web 编辑 Modal 九列回填(service_write.go:82 / Hospitals.tsx);回归锁 service_write_test.go 三态表驱动+e2e F-ADMIN 断言 | 已落地 |
| DIF-F2-2 | 已修复(2026-10-09 随 DIF-F2-1 一并,M13) | 原状:专家简介不可改(UpdateExpertInput 无 intro 字段,注释「简介编辑走后续需求」) | 主数据编辑完备性 | 修复:UpdateExpert 补 intro = COALESCE(?, intro) 三态+建专家表单补简介输入(service_write.go:214);专家列表/独立编辑 UI 仍未立项(「只建不列」口径不变,API 层已可编辑) | API 已落地;UI 待需求 |
| DIF-F2-3 | 已修复(2026-10-10 M14 /review-plan 核查发现即修) | 原状:建院 POST 链路富文本三列断链——web 建院表单提交 intro_intl/services/visit_process,但 CreateHospital handler req struct 不收三列、透传 CreateHospitalInput 亦缺(handler_bo.go),表单值被静默丢弃;F2.03③ 输入表早列三列属「文档先行于实现」 | F-ADMIN-001 建院应保留表单提交字段 | 修复:handler req+透传补三列 *string(与 PUT 三态语义一致,handler_bo.go);回归锁 TestHandler_CreateHospital_BindsRichTextPtr(带三列→指针透传/缺省→nil)+e2e F-ADMIN 建院真库回查+web POST payload 锁 | 已落地 |
| DIF-F3-1 | 已修复(2026-10-10 M15 用户裁决顺手修) | 原状:app 医院详情页「咨询」按钮点击抛 ReferenceError——onConsult 引用未定义变量 hospital(应为 detail),F3.01 详情页咨询入口不可用(detail/index.tsx) | F-CHAT-001 操作入口(m03:22「app H5 医院详情页『咨询』按钮」) | 修复:hospital.id → detail.id(null 守卫防御);回归锁 app/__tests__/detail.test.tsx「点 Consult Now → navigateTo 带 hospital_id」用例(先红:ReferenceError 实证) | 已落地 |
| DIF-F5-1 | 观察项 | 分配不校验 assignee 存在性/角色:Assign 仅 version CAS 写列(service_bo.go:171),assignee_id 可为不存在 id 或患者 id | F-TICK-002 分配语义健全性 | 错误 id 可写入(前端用户列表正常使用时不触发) | service 层补 assignee 存在性+角色校验 |
| DIF-F8-1 | 未实现 | 患者待办事项:SRS F-CARE-003 列出,无对应实体与端点 | F-CARE-003 | 患者进度页无待办区块 | 产品裁决后立项 |
| DIF-F10-1 | 观察项 | 用户管理无自我保护谓词:ADMIN 可禁用自己/改自己角色(user/service.go:159/176) | 后台管理安全性 | 最后一个 ADMIN 可能被自禁(seed 有 ADMIN 兜底) | 禁自禁/自降权谓词 |
| DIF-全局-1 | 口径差 | tech-design §5.1 记「21 张表」,实施收敛为 19 张(translation_cache→Redis 不建表 DIF-M3 ⑥;care_stage_record/trip_arrangement 合并为 trip_record+lifecycle 行集 DIF-M7 ①) | 设计文档与实现一致 | 文档口径 | 本 FSD 以 full.sql 实测为准(P3 数据库总览对账) |
C. 哨兵错误 → HTTP 状态码注册表
机制见总则 §2.4(纯状态码+errors.Is 映射,无业务码字符串)。按域盘点(映射落点=各域 handler mapErr)。
auth / gateway
| 哨兵错误 | 状态码 | 场景 |
|---|---|---|
auth.ErrInvalidCredentials | 401 | 三端登录统一(邮箱不存在/密码错/禁用/role 不符/码错——防枚举) |
ErrTOTPAlreadyEnabled | 409 | setup 时已 ENABLED |
ErrNotConfigured(jwt.secret 空) | 401(受保护面)/ 503(guest-session) | 可选缺省降级 |
| 限流超窗 | 429 | gateway/ratelimit.go:84 |
patient / chat / ticket
| 哨兵错误 | 状态码 | 场景 |
|---|---|---|
ErrEmailTaken | 409 | 注册/建号邮箱唯一 |
ErrDocOwnership | 409 | 注册文档归属对账 affected 不符 |
patient.ErrNotFound | 404 | /pt/me 无账号 |
chat.ErrNotFound | 404 | 会话/消息不可见(含跨 gsid 统一不可见) |
chat.ErrSessionBound | 409 | 绑定后 guest 语义作废 / 绑定竞态 |
ErrNotRetranslatab | 400 | DONE/NONE 重译拒绝 |
ticket.ErrDocQuota | 409 | 第 11 份文档 |
ticket.ErrInvalidTransition | 409 | A 轴白名单外 |
ticket.ErrInvalidStageTransition | 409 | C 轴回退/跳段 |
ticket.ErrVersionConflict | 409 | CAS 命中 0 行(流转/分配/写列/墓碑) |
ticket.ErrNotFound / ErrForbidden | 404 / 403 | 文档不可见 / 归属谓词不过 |
ticket.ErrDocGroupConflict | 409 | 版本替换并发 |
hospital / diagnosis / payment / care / trip / user / notify
| 哨兵错误 | 状态码 | 场景 |
|---|---|---|
hospital.ErrNotFound(含公开面非 PUBLISHED) | 404 | 不存在与运营中不可区分 |
hospital.ErrInvalidHospitalTransition | 409 | 三同构状态机白名单外 |
hospital.ErrVersionConflict | 409 | 编辑/流转 CAS |
hospital.ErrBadImageMime | 400 | 封面图 mime 前置 |
ErrExpertNotFound | 404 | 医生选人查无此专家(M10 核查 A3 收口) |
ValidateExpertSelection 失败 | 409 | 专家非 PUBLISHED/院区不符 |
payment.ErrOrderNotFound | 404 | 支付单不存在/归属不符(同语义) |
payment.ErrTicketNotFound | 404 | 患者无工单 |
payment.ErrNotPayable | 409 | 工单不在 PENDING_PAYMENT |
payment.ErrBadSignature | 400 | webhook 验签失败 |
payment.ErrReceiptNotReady | 409 | 非 SUCCEEDED/能力未装配 |
payment.ErrReasonRequired | 400 | 关单无 reason |
payment.ErrInvalidOrderTransition | 409 | 支付轴白名单外 |
care.ErrNotInTreatment | 409 | C 轴推进前置不满足 |
care.ErrDocGroupInvalid | 400 | 组 0/组不属于本单 |
trip.ErrTicketNotFound | 404 | 挂空单 |
trip.ErrInvalidTripTransition | 409 | 出行轴白名单外 |
user.ErrEmailTaken 等 | 409/400 | 建号冲突/校验 |
patient.ErrNotPatient | 409 | GDPR 抹除目标非患者 |
storage ErrBadMIME/ErrTooLarge/os.ErrNotExist | 400/404 | confirm 第二道/对象缺失 |
D. 与 tech-design 的已知口径差(以实现为准)
| 设计期口径 | 实现现状 | 依据 |
|---|---|---|
| §5.1 「21 张表」 | 19 张 | DIF-M3 ⑥ / DIF-M7 ①(见 B-全局-1) |
| §4.2 「7 个域包」 | 10 个域包(+patient 独立、+trip 独立、care 独立) | domain/ 目录实测 |
| §2 仓库树 docker-compose.yml | 无(DIF-M1 ② 取消) | scripts/ 实测 |
| §3.1 「gopdf v0.38」 | 手写最小 PDF 生成器 | DIF-M10 ① |
| 域包三文件铁律 | 三文件+按职责拆分(worker/scrub/card/image/patient/gdpr 同包分文件) | DIF-M3 ⑬ 放宽口径 |