Files
th-hotel-simple/docs/project/requirements/M002-backend-data-model-design.md
2026-07-12 01:27:42 +08:00

20 KiB
Raw Blame History

M002 Backend Data Model Design 后端数据模型设计

文档信息

项目 内容
文档版本 0.2
日期 2026-07-11
状态 V2 后端数据模型与阶段实现记录V3 新开发和当前实现状态以 M002-order-task-workflow-v3.md 为准
适用范围 AI 过渡层、订单、任务、任务卡、审计和 OPERA 模拟结果
主要读者 后端、数据库、测试、后续协作 agent

1. 文档定位

本文定义 M002 第一阶段后端数据模型草案,用于支撑 SuperAgent 任务结果入站、订单挂靠、任务卡确认、队列顺序、审计和 OPERA 模拟结果。

本文不是完整最终模型。当前后端已经按本模型落地第一阶段 Flyway migration、Entity、Mapper、Repository、Service 和测试;后续真实 OPERA、前端页面和 SuperAgent 查询上下文接口仍需继续补充。

2026-07-11 后M002 V3 已确认采用 0711 P0 冻结基线。后续数据模型扩展必须支持结构化 S10/S99message_events[]、42 路由、方案 C 中的 AI 原始三元组 / 系统处理分类分离、type-known manual review 同卡解阻和 adapter_contract_error,不能只沿用本文的 ai_task_results[] 阶段模型。

2. 设计原则

  • 保留 AI 原始 JSON不覆盖、不重写、不丢字段。
  • 用户确认后的数据写入 confirmed_payload_jsonOPERA 模拟只读取确认后的 payload。
  • 高频查询、幂等、排序和状态机字段冗余为物理列。
  • 任务卡字段第一版先写在代码里,但必须通过低耦合 Provider 封装,后续可迁移为数据库配置。
  • BLOCKED 不作为任务持久状态,而是根据同订单前置任务是否完成实时计算。
  • 用户不允许强制完成任务。
  • 用户不能跳过失败的 OPERA 模拟操作。
  • 同订单队列可处理状态实时计算时,FAILEDCOMPLETED 都视为前置任务已结束,不阻塞后续任务。
  • OPERA 当前是模拟结构,后续真实系统接入时通过 adapter 映射,不污染核心任务模型。

3. 枚举

3.1 订单状态

状态 中文说明
TEMPORARY 临时订单,用于 New Booking 未取得业务号、Fallback、Message Notification 或暂无法匹配订单的任务容器
ACTIVE 有效订单,可承载可处理业务任务
ENDED 已结束订单,例如已完成、已取消或业务生命周期结束;仍可查看历史
LOGIC_DELETED 逻辑删除订单,主要用于临时订单迁移后废弃,不再承载新任务

3.2 任务状态

状态 中文说明
PENDING_CONFIRM 待用户确认订单归属和任务字段
READY 已确认,等待执行 OPERA 模拟
EXECUTING 正在执行 OPERA 模拟
FAILED 任务级失败结束态;第一版 OPERA 单条模拟操作失败时不直接把任务改为该状态,避免按队列规则误放行
COMPLETED 任务已完成

说明:

  • Message Notification 不参与执行队列,可在创建后直接进入 COMPLETED 或保持只读完成态。
  • manual_review / Fallback 默认进入 PENDING_CONFIRM,等待人工转换或处理。
  • 阻塞态通过查询同订单前置任务实时计算,不落 BLOCKED 状态。

3.3 系统主任务类型

类型 中文说明
NEW_BOOKING 新建订单任务
UPDATE_BOOKING 更新订单任务,下面包含多种任务卡
CANCEL_BOOKING 取消订单任务
MANUAL_REVIEW 人工复核 / Fallback 任务
INFORMATIONAL_MESSAGE 只读信息提醒任务,不参与执行队列

3.4 任务卡类型

第一版建议包含:

  • NEW_BOOKING
  • UPDATE_BOOKING
  • CANCEL_BOOKING
  • VOUCHER_RECEIVED
  • ROOMING_LIST
  • AMEND_GROUP_CODE
  • TRACE_RESERVATION_NOTES
  • TA_RECORDER
  • MESSAGE_NOTIFICATION
  • FALLBACK_REVIEW

