# MediLink Global 功能规格说明书（FSD）v1.0 · 总则

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

---

> 上游文档：[prd/srs-medilink-v1.md](/prd/srs-medilink-v1/)（v1.1，需求唯一权威源）。本文档以**代码实现**为事实基准，还原系统真实运转规则；与 SRS 的差异以 ⚠ DIF 注记标出并登记 [99-附录](/prd/fsd-medilink/99-%E9%99%84%E5%BD%95/) 差异台账。
> 功能 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](/prd/fsd-medilink/m01-%E8%B4%A6%E5%8F%B7%E8%AE%A4%E8%AF%81%E4%B8%8E%E6%9D%83%E9%99%90/) 共 10 册 + [99-附录](/prd/fsd-medilink/99-%E9%99%84%E5%BD%95/)，`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 issuer `mfa`（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（key `rbac:<库名>:perm:<role>:pv<pv>`，JWT claim `pv` 隔离版本）；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` | 已完成（终态） |

```mermaid
stateDiagram-v2
    CREATED --> PENDING_ASSIGN: 自动开单流转
    PENDING_ASSIGN --> PREDIAGNOSING: 分配医生（ticket:assign）
    PREDIAGNOSING --> PLAN_CONFIRMING: 医生提交预诊（diag:write）
    PREDIAGNOSING --> PENDING_ASSIGN: 回退边3——医生拒绝重派（diag:write）
    PLAN_CONFIRMING --> PENDING_PAYMENT: 患者创建支付单
    PENDING_PAYMENT --> PENDING_DEPARTURE: 支付成功回调
    PENDING_PAYMENT --> PLAN_CONFIRMING: 回退边1——支付失败重谈
    PENDING_DEPARTURE --> IN_TREATMENT: 顾问流转
    PENDING_DEPARTURE --> PLAN_CONFIRMING: 回退边2——改方案
    IN_TREATMENT --> COMPLETED: 完成
```

- `COMPLETED` 终态不可迁；三条回退边是设计补充（边 1 由支付失败回调驱动、边 3 由医生拒绝驱动，边 2 手动触发权限待产品确认——tech-design §15 风险 3）；迁移只准走 `TransitionInTx`（status 谓词 CAS + lifecycle + op_log 同事务）。

**支付单 `payment_order.status`**（`payment/pure.go:15`）：

```mermaid
stateDiagram-v2
    PENDING --> SUCCEEDED: webhook 支付成功（CAS）
    PENDING --> FAILED: 失败/人工关单
```

- `SUCCEEDED→REFUNDED` 不入白名单（MVP 无自动退款，人工线下改库必走 operation_log 带 reason）；`FAILED` 不复活——重谈后新建支付单（PENDING 复用谓词：同工单已有 PENDING 单则复用重新 CreateCheckout，防残留单堆积，⚠ DIF-M8 ⑦）。

**诊疗阶段 `ticket.care_stage`（C 轴）**（`care` 域 `stageTransitions`，8 阶段单向链，无回退边；推进前置 `status=IN_TREATMENT` 由 service 层校验）：

```mermaid
stateDiagram-v2
    NONE --> PREP_DEPARTURE
    PREP_DEPARTURE --> ARRIVAL
    ARRIVAL --> FIRST_VISIT
    FIRST_VISIT --> EXAM
    EXAM --> DIAGNOSIS
    DIAGNOSIS --> TREATMENT
    TREATMENT --> RECOVERY
    RECOVERY --> DEPARTURE
```

