FSD m09 · 出行协助(trip)
本册覆盖代码域
internal/domain/trip(单表trip_record,detail JSON 列承载酒店/交通字段差异)。全局规则见 00-总则 §2(trip 状态机 §2.2)。
m09 功能节目录
| ID | 名称 | 路由/入口 |
|---|---|---|
| F9.01 | 酒店安排 | POST /api/trips(kind=HOTEL)、POST /api/trips/:id/transition |
| F9.02 | 交通安排 | POST /api/trips(kind=TRANSPORT)、POST /api/trips/:id/transition |
| F9.03 | 患者只读拉取 | GET /pt/trips |
F9.01 酒店安排
对应 SRS:F-TRIP-001 | 实现落点:
internal/domain/trip/service.go:60(Create)/Transition(tripTransitions 白名单)/main.go:319-321(路由) | 操作入口:web 工单详情出行协助区「新增记录」(顾问)
1 功能定义
顾问为工单创建酒店安排记录(推荐合作酒店/距离价格翻译服务说明/预订需求/状态记录):kind='HOTEL',字段差异进 detail JSON 列(服务端透传不校验内部结构——SRS §7「首期人工协助,系统仅做记录,不自动对接 OTA」)。状态机 PLANNED→BOOKED→COMPLETED/CANCELLED。
2 触发条件与前置状态
trip:write(CONSULTANT);工单存在(防挂空单——Create 归属校验 404)。
3 输入与校验
| 字段 | 类型 | 校验 |
|---|---|---|
| ticket_id | int64 | 工单存在性(404 ErrTicketNotFound) |
| kind | enum | HOTEL / TRANSPORT(值域见 entity; kind 白名单校验) |
| title | string | 记录标题 |
| scheduled_at | datetime 可空 | 预定时间 |
| detail | JSON | 明细对象(服务端不校验内部结构——零字段级查询 MVP) |
| note | string 可空 | 备注 |
JSONBytes 类型:Scan/Marshal 双实现(json.RawMessage 无 sql.Scanner——活体 SELECT * 即 500 的「双处登记」教训型修正,⚠ DIF-M8 ⑧)。
4 处理流程
5 输出与结果状态
记录 JSON(id/ticket_id/kind/title/status/scheduled_at/detail/note/version…——json tag snake_case,DIF-M8 ⑧ 整形);患者端 /pt/trips 可见(F9.03)。
6 状态流转
PLANNED → {BOOKED, CANCELLED};BOOKED → {COMPLETED, CANCELLED};CANCELLED/COMPLETED 终态不可迁(tripTransitions 白名单+守卫测试锁定);lifecycle entity_type=‘trip’(无专属 trip_log 表——双日志轨兑现六原则,DIF-M7 ①)。
7 边界与异常
| 场景 | 行为 |
|---|---|
| 工单不存在 | 404 |
| 白名单外流转(如 PLANNED→COMPLETED) | 409 ErrInvalidTripTransition |
| 并发流转 | 409(status 谓词 CAS) |
| OTA 对接 | 不做(SRS §7 明示人工协助——枚举与 detail 结构为未来演进留位) |
8 权限与数据规则
trip:write 创建与流转;ticket:read 工单聚合读(web 详情);detail JSON 原生存储无注入面(JSONBytes 序列化边界)。
F9.02 交通安排
对应 SRS:F-TRIP-002 | 实现落点:同 F9.01(
kind='TRANSPORT'同一 Create/Transition 路径) | 操作入口:web 工单详情出行协助区「新增记录」
1 功能定义
顾问创建交通安排记录(机场接送/就医期间交通/信息同步):与 F9.01 完全同构,仅 kind='TRANSPORT';detail JSON 承载航班号/接送点等字段差异。
2 触发条件与前置状态
同 F9.01(trip:write + 工单存在)。
3 输入与校验
同 F9.01(kind 值域差异)。
4 处理流程
同 F9.01 §4。
5 输出与结果状态
同 F9.01;工单时间线出行节点内嵌展示。
6 状态流转
同 F9.01。
7 边界与异常
同 F9.01(kind 与状态机正交——状态机不区分酒店/交通)。
8 权限与数据规则
同 F9.01。
F9.03 患者只读拉取(/pt/trips)
对应 SRS:F-TRIP(患者可见信息同步) | 实现落点:
internal/domain/trip/service.go:113(ListByPatient)/main.go:322(路由) | 操作入口:app H5#/pages/progress出行信息区
1 功能定义
患者拉取本人最新工单的出行协助记录(只读):直查口径沿 DIF-M6 ⑤(patient_id→最新工单→ListByTicket)。无 SSE 推送(患者拉取式——DIF-M7 ⑦ 明确不做清单:SSE 注册表守卫不扩面)。
2 触发条件与前置状态
pt JWT;无工单返回空列表(非 404——进度页语义)。
3 输入与校验
无入参(patient_id=claims.Sub)。
4 处理流程
5 输出与结果状态
记录数组(同 F9.01 JSON 形态)。
6 状态流转
只读;患者不可创建/流转出行记录。
7 边界与异常
| 场景 | 行为 |
|---|---|
| 无工单 | 200 空列表 |
| SSE 实时性 | 无——打开进度页时拉取(拉取式口径) |
| 多工单 | 最新一单的记录(一人一单 MVP 语义) |
8 权限与数据规则
pt JWT + patient_id 直查(不走权限码);记录全量可见(无字段级脱敏——出行信息非敏感 PII)。