4. 表设计总览

表名 中文说明
workflow_reservation_ai_batch AI 任务结果接收批次表
workflow_reservation_ai_transition AI 任务结果过渡表,一条 AI item 一行
workflow_reservation_order 订单表
workflow_reservation_task 任务表
workflow_reservation_task_card 任务卡确认数据表
workflow_reservation_audit_log 订单任务审计表
workflow_reservation_opera_operation OPERA 模拟逻辑操作表
workflow_reservation_opera_operation_attempt OPERA 模拟操作尝试记录表

表名前缀使用 workflow_reservation,表示当前属于 reservation 工作流,不放入平台中立 platform 模块。

5. AI 接收批次表

表名:workflow_reservation_ai_batch

字段 类型建议 中文说明
id BIGINT 批次 ID
hotel_id VARCHAR(64) 酒店或业务上下文
source_message_id BIGINT 关联 SourceMessage
request_payload_sha256 CHAR(64) 原始请求体 SHA-256
batch_idempotency_key CHAR(64) 系统生成的批次幂等键
client_id VARCHAR(128) SuperAgent 调用方 ID
request_id VARCHAR(128) 调用方请求 ID可为空
received_at DATETIME(6) AI 结果请求接收时间,按 UTC 理解
item_count INT AI item 数量
extraction_warnings_json LONGTEXT 抽取警告 JSON
created_at / updated_at DATETIME(6) 创建和更新时间

索引建议:

  • 唯一索引:hotel_id + batch_idempotency_key
  • 普通索引:hotel_id + source_message_id
  • 普通索引:hotel_id + received_at

6. AI 过渡表

表名:workflow_reservation_ai_transition

V2 一条 ai_task_results[] item 对应一行。M002 V3 后,message_events[]S10/S99 入口通知、unhandled_current_intents[] 和 adapter 契约错误也统一以 transition 方式追溯保存。

字段 类型建议 中文说明
id BIGINT AI 过渡记录 ID
hotel_id VARCHAR(64) 酒店或业务上下文
batch_id BIGINT 接收批次 ID
source_message_id BIGINT 来源消息 ID
source_event_index INT AI current 事件序号
array_index INT AI 返回列表中的顺序,建议从 1 开始
execution_order INT 映射到订单任务队列的初始顺序
catalog_code VARCHAR(32) Skill 目录代码
skill_id VARCHAR(128) Skill 标识
result_type VARCHAR(64) AI 结果类型,例如 normal_taskmanual_reviewsource_message_review_notificationadapter_contract_error
ai_task_type VARCHAR(64) AI 原始任务类型
route_code VARCHAR(64) M002 V3 派生路由码S10/S99 使用外部 route_code业务事件使用系统稳定路由码
system_process_category VARCHAR(64) 系统处理分类:BUSINESS_TASKSOURCE_MESSAGE_NOTIFICATIONUNHANDLED_CURRENT_INTENTADAPTER_CONTRACT_ERROR
system_task_type VARCHAR(64) 系统主任务类型
task_card_type VARCHAR(64) 任务卡类型
task_subtype VARCHAR(128) 业务动作 subtype
current_or_history VARCHAR(32) 当前或历史标识
group_code VARCHAR(128) Group Code 候选
confirmation_number VARCHAR(128) Confirmation Number 候选
item_payload_sha256 CHAR(64) 单个 item JSON 哈希
item_idempotency_key CHAR(64) 系统生成 item 幂等键
manual_reason_code VARCHAR(128) 人工复核原因码
parent_source_event_index INT 父任务事件序号
linked_task_group_id VARCHAR(128) 联动任务组 ID
blocked_until_parent_completed TINYINT(1) 是否等待父任务完成
ai_payload_json LONGTEXT AI 原始 item JSON
case_keys_json LONGTEXT 订单候选键 JSON
extracted_fields_json LONGTEXT AI 业务字段 JSON
manual_review_json LONGTEXT 人工复核 JSON
informational_message_json LONGTEXT 信息提醒 JSON
attachments_json LONGTEXT 附件 JSON
context_used_json LONGTEXT 上下文 JSON
adapter_error_code VARCHAR(128) Adapter 契约错误代码,仅在当前 event 不建业务任务时保存
adapter_error_message VARCHAR(512) Adapter 契约错误说明,仅保存安全摘要
created_at / updated_at DATETIME(6) 创建和更新时间