**出行记录 `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 通用校验与一致性（全系统不变量）

1. **单库 DB 事务 + version CAS**（tech-design §1 降级裁决，比模板三层补偿更强更简）：写方法 service 层 `WithTx` 包事务；状态表必带 `version` 列，状态变更走**状态谓词 CAS**（`WHERE id=? AND status=?`，SET version=version+1——from 漂移即 `ErrVersionConflict` 409）。
2. **禁裸 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）。
3. **迁移-日志同路径**：每次状态变更 = transition 封装内同事务写 `entity_lifecycle_event`（from/to）+ `operation_log`（actor/reason）——无独立日志通道。
4. **读路径绝不加锁**：全部业务读直查 dbmap，无任何串行化设施。
5. **幂等**：`payment_webhook_event`（provider+event_id UNIQUE，INSERT 冲突=重复投递直接 200）；注册绑定 CAS 谓词（`WHERE patient_id=0`）天然幂等；seed 幂等 `INSERT IGNORE`。
6. **SSE 推送在事务 Commit 后**（⚠ DIF-M5 ③）：事务内推则回滚放假事件；失败仅 warn 不反压业务。
7. **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。
8. **守卫总表**：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` 包级单例）+ handler `mapErr` 的 `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 路径）。
- 收敛方向（tech-design §2.4 同族）：资源不存在=404、CAS 冲突/业务拒绝=409、可判定校验=400——现状 gorp 层错误多归 500 族（127 处中 15 处），是已知待收敛项不扩面。
- 哨兵错误清单全表：见 [99-附录](/prd/fsd-medilink/99-%E9%99%84%E5%BD%95/) C。

### 2.5 直传三步协议通用规则（病历 / 聊天图 / 医院图 / 阶段资料四处同构）

1. **三步**：①`POST .../presign`（校验登录态+配额+size/mime 申报）→ 签发带 policy 的预签名 PUT URL（`content-length-range 0..N MB` + mime 白名单 + 15min）——policy 签名在存储侧硬性拦截超限；②浏览器直传（不占后端带宽）；③`POST .../confirm`：服务端 HeadObject 复核实际 size/mime（不信任客户端申报，**第二道拦截**）→ 配额复核 → 落库。
2. **限制的执行点在服务端两道**，存储只是执行器不是规则源；配额=第一道 presign 前 COUNT + confirm 二次 COUNT（⚠ DIF-M4 ⑭①：confirm 复核带 `ticket_id=0` 谓词，已绑定历史文档不占新配额）。
3. **mime 白名单**：病历 pdf/jpg/png 20MB；聊天图 jpg/png 10MB（mini 两步）；医院图/阶段资料同病历口径。
4. **对象存储**：`storage.Store` 接口隔离——dev/e2e=minio S3 兼容（LAN 192.168.50.190:9000），单测=localfs 不连外部服务；S3 的「对象 mime」=上传方 Content-Type 元数据（presign 已锁死申报），真内容校验随生产 OSS driver 加服务端嗅探（⚠ DIF-M4 ① 已知局限）。

### 2.6 双日志轨与可选依赖降级

1. **双日志轨分工**：`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）。
2. **可选依赖降级矩阵**（缺省=功能降级可见，不阻塞起服）：jwt.secret 空→受保护面一律 401；master_key 空→TOTP 相关返 `ErrKeyNotConfigured`；webhook_secret 空→`/webhooks/stripe` 一律 503；redis 缺→限流回落内存内核、RBAC 直查 DB、翻译缓存直查（不降级放行也不误杀）；receiptIO 未注入→凭证生成跳过、下载 409；mailer=log 档（日志即送达）。
3. **通知双通道**：EMAIL（dispatcher 30s 扫描指数退避、3 败 FAILED 可人工重发）/ INBOX（常驻 PENDING + read_at 列，dispatcher 不消费——已读语义独立于投递语义）。
4. **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](/prd/fsd-medilink/m01-%E8%B4%A6%E5%8F%B7%E8%AE%A4%E8%AF%81%E4%B8%8E%E6%9D%83%E9%99%90/) · [m02](/prd/fsd-medilink/m02-%E5%8C%BB%E9%99%A2%E4%B8%BB%E6%95%B0%E6%8D%AE%E4%B8%8E%E5%B1%95%E7%A4%BA/) · [m03](/prd/fsd-medilink/m03-%E5%8F%8C%E8%AF%AD%E5%92%A8%E8%AF%A2/) · [m04](/prd/fsd-medilink/m04-%E6%82%A3%E8%80%85%E6%B3%A8%E5%86%8C%E4%B8%8E%E7%97%85%E5%8E%86/) · [m05](/prd/fsd-medilink/m05-%E5%B7%A5%E5%8D%95%E4%B8%8E%E7%9C%8B%E6%9D%BF/) · [m06](/prd/fsd-medilink/m06-%E9%A2%84%E8%AF%8A%E6%96%AD%E4%B8%8E%E6%96%B9%E6%A1%88/) · [m07](/prd/fsd-medilink/m07-%E6%94%AF%E4%BB%98%E4%B8%8E%E5%AF%B9%E8%B4%A6/) · [m08](/prd/fsd-medilink/m08-%E8%AF%8A%E7%96%97%E8%BF%87%E7%A8%8B/) · [m09](/prd/fsd-medilink/m09-%E5%87%BA%E8%A1%8C%E5%8D%8F%E5%8A%A9/) · [m10](/prd/fsd-medilink/m10-%E7%B3%BB%E7%BB%9F%E7%AE%A1%E7%90%86%E4%B8%8E%E5%AE%A1%E8%AE%A1/) · [99-附录](/prd/fsd-medilink/99-%E9%99%84%E5%BD%95/)

---

反链：

- [功能规格说明书(FSD)](/prd/fsd-medilink/)
- [FSD m01 · 账号认证与权限（auth + gateway）](/prd/fsd-medilink/m01-%E8%B4%A6%E5%8F%B7%E8%AE%A4%E8%AF%81%E4%B8%8E%E6%9D%83%E9%99%90/)
- [FSD m02 · 医院主数据与展示（hospital）](/prd/fsd-medilink/m02-%E5%8C%BB%E9%99%A2%E4%B8%BB%E6%95%B0%E6%8D%AE%E4%B8%8E%E5%B1%95%E7%A4%BA/)
- [FSD m03 · 双语咨询（chat）](/prd/fsd-medilink/m03-%E5%8F%8C%E8%AF%AD%E5%92%A8%E8%AF%A2/)
- [FSD m04 · 患者注册与病历（patient + ticket 直传）](/prd/fsd-medilink/m04-%E6%82%A3%E8%80%85%E6%B3%A8%E5%86%8C%E4%B8%8E%E7%97%85%E5%8E%86/)
- [FSD m05 · 工单与看板（ticket）](/prd/fsd-medilink/m05-%E5%B7%A5%E5%8D%95%E4%B8%8E%E7%9C%8B%E6%9D%BF/)
- [FSD m06 · 预诊断与方案（diagnosis）](/prd/fsd-medilink/m06-%E9%A2%84%E8%AF%8A%E6%96%AD%E4%B8%8E%E6%96%B9%E6%A1%88/)
- [FSD m07 · 支付与对账（payment）](/prd/fsd-medilink/m07-%E6%94%AF%E4%BB%98%E4%B8%8E%E5%AF%B9%E8%B4%A6/)
- [FSD m08 · 诊疗过程（care）](/prd/fsd-medilink/m08-%E8%AF%8A%E7%96%97%E8%BF%87%E7%A8%8B/)
- [FSD m09 · 出行协助（trip）](/prd/fsd-medilink/m09-%E5%87%BA%E8%A1%8C%E5%8D%8F%E5%8A%A9/)
- [FSD m10 · 系统管理与审计（user + audit + infra/notify）](/prd/fsd-medilink/m10-%E7%B3%BB%E7%BB%9F%E7%AE%A1%E7%90%86%E4%B8%8E%E5%AE%A1%E8%AE%A1/)
