Files
th-hotel-simple/docs/project/requirements/M002-v4-order-task-card-domain-model-cp2.md

738 lines
39 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# M002 V4 CP2 订单任务与多卡领域模型设计
## 文档信息
| 项目 | 内容 |
| --- | --- |
| 文档版本 | 0.4 |
| 日期 | 2026-07-19 |
| 状态 | CP2 设计已确认CP3 表结构、Entity、Mapper、Repository 基线已实现CP4 入站写入新模型已实现CP5 查询接口已实现CP6 卡片确认和 S10/S99 ack 已实现 |
| 适用范围 | M002 V4 入站后的订单任务、多卡、状态、查询和写操作设计 |
| 不适用范围 | V4 复核接口、真实 PMS / OPERA / OHIP、前端页面视觉稿、历史数据迁移 |
## 1. 文档定位
M002 V4 CP1 已完成 SuperAgent V4 回调包入站解析、基础校验、路由适配和 AI transition 最小落库。CP1 仍然把可映射的 V4 event 临时接入 M002 V3 的订单 / 任务 / 任务卡链路。
本文是 CP2 设计文档,用于把 2026-07-18 V4 字段契约落成后续可开发的数据模型和接口草案。
截至 CP8后端已实现本文第 10、11 节中的持久化基线,并已把 SuperAgent V4 入站结果写入新表:普通业务包创建 V4 订单任务、来源邮件展示卡、Basic Information 卡和业务卡V4 S10/S99 创建来源通知。当前已开放 V4 工作台、订单任务列表 / 详情、来源通知详情查询接口、V4 卡片确认接口、S10/S99 来源通知 ack 接口、V4 `REVIEW_REQUIRED` 卡复核解阻接口,以及 Account / Room Type / Rate Code 固定种子目录第一版校验和卡片 `fields[]` 白名单。
后续如本文与 `M002-v4-agent-callback-field-contract.md` 的字段契约冲突,以字段契约为准;如与安全边界冲突,以 `security-access-control-boundary.md` 为准。
## 2. CP1 已完成和 CP2 差距
| 主题 | CP1 当前实现 | V4 目标模型差距 |
| --- | --- | --- |
| 入站识别 | 已识别 `route_code``source_message``order_contexts[]``message_events[]` | CP4 已把有合法 event 的 `order_ref` 建成订单任务聚合CP5 已开放 V4 安全查询接口 |
| SourceMessage | 已按 `source_message.source_message_id` 反查 SourceMessage Inbox | CP4 已固定生成普通业务包内邮件展示卡;邮件正文完整读取仍走 SourceMessage 会话接口 |
| Basic Information | 已写入 V4 Basic Information 独立卡 | CP6 已支持确认并锁定CP7 已支持复核解阻CP8 已支持 Account 固定目录校验、Market / Source 派生和 `fields[]` 白名单 |
| 业务 Event | 可映射 event 临时创建旧 `workflow_reservation_task`,并已额外创建 V4 业务卡 | 旧任务链路仍作前端过渡兼容,后续 V4 查询和写接口完成后再逐步废弃 |
| 技术错误 | 已落 `adapter_contract_error` transition | 已符合目标方向:不创建用户可处理卡 |
| 草稿 / READY / OPERA | 仍复用 V3 草稿、READY 和 OPERA 模拟骨架 | V4 新数据确认口径是不保存草稿、确认后锁定、当前不生成 OPERA |
| 前端查询 | 复用旧任务列表和任务详情 | 需要新订单任务详情接口返回邮件卡、Basic Information 卡和业务卡数组 |
## 3. 领域词汇
| 术语 | 英文建议 | 中文含义 |
| --- | --- | --- |
| AI 回调包 | AI Callback Package | SuperAgent 对本系统提交的一次 V4 JSON 包,对应一个 SourceMessage 和一个 AI batch |
| 来源邮件展示卡 | Source Message Display Card | 由包级 `source_message` 固定生成的只读展示卡,用于查看当前邮件正文、附件和会话入口 |
| 订单任务 | Reservation Order Task | 同一 `source_message_id + order_ref` 在本系统内形成的业务处理聚合,不等同 PMS 订单,也不等同旧 `workflow_reservation_task` 单任务 |
| 本地订单投影 | Reservation Order Projection | 本系统保存的订单归属和业务号投影,当前主要复用 `workflow_reservation_order` |
| 任务卡 | Reservation Task Card | 订单任务下可独立确认、独立锁定的卡片,例如 Basic Information、房间信息、Trace、Rooming List、Payment |
| 技术失败记录 | Adapter / Technical Error | Agent / Adapter / MCP 契约或技术异常,只进入 AI transition 或技术运行记录,不进入用户可处理任务卡 |
## 4. 核心关系
普通业务包:
```text
source_message
-> 1 个来源邮件展示卡
order_contexts[]
-> 每个 order_ref 创建 1 个订单任务
-> 每个订单任务创建 1 张 Basic Information 卡
message_events[]
-> 每个 event 按 order_ref 挂到对应订单任务
-> 每个 event 创建 1 张业务任务卡
target_order
-> 用于订单任务绑定本地订单投影
```
纯通知包 `route_code=S10`
```text
source_message
-> 只显示来源邮件通知卡
-> 不创建订单任务
-> 不创建 Basic Information 或业务卡
```
技术异常:
```text
V4 package / event contract error
-> workflow_reservation_ai_transition
-> system_process_category=ADAPTER_CONTRACT_ERROR
-> 不创建订单任务
-> 不创建任务卡
```
## 5. 卡片类型第一版
| 卡片类型 | 来源 | 是否用户可确认 | 是否可编辑 | 中文说明 |
| --- | --- | --- | --- | --- |
| `SOURCE_MESSAGE_DISPLAY` | `source_message` | 否 | 否 | 普通业务包内固定展示当前邮件和附件入口 |
| `SOURCE_MESSAGE_NOTIFICATION` | `route_code=S10` | 是,仅确认已读 | 否 | 纯通知邮件,只需要用户确认已读 / 已处理 |
| `BASIC_INFORMATION` | `order_contexts[].basic_information` | 是 | 是 | 订单级 Account / Market / Source 卡,第一版 Agent 只给 `account_code` |
| `ROOM_INFORMATION` | `NEW_BOOKING` / `UPDATE_BOOKING` / `CANCEL_BOOKING` | 是 | 是 | 房间信息卡,卡内根据 event_type 展示新建、修改或整单取消字段 |
| `TRACE_RESERVATION_NOTES` | `TRACE_RESERVATION_NOTES` | 是 | 是 | Trace 卡,卡内可有普通备注和加床备注多条事项 |
| `ROOMING_LIST` | `ROOMING_LIST` | 是 | 第一版可只读或确认 | 识别到 Rooming List 任务,不在 Agent 回调里保存名单 rows |
| `PAYMENT` | `PAYMENT` | 是 | 第一版主要确认附件关联 | 付款凭证卡,只按 `attachment_ids[]` 引用包级附件 |
说明:
- Basic Information 不是 event但必须是独立任务卡。
- 来源邮件展示卡不是 event普通业务包内只读不参与订单执行阻塞。
- S10/S99 采用来源通知模型:任务列表 / 工作台可见点击进入纯通知详情页只显示邮件展示卡和确认按钮不创建订单、不进订单列表、不参与订单阻塞也不支持编辑、复核、OPERA 或人工终止。
- 同一 `order_ref` 下如果有多个相同 `event_type`,第一版按 event 数组项分别建卡;页面排序按固定卡片顺序,再按 `source_event_index` 排序。
## 6. 状态设计
### 6.1 订单任务状态
订单任务状态用于列表和页面入口,第一版按卡片状态派生,不允许用户直接编辑。为了便于列表查询,`order_task_status` 可以作为落库快照字段保存当前订单任务自身完成情况;同订单前置任务造成的阻塞不落入 `order_task_status`,而是在查询响应的 `availability` 中实时派生。
| 状态 | 中文含义 | 派生规则 |
| --- | --- | --- |
| `OPEN` | 仍有待处理卡 | 存在 `PENDING_CONFIRM``REVIEW_REQUIRED` 的可确认卡 |
| `COMPLETED` | 当前订单任务已完成 | 所有用户可确认卡均已 `CONFIRMED` |
查询响应可以额外返回 `display_status=BLOCKED`表示当前订单任务因同订单前置订单任务未完成、Basic Information 未确认或权限不足而只能查看;该值由查询服务实时计算。
技术错误不派生订单任务状态,因为技术错误不创建订单任务。
### 6.2 卡片状态
| 状态 | 中文含义 | 允许动作 |
| --- | --- | --- |
| `READONLY` | 只读卡 | 只能查看,例如普通业务包的来源邮件展示卡 |
| `PENDING_CONFIRM` | 待确认 | 若没有前置阻塞,允许提交最终确认 |
| `REVIEW_REQUIRED` | 待人工复核 | 若没有前置阻塞,允许提交复核修正并确认 |
| `CONFIRMED` | 已确认锁定 | 只能查看,不允许再次编辑或覆盖 |
| `ACK_REQUIRED` | 通知待确认 | 仅用于 S10/S99 来源通知,落在 `workflow_reservation_v4_source_notification.notification_status` |
| `ACKED` | 通知已确认 | 仅用于 S10/S99 来源通知,落在 `workflow_reservation_v4_source_notification.notification_status` |
### 6.3 可操作性派生
接口响应应返回 `availability` 或等价字段,避免前端自己猜。
| 派生状态 | 中文含义 |
| --- | --- |
| `available=true` | 当前用户在权限、酒店、状态和阻塞规则下可以处理 |
| `blocked=true` | 当前卡只能查看 |
| `readonly_reason_code=PRIOR_CARD_NOT_CONFIRMED` | 同一订单任务内前置卡未确认 |
| `readonly_reason_code=PRIOR_ORDER_TASK_NOT_COMPLETED` | 同一本地订单下更早订单任务未完成 |
| `readonly_reason_code=CARD_LOCKED` | 当前卡已确认锁定 |
| `readonly_reason_code=SOURCE_MESSAGE_DISPLAY_READONLY` | 来源邮件展示卡只读 |
## 7. 确认、复核和锁定规则
### 7.1 不保存草稿
V4 新数据不再提供后端草稿保存。前端可以在页面本地维护未提交表单状态,但后端只接受最终确认或复核解阻提交。
原因:
- 2026-07-18 V4 契约已确认“不保存草稿”。
- V4 当前没有真实 OPERA / PMS 执行,后端不需要为半成品 payload 生成后续操作。
- 可以避免 V3 `draft_payload_json``READY` 和 OPERA 模拟骨架继续扩大。
### 7.2 最终确认
用户确认卡片时,后端保存:
- `confirmed_payload_json`:用户确认后的结构化字段。
- `confirmed_by`:当前登录用户 ID。
- `confirmed_at`UTC 时间点。
- `card_status=CONFIRMED`
确认后永久锁定。若后续发现错误,不覆盖原确认记录,应该通过审计记录和未来纠错流程表达。
### 7.3 人工复核
`manual_review=true` 或目录校验失败时,卡片进入 `REVIEW_REQUIRED`
复核提交后:
- 不改写 AI 原始 payload。
- 用户修正写入 `review_resolution_json``confirmed_payload_json`
- CP8 起确认和复核都会校验目录字段Basic Information 的 `account_code` 必须来自第一版 Account 固定目录,通过后后端派生 `market_code` / `source_code`
- 通过校验后卡片直接进入 `CONFIRMED`,不再进入 V3 `READY` 状态。
- `field_overrides[].field_pointer` 必须是当前卡 `display_payload_json` 中允许编辑的 RFC 6901 JSON Pointer如果当前卡展示 payload 中存在显式 `missing_fields[]`,只允许提交该清单内的 pointer如果没有显式清单第一版只允许 `basic_information.*``business_fields.*` 下已经存在且值为 `null` / 空字符串的未解决叶子字段,或后端 `validation_errors_json` 指向的目录错误字段,不允许替换对象或数组。
- 来源消息、路由、订单定位关系、诊断、缺失字段清单、`manual_review`、raw evidence 等只读字段不得提交。
- 如果订单任务归属未解决,复核请求必须提交 `confirmed_order_id`;后端按当前订单任务酒店校验该订单存在、非逻辑删除且不是系统隐藏订单。
- 如果订单任务已经有 `order_id``target_resolution_status=RESOLVED`,复核请求不能提交不同的 `confirmed_order_id`,否则返回 `V4_ORDER_REBIND_NOT_ALLOWED`;普通任务任意切换订单继续后置。
- `availability.reviewable=true``card_status=REVIEW_REQUIRED` 时,前端可以展示复核提交入口;普通确认接口仍拒绝 `REVIEW_REQUIRED` 卡。
### 7.4 Basic Information 目录规则
第一版 Basic Information 至少包含:
- Agent 原始 `account_code`
- 信息系统目录校验状态。
- 后端派生的 `market_code``source_code` 快照,来源是 Account 目录。
如果 `account_code=null` 或目录不存在:
- 卡片进入 `REVIEW_REQUIRED`
- 用户只能从信息系统已有 Account 目录中选择。
- 后端不得反向篡改 Agent 原始 `basic_information.manual_review`
第一版 Account / Market / Source 目录使用后端固定种子数据,不依赖 SuperAgent 动态提供目录文件。后续如目录由管理后台维护或从外部系统同步,应以专项 checkpoint 设计目录版本、变更审计和回放影响。
CP8 第一版固定种子:
| 目录 | 第一版代码 |
| --- | --- |
| Account | `QBD_TRAVEL``LIAN_TAI``HANATOUR_TD` |
| Market | 由 Account 派生,当前固定为 `LEISURE` |
| Source | 由 Account 派生,当前固定为 `TRAVEL_AGENT` |
| Room Type | `TWN``KING``DBL``SGL``TRP``RM1``RM2``RM3` |
| Rate Code | `BAR``RACK``PACKAGE``GROUP``FIT` |
说明Room Type / Rate Code 当前只作为确认和字段控件的第一版校验 / 选项来源代码;尚未接真实 PMS 房型目录、Rate Code 配置中心或通用 lookup API。
## 8. 订单归属和 target_order
### 8.1 order_ref 和 target_order 分工
| 字段 | 用途 |
| --- | --- |
| `order_ref` | 当前回调包内归组,同一 `order_ref` 形成一个订单任务 |
| `target_order` | 本系统查找或创建本地订单投影,用于后续同订单阻塞和页面关联 |
不得用相同 `target_order=null` 合并订单任务Agent 如果无法判断是否同单,应输出不同 `order_ref`
### 8.2 本地订单绑定规则
| `booking_type` | `locator_type` | 第一版绑定规则 |
| --- | --- | --- |
| `GROUP` | `GROUP_CODE` | 按 `hotel_id + GROUP_CODE` 查找 ACTIVE 本地订单;不存在则创建或挂临时可见订单 |
| `FIT` | `BOOKING_CODE` | 按 `hotel_id + BOOKING_CODE` 查找本地订单投影;不存在则创建临时或 Booking Code 订单;若匹配多条则进入人工复核,不自动选单 |
| `FIT` | `CONFIRMATION_NUMBER` | 按 `hotel_id + CONFIRMATION_NUMBER` 查找 ACTIVE 本地订单;不存在则创建可见订单 |
| 任意 | 任意字段未解决 | 创建可见临时订单,订单任务和相关卡片进入复核或阻塞状态,等待用户确认订单归属 |
`FIT + BOOKING_CODE` 第一版不建立 ACTIVE 唯一约束。`BOOKING_CODE` 是拿到 `CONFIRMATION_NUMBER` 前的临时定位字段,后续不作为 PMS 永久主键;系统只在业务绑定时要求匹配结果至多一条。
### 8.3 复核场景订单归属确认
V4 CP2 只设计复核场景下的订单归属确认,不开放普通任务任意切换订单。
规则:
- 用户只能在 `REVIEW_REQUIRED` 卡片或订单任务归属未解决时确认订单归属。
- 订单归属确认必须写业务审计。
- 若确认到其他订单,原临时订单可在无其它任务引用时逻辑删除。
- 已确认锁定卡片不能通过该接口二次迁移订单。
- CP7 第一版只支持在复核解阻请求中提交 `confirmed_order_id` 完成未解决归属的一次性确认;如果订单任务已解析到某个订单且状态为 `RESOLVED`,只能确认同一订单,不能借复核接口切换到其它订单。
- 如果确认到的订单下存在更早未完成 V4 订单任务,后端拒绝当前复核提交,避免绕过同订单阻塞规则。
## 9. 同订单阻塞规则
V4 当前不做 OPERA / PMS 执行,但仍需要保留同订单处理顺序,避免用户先确认后续邮件导致业务事实倒置。
### 9.1 同一订单任务内
推荐固定顺序:
```text
10 SOURCE_MESSAGE_DISPLAY
20 BASIC_INFORMATION
30 ROOM_INFORMATION
40 TRACE_RESERVATION_NOTES
50 ROOMING_LIST
60 PAYMENT
```
规则:
- `SOURCE_MESSAGE_DISPLAY` 只读,不阻塞。
- `BASIC_INFORMATION` 未确认时,其它业务卡只能查看,不能确认。
- 除 Basic Information 必须先确认外,第一版不强制业务卡之间逐张顺序确认;业务卡可独立确认,但页面仍按固定顺序展示。
- 同类型多张业务卡按 `source_event_index` 排序。
### 9.2 同一本地订单下多个订单任务
如果多个 SourceMessage 或多个回调包绑定到同一本地订单:
- 按来源邮件接收时间、AI batch 接收时间、订单任务创建时间排序。
- 更早订单任务仍有未完成可确认卡时,后续订单任务只能查看。
- 技术错误 transition 不参与阻塞。
- S10/S99 来源通知不参与阻塞,也不被阻塞。
## 10. 数据表设计草案
### 10.1 继续复用的表
| 表 | 复用方式 |
| --- | --- |
| `platform_source_message_inbox` | 继续作为来源消息事实和外部 `source_message_id` 查询入口 |
| `workflow_reservation_ai_batch` | 继续保存一次 SuperAgent 回调包的幂等和批次信息 |
| `workflow_reservation_ai_transition` | 继续保存 event 级原始 payload、route、adapter error 和追踪信息 |
| `workflow_reservation_order` | 继续作为本地订单投影和订单列表数据源,但需要补 V4 所需 `BOOKING_CODE` 或 locator 相关能力 |
| `workflow_reservation_audit_log` | 继续保存卡片确认、复核、订单归属确认等业务审计 |
### 10.2 已新增表:`workflow_reservation_v4_order_task`
一条记录表示一个 `source_message_id + order_ref` 形成的 V4 订单任务。
| 字段 | 中文说明 |
| --- | --- |
| `id` | V4 订单任务 ID |
| `hotel_id` | 酒店 ID |
| `source_message_id` | SourceMessage Inbox 内部 ID |
| `ai_batch_id` | AI 回调批次 ID |
| `order_ref` | V4 包内订单引用 |
| `order_context_index` | `order_contexts[]` 中的一基序号,用于同一 SourceMessage 下稳定排序 |
| `order_id` | 绑定的本地订单投影 ID |
| `target_booking_type` | `GROUP` / `FIT` |
| `target_locator_type` | `GROUP_CODE` / `BOOKING_CODE` / `CONFIRMATION_NUMBER` |
| `target_locator_value` | 目标订单定位值,未解决时为空 |
| `target_resolution_status` | `RESOLVED` / `UNRESOLVED` / `CONFLICT` |
| `order_task_status` | 落库快照,仅保存 `OPEN` / `COMPLETED``BLOCKED` 由查询响应实时派生 |
| `source_received_at` | 来源邮件接收 UTC 时间,用于排序 |
| `version` | 乐观锁版本 |
| `created_at` / `updated_at` | UTC 创建和更新时间 |
| `logic_deleted_at` / `logic_deleted_reason` | 逻辑删除时间和原因CP3 第一版只预留字段Repository 默认排除逻辑删除记录 |
建议唯一约束:
```text
uk_reservation_v4_order_task_source_ref(hotel_id, source_message_id, order_ref)
uk_reservation_v4_order_task_source_index(hotel_id, source_message_id, order_context_index)
```
### 10.3 已新增表:`workflow_reservation_v4_task_card`
一条记录表示 V4 订单任务下的一张卡。
| 字段 | 中文说明 |
| --- | --- |
| `id` | V4 任务卡 ID |
| `hotel_id` | 酒店 ID |
| `v4_order_task_id` | 所属 V4 订单任务 IDS10/S99 来源通知不挂订单任务,后续使用独立通知模型承载 |
| `source_message_id` | 来源消息 ID便于查邮件会话 |
| `ai_transition_id` | 对应 event 的 AI transition IDBasic Information 和来源邮件展示卡可为空 |
| `card_type` | 卡片类型 |
| `event_type` | 对应 V4 event_type非 event 卡为空 |
| `source_event_index` | event 在 `message_events[]` 中的一基序号;非 event 卡固定为 `0`,避免 MySQL 唯一索引因 `NULL` 失效 |
| `card_sort_order` | 页面固定排序值 |
| `card_status` | `READONLY` / `PENDING_CONFIRM` / `REVIEW_REQUIRED` / `CONFIRMED` 等 |
| `review_status` | `PENDING` / `RESOLVED`,仅复核卡使用 |
| `ai_payload_json` | 当前卡使用的 AI 原始片段,不可被用户覆盖 |
| `display_payload_json` | 后端给前端展示的字段快照,可由 AI 和目录派生 |
| `confirmed_payload_json` | 用户最终确认后的字段 |
| `review_resolution_json` | 人工复核修正和订单归属确认结果 |
| `validation_errors_json` | 目录或业务校验错误摘要,不保存敏感正文 |
| `confirmed_by` / `confirmed_at` | 确认人和确认 UTC 时间 |
| `version` | 乐观锁版本 |
| `created_at` / `updated_at` | UTC 创建和更新时间 |
| `logic_deleted_at` / `logic_deleted_reason` | 逻辑删除时间和原因CP3 第一版只预留字段Repository 默认排除逻辑删除记录 |
建议唯一约束:
```text
uk_reservation_v4_task_card_slot(hotel_id, v4_order_task_id, card_sort_order, source_event_index)
```
约束说明:
- `SOURCE_MESSAGE_DISPLAY``BASIC_INFORMATION` 等非 event 卡使用 `source_event_index=0`
- event 业务卡使用一基 `source_event_index`
- 同一个订单任务下,固定卡片顺序 + `source_event_index` 必须唯一,防止入站重试或幂等异常重复创建同一张卡。
### 10.4 已新增表:`workflow_reservation_v4_source_notification`
一条记录表示一个 S10/S99 来源通知。它不挂订单任务、不创建订单、不进入订单列表,只用于任务列表 / 工作台和纯通知详情页。
| 字段 | 中文说明 |
| --- | --- |
| `id` | 来源通知 ID |
| `hotel_id` | 酒店 ID第一版使用系统默认酒店或 SourceMessage 所属酒店 |
| `source_message_id` | SourceMessage Inbox 内部 ID |
| `ai_batch_id` | AI 回调批次 ID |
| `ai_transition_id` | S10/S99 对应 AI transition ID |
| `route_code` | `S10``S99` |
| `notification_status` | `ACK_REQUIRED` / `ACKED` |
| `raw_payload_json` | S10/S99 原始 AI 片段或包级摘要 |
| `ack_by` / `ack_at` | 确认人和确认 UTC 时间 |
| `source_received_at` | 来源邮件接收 UTC 时间,用于任务列表 / 工作台排序 |
| `version` | 乐观锁版本,用于确认按钮并发控制 |
| `created_at` / `updated_at` | UTC 创建和更新时间 |
| `logic_deleted_at` / `logic_deleted_reason` | 逻辑删除时间和原因CP3 第一版只预留字段Repository 默认排除逻辑删除记录 |
建议唯一约束:
```text
uk_reservation_v4_notification_message_batch(hotel_id, source_message_id, ai_batch_id)
```
### 10.5 暂不新增的表
| 表或能力 | 暂不新增原因 |
| --- | --- |
| V4 草稿表 | V4 已确认不保存草稿 |
| V4 OPERA operation 表 | 当前不做真实 OPERA / OHIP也不生成 OPERA 模拟 |
| 技术错误用户任务表 | 技术错误不进入用户任务体系,先用 AI transition 和 dispatch run |
| 目录表 | Account、Market、Source 第一版已确认用后端固定种子数据CP2 只设计边界,后续目录 checkpoint 再决定是否建表、导入或管理后台维护 |
## 11. Entity / Mapper / Repository 边界草案
后续 Java 实现必须遵守当前后端目录规范。
### 11.1 domain
已新增:
- `ReservationV4OrderTaskEntity`:映射 `workflow_reservation_v4_order_task`
- `ReservationV4TaskCardEntity`:映射 `workflow_reservation_v4_task_card`
- `ReservationV4SourceNotificationEntity`:映射 `workflow_reservation_v4_source_notification`
Entity 字段必须有中文注释,说明字段业务含义、来源和状态代码范围。
### 11.2 mapper
已新增:
- `ReservationV4OrderTaskMapper`
- `ReservationV4TaskCardMapper`
- `ReservationV4SourceNotificationMapper`
Mapper 只放 MyBatis-Plus 基础访问和必要语义化查询。自定义方法需要中文注释。
### 11.3 repository
已新增:
- `ReservationV4WorkflowRepository`
- `MybatisReservationV4WorkflowRepository`
- `ReservationV4SourceNotificationRepository`
- `MybatisReservationV4SourceNotificationRepository`
CP3 Repository 已封装:
- 按 SourceMessage + order_ref 幂等创建订单任务。
-`order_context_index` 保留同一 SourceMessage 下多个 `order_contexts[]` 的稳定顺序。
- 创建 Basic Information / SourceMessage / Event 卡的基础插入方法;非 event 卡 `source_event_index` 固定写入 `0`
- 按 SourceMessage + AI batch 幂等创建 S10/S99 来源通知。
- 查询订单任务详情和卡片列表。
- 查询来源通知列表和详情。
- 卡片状态的 version 乐观锁更新基础方法。
- 来源通知状态的 version 乐观锁更新基础方法。
- event 卡必须传入正数一基 `source_event_index`;漏传会拒绝写入,避免被误当成非 event 卡。
CP6 已实现普通卡片确认和 S10/S99 来源通知 ack 的业务 Service 和 APIV4 复核解阻、复核场景订单归属确认仍属于后续 checkpoint。
Service 不直接访问 Mapper。
### 11.4 service
建议新增或拆分:
- `ReservationV4TaskIntakeService`已实现V4 入站从 AI transition 落 V4 订单任务、卡片和 S10/S99 来源通知。
- `ReservationV4OrderTaskQueryService`:前端查询订单任务列表和详情。
- `ReservationV4CommandService`:已实现卡片确认和 S10/S99 来源通知确认;后续继续承接 V4 复核和订单归属确认。
- `ReservationV4SourceNotificationService`:来源通知查询已并入 V4 查询服务,确认已并入 V4 命令服务。
当前 `ReservationAiTaskIntakeServiceImpl` 已在 V4 分支调用 `ReservationV4TaskIntakeService` 完成新模型写入;查询和确认已拆到独立 V4 service后续复核仍应继续留在 V4 命令侧,避免主入站类继续膨胀。
## 12. 前端查询接口
以下查询接口已在 CP5 实现。所有接口都属于 `FRONTEND_USER`,必须带 Bearer token权限码为 `RESERVATION_TASK_READ`,并按酒店访问权校验。查询接口只返回安全摘要、展示 payload、确认 payload、复核结果和状态不返回邮件正文、附件 URL、`ai_payload_json` 或来源通知原始 payload。
V4 前端接口不继续扩展旧 `/api/reservation/tasks/**` 作为 V4 主模型入口。第一版中,工作台统一列表使用 `/api/reservation/workbench-items`,业务订单任务使用 `/api/reservation/order-tasks/**`S10/S99 来源通知详情使用 `/api/reservation/source-notifications/**`
### 12.1 工作台统一列表
```text
GET /api/reservation/workbench-items
分类FRONTEND_USER
权限RESERVATION_TASK_READ
```
用途:
- 作为 V4 任务列表 / 工作台的第一版统一入口。
- 同时返回业务订单任务和 S10/S99 来源通知。
- 前端按 `item_type` 区分跳转目标。
返回摘要应包含:
- `item_type``ORDER_TASK` / `SOURCE_NOTIFICATION`
- `target_id`:订单任务 ID 或来源通知 ID。
- `source_message_summary`
- `display_order_key`S10/S99 来源通知为空。
- `card_counts`S10/S99 来源通知为空或只返回通知状态。
- `next_action_card_id`S10/S99 来源通知为空。
- `notification_status`:仅 S10/S99 来源通知返回 `ACK_REQUIRED` / `ACKED`
- `order_task_status`:仅业务订单任务返回 `OPEN` / `COMPLETED`
- `display_status`:可返回 `OPEN` / `BLOCKED` / `COMPLETED` / `ACK_REQUIRED` / `ACKED`
- `readonly_reason_code`
- `created_at` / `updated_at`:工作台条目创建和更新时间,主要用于同一来源时间下的稳定排序和前端调试。
排序规则:
- 默认按 `source_received_at` 倒序。
- 同一来源时间下按记录 `updated_at``created_at`、数字 ID 倒序。
### 12.2 业务订单任务列表
```text
GET /api/reservation/order-tasks
分类FRONTEND_USER
权限RESERVATION_TASK_READ
```
查询参数:
| 参数 | 中文说明 |
| --- | --- |
| `hotel_id` | 可选,按用户酒店访问权校验 |
| `order_id` | 可选,查询某个本地订单下的订单任务 |
| `card_status` | 可选,筛选含某类待处理卡的订单任务 |
| `keyword` | 可选匹配邮件主题、发件人、Group Code、Booking Code、Confirmation Number |
| `page_num` / `page_size` | 分页 |
筛选说明:
- `order_task_status` 只接受 `OPEN` / `COMPLETED`,非法值返回 `V4_ORDER_TASK_STATUS_INVALID`
- `card_status` 只接受 `READONLY` / `PENDING_CONFIRM` / `REVIEW_REQUIRED` / `CONFIRMED`,非法值返回 `V4_CARD_STATUS_INVALID`
- `card_status` 按业务 / 可处理卡筛选,固定的 `SOURCE_MESSAGE_DISPLAY` 来源邮件只读卡不参与匹配,避免 `READONLY` 把所有普通业务任务都筛出来。
返回摘要应包含:
- `order_task_id`
- `order_ref`
- `order_id`
- `display_order_key`
- `source_message_summary`
- `card_counts`
- `next_action_card_id`
- `order_task_status`
- `display_status`
- `readonly_reason_code`
说明:
- 该接口只返回业务订单任务,不返回 S10/S99 来源通知。
- V4 任务列表 / 工作台页面第一版优先使用 `GET /api/reservation/workbench-items`
### 12.3 订单任务详情
```text
GET /api/reservation/order-tasks/{orderTaskId}
分类FRONTEND_USER
权限RESERVATION_TASK_READ
```
返回结构:
```json
{
"order_task": {},
"bound_order": {},
"source_message_card": {},
"basic_information_card": {},
"business_cards": [],
"adapter_contract_errors": [],
"availability": {}
}
```
前端应以返回的 `cards[]``availability` 为准渲染,不自行拼完整字段矩阵。
`adapter_contract_errors[]` 返回同一 AI 批次中未生成业务卡的 V4 event 级契约错误诊断块,只包含白名单诊断字段,例如 `event_type``source_event_index``contract_errors``reason_code``missing_fields` 等;不返回完整 AI payload、邮件正文、附件 URL 或 raw evidence。
来源邮件摘要必须按当前查询酒店过滤。如果 V4 订单任务因脏引用指向了其它酒店的 SourceMessage详情接口只能返回该 `source_message_id` 的空摘要占位,不得透出对方酒店的主题、外部消息 ID、发件人或会话信息。
### 12.4 S10/S99 来源通知详情
```text
GET /api/reservation/source-notifications/{notificationId}
分类FRONTEND_USER
权限RESERVATION_TASK_READ
```
返回结构:
```json
{
"notification": {},
"source_message_card": {},
"conversation_summary": {},
"availability": {}
}
```
说明:
- 只用于 S10/S99 来源通知详情页。
- 不返回 `order_task``bound_order``basic_information_card``business_cards`
- 邮件正文、附件 URL 和会话原文读取仍按 SourceMessage 权限和原文读取审计规则处理。
### 12.5 订单详情时间线
建议后续扩展CP5 尚未实现:
```text
GET /api/reservation/orders/{orderId}/order-tasks
分类FRONTEND_USER
权限RESERVATION_ORDER_READ
```
用于订单详情页展示 V4 订单任务时间线。旧 `GET /api/reservation/orders/{orderId}` 可以在过渡期继续返回 V3 `tasks[]`
## 13. 前端写操作接口
### 13.1 确认卡片
```text
POST /api/reservation/order-tasks/{orderTaskId}/cards/{cardId}/confirm
分类FRONTEND_USER
权限RESERVATION_TASK_CONFIRM
```
请求要点:
- 请求 JSON 必须携带 `version``confirmed_payload` 可选,未传时后端使用当前展示 payload 作为确认快照。
- 前端只应提交当前卡 `fields[]` 中可编辑字段。后端确认时以当前卡展示快照为基准合并 `confirmed_payload`,未出现在展示快照 / 字段白名单中的字段会被忽略,不会写入 `confirmed_payload_json`
- Basic Information 确认时 `basic_information.account_code` 必须是第一版 Account 目录值;后端确认前会派生 `account_name``market_code``source_code` 写入 `confirmed_payload_json`
- 业务卡确认时,第一版会递归校验已有 `rate_code``room_items[].room_type_code` 是否在固定目录中;`UPDATE_BOOKING` 等嵌套结构会返回类似 `business_fields.after.room_items.0.room_type_code` 的错误路径,失败返回 `V4_FIELD_VALIDATION_FAILED`
- 不提交草稿。
- 必须带 `version` 做并发校验。
- 后端确认后卡片 `CONFIRMED` 并锁定。
- 返回刷新后的 `GET /api/reservation/order-tasks/{orderTaskId}` 详情结构。
- Basic Information 必须先确认;业务卡第一版不强制逐张顺序确认。
- `SOURCE_MESSAGE_DISPLAY``CONFIRMED``REVIEW_REQUIRED` 卡不能通过该接口确认。
### 13.2 复核并确认卡片
```text
POST /api/reservation/order-tasks/{orderTaskId}/cards/{cardId}/review-resolution
分类FRONTEND_USER
权限RESERVATION_MANUAL_REVIEW_RESOLVE
```
请求要点:
- 提交 `field_overrides[]`
- 可提交复核场景订单归属确认。
- 请求 JSON 必须携带卡片 `version`;可选 `reason` 写入业务审计摘要;`confirmed_order_id` 表示复核场景确认后的本地订单 ID。
- 如果订单任务当前 `order_id=null``target_resolution_status!=RESOLVED``confirmed_order_id` 必填;后端会按订单任务所属酒店查询并校验真实可见订单。
- `field_overrides[]` 每项包含 `field_pointer``value``field_pointer` 只允许指向当前卡展示 payload 中的可编辑业务字段,不允许指向 `source_message``route_code``card_type``target_order``order_ref``missing_fields``manual_review``raw_evidence``validation_errors` 等只读诊断字段。
- 第一版允许的写入容器是 `basic_information``business_fields`;如果展示 payload 中存在显式 `missing_fields[]`,只允许提交清单中的 pointer否则只能改已存在且值为 `null` / 空字符串的叶子字段,或后端 `validation_errors_json` 指向的目录错误字段,不能修改其它已有有效值、替换整个对象 / 数组或新增未知字段。
- 复核提交后同样执行目录校验Basic Information 复核成功后会在 `confirmed_payload_json.basic_information` 中写入派生的 `account_name``market_code``source_code`
- 如果订单任务已经有 `order_id``target_resolution_status=RESOLVED``confirmed_order_id` 只能为空或等于当前订单 ID提交其它订单 ID 会返回 `V4_ORDER_REBIND_NOT_ALLOWED`
- Basic Information 必须先确认;如果 Basic Information 自身是 `REVIEW_REQUIRED`,允许通过本接口先复核并确认 Basic。
- 解阻过程不改写 `ai_payload_json`;用户修正写入 `review_resolution_json`,最终确认快照写入 `confirmed_payload_json`
- 校验通过后直接 `CONFIRMED`
- 写业务审计。
- 返回刷新后的 `GET /api/reservation/order-tasks/{orderTaskId}` 详情结构;对应卡片 `review_status=RESOLVED``confirmed_by``confirmed_at` 会返回。
### 13.3 S10/S99 通知确认
```text
POST /api/reservation/source-notifications/{notificationId}/ack
分类FRONTEND_USER
权限RESERVATION_TASK_CONFIRM
```
S10/S99 已确认采用来源通知模型,不继续复用隐藏技术订单或旧 `SOURCE_MESSAGE_ONLY` 任务确认方式。第一版通知详情只显示邮件展示卡和确认按钮,确认动作表示已读 / 已处理。
请求要点:
- 必须带 `version` 做并发校验。
- 仅允许 `route_code=S10/S99` 的来源通知;其它路由即使状态为 `ACK_REQUIRED` 也不能通过该接口确认。
- 确认后 `notification_status=ACKED`,写确认人和 UTC 确认时间。
- 重复提交已确认通知按幂等成功返回当前已确认状态,不新增审计,不允许回退到 `ACK_REQUIRED`
- 返回刷新后的 `GET /api/reservation/source-notifications/{notificationId}` 详情结构。
## 14. 旧 V3 / V2 兼容和废弃边界
开发阶段已确认可以清空数据,因此后续 V4 开发可以不迁移历史任务数据。
### 14.1 可继续保留
- `workflow_reservation_ai_batch`
- `workflow_reservation_ai_transition`
- `workflow_reservation_order`
- `workflow_reservation_audit_log`
- SuperAgent V3 / V2 入站兼容代码,直到正式切换前
### 14.2 V4 新数据不再使用
- `workflow_reservation_task_card.draft_payload_json`
- V3 `READY` 作为确认后等待 OPERA 的状态语义
- V3 OPERA 模拟自动生成
- V2 `ai_task_results[]` 字段矩阵作为新 V4 页面主模型
-`S000/S999` 作为新入站格式
- Fallback 转 New / Update / Cancel 作为 V4 主入口
### 14.3 可以后续专项废弃
- V2 `text/plain S000/S999` 兼容入口。
-`ai_task_results[]` 入站入口。
- V3 40 路由中不再被 V4 使用的历史 subtype。
- `workflow_reservation_task` 作为 V4 多卡主模型的直接承载方式。
- 旧 V2/V3 任务详情、草稿保存和最终确认接口,待 V4 新模型落地并完成前端切换后逐步废弃。
废弃前必须先确认前端、MCP、SuperAgent 联调方和测试 fixture 都已切到 V4。
## 15. 安全、权限和审计
后续实现接口时必须同步更新 `security-access-control-boundary.md`
第一版建议:
| 能力 | 分类 | 权限码 | 审计 |
| --- | --- | --- | --- |
| 查询工作台、订单任务列表 / 详情、来源通知详情 | `FRONTEND_USER` | `RESERVATION_TASK_READ` | 只读默认不写业务审计 |
| 确认卡片 | `FRONTEND_USER` | `RESERVATION_TASK_CONFIRM` | 写业务审计 |
| 复核解阻 | `FRONTEND_USER` | `RESERVATION_MANUAL_REVIEW_RESOLVE` | 写业务审计 |
| 确认 S10/S99 来源通知 | `FRONTEND_USER` | `RESERVATION_TASK_CONFIRM` | 写业务审计 |
| 读取邮件正文 / 附件 | `FRONTEND_USER` | `SOURCE_MESSAGE_READ` + `SOURCE_MESSAGE_ORIGINAL_READ` | 写原文读取审计 |
| SuperAgent V4 回调 | `THIRD_PARTY_SUPERAGENT` | HMAC 机器鉴权 | 写 AI batch / transition |
AI 原始 payload、邮件正文、附件 URL 和技术 trace 不应直接进入普通列表接口。
## 16. 后续开发 checkpoint
| Checkpoint | 目标 | 主要交付 |
| --- | --- | --- |
| M002-V4-CP3 | V4 表结构和基础 Repository | 新增 V4 order task / card / source notification 表、Entity、Mapper、Repository、测试 |
| M002-V4-CP4 | V4 入站落新模型 | 已完成SuperAgent V4 回调创建订单任务、Basic Information 卡、业务卡、邮件展示卡和 S10/S99 来源通知 |
| M002-V4-CP5 | V4 查询接口 | 已完成:工作台统一列表、订单任务列表、订单任务详情和来源通知详情查询接口;订单详情 V4 专属时间线后续再做 |
| M002-V4-CP6 | V4 卡片确认和 S10/S99 ack | 已完成不保存草稿支持普通卡片确认、确认后锁定、Basic Information 前置约束、同订单前置任务写侧阻塞、业务审计、version 并发校验和 S10/S99 来源通知确认 |
| M002-V4-CP7 | V4 复核解阻与订单归属确认 | 已完成:支持 `REVIEW_REQUIRED` 卡字段修正、复核说明、复核场景订单归属确认、version 并发校验、直接 `CONFIRMED`、审计和 availability.reviewable |
| M002-V4-CP8 | 受控目录第一版 | 已完成第一版Account 固定目录校验、Market / Source 派生、RoomType / RateCode 固定种子校验、V4 任务卡 `fields[]` 字段白名单 |
| M002-V4-CP9 | V4 前端契约收口 | 字段、控件、availability、错误展示和旧任务入口切换 |
| M002-V4-CP10 | 旧 V3 / V2 能力收口评估 | 明确哪些兼容入口可以关闭,哪些仍保留只读历史 |
## 17. 已确认设计决策
1. V4 前端接口不继续扩展旧 `/api/reservation/tasks/**`;工作台统一列表新开 `/api/reservation/workbench-items`,业务订单任务新开 `/api/reservation/order-tasks/**`S10/S99 来源通知使用 `/api/reservation/source-notifications/**`
2. `FIT + BOOKING_CODE` 第一版不建立 ACTIVE 唯一约束;业务绑定时要求匹配结果至多一条,匹配多条进入人工复核。
3. `BOOKING_CODE` 只是拿到 `CONFIRMATION_NUMBER` 前的临时定位字段,后续不作为 PMS 永久主键。
4. S10/S99 采用来源通知模型:任务列表 / 工作台展示,不挂隐藏技术订单;通知详情只显示邮件展示卡和确认按钮。
5. S10/S99 不创建订单、不进订单列表、不参与订单阻塞也不支持编辑、复核、OPERA 或人工终止。
6. 第一版不强制所有业务卡逐张顺序确认,但 Basic Information 必须先确认。
7. Basic Information 的 Account / Market / Source 目录第一版使用后端固定种子数据。
8. 普通业务邮件的来源邮件展示卡只读展示,不需要用户确认;用户只确认 Basic Information 和具体业务卡。
9. S10/S99 因为没有业务卡,邮件展示卡需要确认按钮,用来记录已读 / 已处理。
10. V4 新模型落地并完成前端切换后,旧 V2/V3 任务详情、草稿保存和最终确认接口可以逐步废弃。