索引建议:

  • 唯一索引:hotel_id + item_idempotency_key
  • 普通索引:hotel_id + source_message_id + source_event_index
  • 普通索引:hotel_id + result_type + ai_task_type
  • 普通索引:hotel_id + route_code
  • 普通索引:hotel_id + system_process_category
  • 普通索引:hotel_id + group_code
  • 普通索引:hotel_id + confirmation_number

7. 订单表

表名:workflow_reservation_order

字段 类型建议 中文说明
id BIGINT 系统内部订单 ID
hotel_id VARCHAR(64) 酒店或业务上下文
order_key_type VARCHAR(32) 业务号类型:GROUP_CODECONFIRMATION_NUMBERTEMPORARY
order_business_key VARCHAR(128) 真实业务号
active_business_key VARCHAR(128) ACTIVE 订单唯一约束辅助键ACTIVE 业务订单时等于真实业务号,其他状态为空
temporary_order_code VARCHAR(128) 临时订单展示编号
order_status VARCHAR(32) 订单状态
business_key_source VARCHAR(64) 业务号来源,例如 AI_CANDIDATEUSER_CONFIRMEDOPERA_SIMULATION_RESULT
business_key_backfilled_at DATETIME(6) New Booking 成功后回填真实业务号的 UTC 时间
display_name VARCHAR(256) 前端展示名称
source_message_id BIGINT 首次创建该订单的来源消息
created_from_task_id BIGINT 首次创建该订单的任务 ID可为空
ended_at DATETIME(6) 订单进入 ENDED 的时间
logic_deleted_at DATETIME(6) 逻辑删除时间
logic_deleted_reason VARCHAR(512) 逻辑删除原因
version BIGINT 乐观锁版本
created_at / updated_at DATETIME(6) 创建和更新时间

索引建议:

  • 普通索引:hotel_id + order_status + updated_at
  • 普通索引:hotel_id + order_key_type + order_business_key
  • 唯一索引:hotel_id + order_key_type + active_business_key,用于保证同一 hotel_id + GROUP_CODE / hotel_id + CONFIRMATION_NUMBER 只能有一个 ACTIVE 订单
  • 唯一索引:hotel_id + temporary_order_code

说明:

  • MySQL 第一版不依赖部分唯一索引;通过 active_business_key 在 ACTIVE 业务订单时写入真实业务号、非 ACTIVE 或临时订单为空,配合唯一索引保证同一业务号只能有一个 ACTIVE 订单。
  • LOGIC_DELETED 订单不得再挂新任务。

8. 任务表

表名:workflow_reservation_task

字段 类型建议 中文说明
id BIGINT 系统任务 ID
hotel_id VARCHAR(64) 酒店或业务上下文
order_id BIGINT 当前挂靠订单 ID
source_message_id BIGINT 来源消息 ID
ai_transition_id BIGINT AI 过渡记录 ID
result_type VARCHAR(32) AI 结果类型
ai_task_type VARCHAR(64) AI 原始任务类型
system_task_type VARCHAR(64) 系统主任务类型
task_card_type VARCHAR(64) 任务卡类型
task_subtype VARCHAR(128) 业务动作 subtype
task_status VARCHAR(32) 任务状态
queue_participation TINYINT(1) 是否参与订单执行队列
execution_order INT 同订单执行顺序
parent_task_id BIGINT 父任务 ID可为空
parent_source_event_index INT 父任务 source event index
linked_task_group_id VARCHAR(128) 联动任务组 ID
blocked_until_parent_completed TINYINT(1) 是否等待父任务完成
last_failure_reason VARCHAR(512) 最近失败原因摘要
confirmed_at DATETIME(6) 用户确认时间
completed_at DATETIME(6) 完成时间
version BIGINT 乐观锁版本
created_at / updated_at DATETIME(6) 创建和更新时间

