# FSD 99 · 附录

LLMS 索引： [llms.txt](/llms.txt)

---

## 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 ⑬ 放宽口径 |

---

反链：

- [功能规格说明书(FSD)](/prd/fsd-medilink/)
- [MediLink Global 功能规格说明书（FSD）v1.0 · 总则](/prd/fsd-medilink/00-%E6%80%BB%E5%88%99/)