索引建议:

  • 普通索引:hotel_id + order_id + queue_participation + execution_order
  • 唯一索引:hotel_id + order_id + queue_participation + execution_order,用于防止并发创建任务时出现相同队列序号
  • 普通索引:hotel_id + task_status + updated_at
  • 普通索引:hotel_id + source_message_id
  • 普通索引:hotel_id + ai_transition_id

队列规则:

  • queue_participation=false 的任务不阻塞队列,适用于 Message Notification
  • 是否可编辑、可确认、可执行由服务层实时计算。
  • 当前任务前面存在未完成且参与队列的任务时,本任务只能查看。

9. 任务卡确认数据表

表名:workflow_reservation_task_card

字段 类型建议 中文说明
id BIGINT 任务卡 ID
hotel_id VARCHAR(64) 酒店或业务上下文
task_id BIGINT 所属任务
task_card_type VARCHAR(64) 任务卡类型
field_contract_version VARCHAR(64) 字段契约版本,当前 P0 字段矩阵写 20260711-p0
ai_payload_json LONGTEXT 任务卡使用的 AI 原始 JSON 快照
draft_payload_json LONGTEXT 用户编辑草稿,可为空
confirmed_payload_json LONGTEXT 用户确认后的最终 payload
confirmed_by VARCHAR(128) 确认人
confirmed_at DATETIME(6) 确认时间
created_at / updated_at DATETIME(6) 创建和更新时间

索引建议:

  • 唯一索引:hotel_id + task_id
  • 普通索引:hotel_id + task_card_type

说明:

  • 第一版任务卡字段配置写在代码中,但通过 TaskCardFieldDefinitionProvider 之类的接口提供,避免 Controller / Service 直接依赖硬编码数组。
  • 后续如果改为数据库配置,只替换 Provider 实现,不改任务核心流程。
  • 字段契约从 code-v1 迁移到 20260711-p0 时,不能盲目改写已经存在用户草稿或确认结果的历史任务卡。当前 V18 仅更新 draft_payload_json IS NULLconfirmed_payload_json IS NULL 的旧任务卡;已存在 payload 的历史数据继续保留原 field_contract_version,待重新保存、最终确认或后续专项 backfill 时再迁移。

10. 审计表

表名:workflow_reservation_audit_log

字段 类型建议 中文说明
id BIGINT 审计 ID
hotel_id VARCHAR(64) 酒店或业务上下文
order_id BIGINT 订单 ID可为空
task_id BIGINT 任务 ID可为空
operation_id BIGINT OPERA 模拟操作 ID可为空
actor_type VARCHAR(32) 操作人类型,例如 SYSTEMUSERSUPERAGENT
actor_id VARCHAR(128) 操作人标识
action VARCHAR(128) 操作类型
reason VARCHAR(512) 操作原因
before_snapshot_json LONGTEXT 变更前摘要 JSON
after_snapshot_json LONGTEXT 变更后摘要 JSON
occurred_at DATETIME(6) 发生时间
created_at DATETIME(6) 记录创建时间

索引建议:

  • 普通索引:hotel_id + order_id + occurred_at
  • 普通索引:hotel_id + task_id + occurred_at
  • 普通索引:hotel_id + action + occurred_at

审计不得保存 Secret、Token、完整邮件正文、真实附件 URL 或不必要的个人敏感信息。

11. OPERA 模拟逻辑操作表

表名:workflow_reservation_opera_operation

一条任务可能生成多条 OPERA 模拟逻辑操作。

字段 类型建议 中文说明
id BIGINT OPERA 模拟操作 ID
hotel_id VARCHAR(64) 酒店或业务上下文
order_id BIGINT 订单 ID
task_id BIGINT 任务 ID
operation_sequence INT 同任务下操作顺序,从 1 开始
operation_code VARCHAR(64) 模拟操作代码,第一版固定 SIMULATE_PRECHECKSIMULATE_WRITE
operation_name VARCHAR(128) 模拟操作展示名称
operation_status VARCHAR(32) 操作状态:PENDINGSUCCEEDEDFAILED
request_payload_json LONGTEXT 生成该操作时使用的模拟请求摘要,不保存完整邮件原文
attempt_count INT 已执行 attempt 次数
last_attempt_id BIGINT 最近一次 attempt ID
last_error_message VARCHAR(512) 最近一次失败原因摘要
created_at / updated_at DATETIME(6) 创建和更新时间

索引建议:

  • 唯一索引:hotel_id + task_id + operation_sequence
  • 普通索引:hotel_id + task_id + operation_status
  • 普通索引:hotel_id + order_id + operation_sequence

12. OPERA 模拟尝试记录表

表名:workflow_reservation_opera_operation_attempt

每次执行或重试都新增一条 attempt不能覆盖历史。

字段 类型建议 中文说明
id BIGINT 尝试记录 ID
hotel_id VARCHAR(64) 酒店或业务上下文
order_id BIGINT 订单 ID
task_id BIGINT 所属任务
operation_id BIGINT 所属逻辑操作
attempt_number INT 第几次尝试,从 1 开始
attempt_status VARCHAR(32) 尝试状态:SUCCEEDEDFAILED
request_payload_json LONGTEXT 本次模拟请求 payload
response_payload_json LONGTEXT 本次模拟响应 payload
error_message VARCHAR(512) 失败原因摘要
started_at DATETIME(6) 开始时间
finished_at DATETIME(6) 结束时间
created_at DATETIME(6) 记录创建时间

索引建议:

  • 唯一索引:hotel_id + operation_id + attempt_number
  • 普通索引:hotel_id + task_id + created_at
  • 普通索引:hotel_id + operation_id + attempt_number

规则:

  • 用户不能跳过失败的 OPERA 模拟操作。
  • 失败后操作进入 FAILED,任务保持未完成;因为队列规则里任务 FAILED 视为已结束,第一版不能把 OPERA 操作失败直接落成任务 FAILED,避免后续任务被错误放行。
  • 不允许用户强制把失败任务改成 COMPLETED
  • 后续真实 OPERA 接入时,应通过 adapter 把真实响应映射到 response_payload_json,业务号候选字段需在拿到真实结构后再补稳定字段或 JSON 结构。

13. 订单业务号回填

只有 NEW_BOOKINGconfirmed_payload_json 没有可用业务号时,才需要从 OPERA 成功结果回填订单业务号。

当前第一版后端不做业务号回填,也没有落地 business_key_candidates_json 字段。后续拿到真实 OPERA 返回结构后,再通过低耦合 adapter 解析候选业务号并补充稳定字段或 JSON 结构。候选结构可以参考:

{
  "key_type": "CONFIRMATION_NUMBER",
  "business_key": "CNF123456",
  "source": "OPERA_SIMULATION_RESULT",
  "raw_path": "reserved.for.future.real.opera.path"
}

说明:

  • 当前没有真实 OPERA 返回样例,raw_path 只能预留。
  • FIT Reservation 回填 CONFIRMATION_NUMBER
  • Group / Block / Allotment 回填 GROUP_CODE 或后续确认的对应业务号类型。

14. 第一版不落库的内容

以下内容第一版不建议单独建表:

  • 任务卡字段矩阵配置:先写在代码 Provider 中。
  • 任务阻塞状态:实时计算,不落 BLOCKED
  • OPERA 真实接口字段映射:后续真实系统接入后在 adapter 层补充。
  • 全量 Excel 字段路径:后端引用 docs/import/20260706/任务卡展示编辑矩阵.xlsx 作为完整规则来源,不手抄成数据库。
  • 前端展示 / 编辑白名单V2 阶段前端引用 docs/import/20260708/任务卡前端展示字段表 3.0.xlsxV3 起以 2026-07-11 P0 冻结基线中的前端 Excel 和路由说明为准。前端白名单不作为后端校验和 OPERA 映射的替代来源。

15. 待确认问题

  • ENDED 是否仅表示取消完成,还是也包含正常完成后的历史订单。
  • 临时订单逻辑删除前是否需要保留空订单一段时间。
  • OPERA 真实响应字段出现后,是否需要新增稳定字段而不是只放 JSON。
  • 任务卡字段代码 Provider 的具体类名和包路径,后续实现时按项目规范确认。