From c826b6e5745033e8a8b87bd74d1b62fcbeb842ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=B2=A8=E9=B1=BC=E8=BE=A3=E6=A4=92?= Date: Sat, 8 Aug 2026 16:03:35 +0800 Subject: [PATCH] docs(booking): freeze v0.4 contracts and verification path --- .gitea/workflows/verify.yml | 71 ++++++++ CONTEXT.md | 8 +- PROJECT_STATE.md | 36 ++-- README.md | 16 ++ docs/project/README.md | 15 +- docs/project/ai-nses-project-overlay.md | 2 +- .../requirements/booking-agent-profile-v1.md | 54 ++++++ .../booking-email-architecture-v0.4.md | 121 +++++++++++++ ...mail-br00-contract-acceptance-matrix-v1.md | 53 ++++++ .../booking-email-contracts-v1.md | 168 ++++++++++++++++++ 10 files changed, 526 insertions(+), 18 deletions(-) create mode 100644 .gitea/workflows/verify.yml create mode 100644 docs/project/requirements/booking-agent-profile-v1.md create mode 100644 docs/project/requirements/booking-email-architecture-v0.4.md create mode 100644 docs/project/requirements/booking-email-br00-contract-acceptance-matrix-v1.md create mode 100644 docs/project/requirements/booking-email-contracts-v1.md diff --git a/.gitea/workflows/verify.yml b/.gitea/workflows/verify.yml new file mode 100644 index 0000000..9360ccb --- /dev/null +++ b/.gitea/workflows/verify.yml @@ -0,0 +1,71 @@ +name: verify + +on: + push: + pull_request: + +jobs: + booking-verify: + runs-on: ubuntu-latest + services: + postgres: + image: postgres:16-alpine + env: + POSTGRES_DB: booking_ci + POSTGRES_USER: booking_ci + POSTGRES_PASSWORD: booking_ci + ports: + - 5432:5432 + options: >- + --health-cmd "pg_isready -U booking_ci -d booking_ci" + --health-interval 5s + --health-timeout 5s + --health-retries 20 + steps: + - uses: actions/checkout@v4 + + - name: Set up JDK 17 + uses: actions/setup-java@v4 + with: + distribution: temurin + java-version: '17' + cache: maven + + - name: Set up Node 24 + uses: actions/setup-node@v4 + with: + node-version: '24.14.0' + cache: pnpm + cache-dependency-path: client/pnpm-lock.yaml + + - name: Enable pinned pnpm + run: | + corepack enable + corepack install + + - name: Backend verify + working-directory: server + run: ./mvnw -B verify + + - name: Frontend install and quality gates + working-directory: client + run: | + pnpm install --frozen-lockfile + pnpm typecheck + pnpm lint + pnpm test + pnpm build + pnpm audit --prod + + - name: Source secret scan + run: bash scripts/verify-no-secrets.sh + + - name: Install PostgreSQL client + run: | + sudo apt-get update + sudo apt-get install --yes postgresql-client + + - name: Verify Booking PostgreSQL migration boundary + env: + BOOKING_PG_VERIFY_URL: postgresql://booking_ci:booking_ci@localhost:5432/booking_ci + run: bash scripts/verify-booking-postgresql-migration.sh diff --git a/CONTEXT.md b/CONTEXT.md index 2a21dfe..ed16ee0 100644 --- a/CONTEXT.md +++ b/CONTEXT.md @@ -36,7 +36,7 @@ TH Hotel Simple 是一个前后端分离的酒店业务协同项目。 - PrimeVue 4、PrimeIcons 7。 - Vue Router 5、Vue I18n 11。 - Vitest 4、ESLint 10、vue-tsc 3。 -- Node.js >= 22.13.0。 +- Node.js 24.x 与 pnpm 11.x(项目文件 `client/.node-version`、`client/package.json` 固定验证基线)。 ## 4. 当前业务领域 @@ -44,7 +44,8 @@ TH Hotel Simple 是一个前后端分离的酒店业务协同项目。 - Email / Message Conversation:邮件和邮件会话,用于历史邮件查询、正文读取和会话级任务查询。 - Reservation Case / Task:预订相关订单、任务卡、人工复核和任务结果。 - Reservation Order Task / Card:M002 V4 后续采用的订单任务与多卡模型;一封来源邮件可按 `order_ref` 形成多个订单任务,每个订单任务下包含来源邮件展示卡、Basic Information 卡和若干业务卡。 -- Room Information Card:V4 订单任务中由 New Booking、Update Booking 或 Cancel Booking 触发的房型信息卡;它展示订单房型、日期、早餐、晚数和 Group 状态等可确认业务信息。 +- Booking Email Intake:M012 普通员工预订邮件入口;可上传 `.eml`,按版本化 Catalog 和固定渠道严格底色 Parser 形成 V4 订单任务/来源通知,随后由用户复核和确认。手工导入无确定事实时当前生成 S10/S99,不在请求内自动调用外部 Agent。 +- Room Information Card:V4 可定位订单任务的房型与日期区块;New / Update / Cancel 直接生成生命周期 Room,只有 Trace / Rooming List / Payment 的订单任务补一张共享 current-only companion Room,因此六类订单事件均具备 Basic + Room。 - Review Required Card:V4 订单任务中需要人工复核的原业务卡状态;用户仍在原卡片内检查和修正业务字段,完成后确认卡片,不另建独立复核任务卡。 - Reservation Account:预订业务中的公司、旅行社或客户账户,不是系统登录账号;它用于订单级 Basic Information,并派生 Market / Source。 - Room Type Catalog:预订业务可选房型代码目录;第一阶段已确认稳定业务集合为 `RM2`、`RM3`、`RM4`、`SU1`、`SU2`、`SU3`,暂不按 Account 限制可用房型。 @@ -66,6 +67,7 @@ TH Hotel Simple 是一个前后端分离的酒店业务协同项目。 | SuperAgent MCP | SuperAgent 调用本项目能力的 MCP 映射,当前内嵌在后端服务。 | `docs/project/integrations/superagent-mcp/README.md` | | Aliyun OSS | 调试 EML、附件或生成文件的对象存储。 | 相关配置和安全边界见项目文档与后端配置 | | OHIP / PMS | 后续酒店系统集成方向。当前不允许前端直接访问。 | 后续 Spec / ADR 明确 | +| PostgreSQL 测试目标模型 | M012 已在测试库隔离创建 `th_hotel_booking`;当前 Spring 运行时仍保持 MySQL/H2,PostgreSQL 方言接入另行设计。 | `database/postgresql/README.md` | ## 6. 当前开发方向 @@ -80,6 +82,8 @@ TH Hotel Simple 是一个前后端分离的酒店业务协同项目。 业务开发仍以 `docs/project/requirements/` 和 `docs/project/integrations/` 下的当前有效文档为准。 +预订邮件识别到人工确认的当前基线见 `docs/project/requirements/M012-booking-email-confirmation-e2e-v01.md`;确认后的 PMS/Opera 执行不在该版本范围。 + 新增重要 V4 需求时,应先按项目级 Overlay 形成或更新模板化 Spec / Change Request,再安排后端、前端或测试 agent 开工;现有 M002 V4 大文档继续作为字段、接口、安全和实现契约。 ## 7. 新 Agent 阅读顺序 diff --git a/PROJECT_STATE.md b/PROJECT_STATE.md index 69c9ee1..b57de36 100644 --- a/PROJECT_STATE.md +++ b/PROJECT_STATE.md @@ -2,18 +2,32 @@ | 项 | 内容 | | --- | --- | -| 最近更新 | 2026-07-24 | -| 当前分支 | `feature/huangting` | -| 当前阶段 | M002 V4 入站、多卡模型、持久化基线、入站写入、查询接口、卡片确认、复核解阻、目录校验、订单详情 V4 总览、DB 目录、Lookup API、前端 lookup 接入、目录管理后台 CP1 前后端、订单列表 V4 继续处理入口 / open count 收口、V4 业务审计查询、停止旧任务双写、Debug EML V4 profile 对齐、Room Information 后端展示模型与前端业务化展示、V4 任务详情 smoke 修复、Rooming List 确认自动 DEF 后端联动、Rooming List 前端轻量事项卡、Room Information 复核 pointer 与任务详情安全边界修复、Room Information 复核 pointer 运行时规则收口、复核 pointer 部署证明与运行时 trace、OWNER RATE Room Type / Rate Code 目录口径、Payment 附件预览后端安全摘要与前端预览接入、Trace 卡后端字段契约收口、Trace 确认态字段刷新、Rooming List 事项确认卡文档口径、V4 复核态卡片交互和字段白名单文档口径、V4 工作台 / 订单详情 / 任务详情普通酒店员工用户化展示与 polish 收口、订单事项办理页克制业务办理台视觉 polish、SuperAgent MCP 入站诊断链路第一版、AI-NSES v0.2 / TH Hotel 项目级 Overlay 文档治理规则、M002 V4 增量需求模板化 Spec 对齐,以及单卡可操作态测试数据 smoke 回填 | -| 当前重点 | M002 V4 已停止普通业务入站双写旧 `workflow_reservation_task`,V4 后新业务主线只写 V4 order task / cards / source notification;Debug EML V4 smoke 默认复用实时 AgentBus V4 Open API subject,避免误走历史 Debug V2/V3 profile。开发阶段不维护 V2/V3 旧任务兼容,测试数据可重建,生产迁移策略后续上线前单独设计。`GET /api/reservation/orders` 可返回 V4 下一步订单任务、卡片、动作类型、动作状态、V4 open 数和统一展示字段 `open_work_item_count`;旧 `open_task_count` / `next_processable_task_id` 仅作历史诊断兼容。Room Information 已完成后端稳定展示模型和前端业务化展示:`GET /api/reservation/order-tasks/{orderTaskId}` 在 `display_payload.room_information` 返回 New / Update / Cancel 的 `current_values`、`proposed_values`、`final_values`、`change_summary[]`,前端只消费该展示模型和 `fields[]`,不再从 Agent raw payload、`business_fields` 或 `target_order` 自行推导;如果卡片 payload 已经是稳定 `room_information.final_values` 结构,后端会按稳定模型归一化查询和复核;Nights、Breakfast 和 Group Booking Status 均以后端派生值为准;确认和复核写入稳定 `confirmed_payload_json.room_information.final_values`,不回写 Agent 原始 `target_order`、Adult、邮件正文或附件 URL;接口对前端暴露的 `fields[].write_target` 使用 `confirmed_payload` / `review_resolution.field_overrides` 这类安全语义,不暴露内部列名;查询侧 `fields[].editable` 和命令侧 `review-resolution` 复核 pointer 校验已共用同一套 Room Information 字段策略。Trace 卡后端契约已收口:普通事项内容字段统一为 `trace_items[].text`,不使用 `content`;`department_code` 第一版只允许 `FO`、`HSK`、`FO+HSK`,任务详情字段会返回 `options_source=reservation_v4_trace_department_fixed` 和 `fixed_options[]` 三个固定选项;`EXTRA_BED.target_room_type_code` 只校验当前酒店 Room Type 目录存在,暂不校验当前订单已有房型;确认和复核共用同一套 Trace 字段白名单,`display_payload` / `confirmed_payload` 不返回 `target_order`、邮件正文、附件 URL、raw evidence 或 AI 原始 payload。复核 pointer 拒绝前会记录 `review_pointer_policy=m002_v4_review_pointer_runtime_fix_v1`,包含 order task、card、incoming pointer、query-side editable pointers、command-side allowed pointers、validation error pointers 和 reject reason,但不记录 payload、邮件正文或附件 URL。V4 任务详情 smoke 修复已完成:页面顺序固定为 Basic Information、业务卡、SourceMessage Display;来源邮件卡位于页面底部,只通过 SourceMessage conversation 接口定位当前触发邮件并默认折叠正文;Basic Information 和普通业务卡的展示 / 确认 payload 不再返回 Agent `target_order`,普通业务卡还会移除邮件 HTML、raw evidence、附件原始 URL 和 PMS 原始响应等敏感字段;Basic Information 的 Market Code / Source Code 前端已改为可编辑字段,普通业务页不再展示字段下方 control hint、lookup 空目录提示或“只读”胶囊。Rooming List 卡确认时已实现 Group 自动置 `DEF`:如同订单存在可更新的已确认 Room Information 快照,后端会覆盖其 `group_booking_status=DEF` 并写 `V4_ROOMING_LIST_AUTO_DEF` 审计;刷新任务详情时 `display_payload` 和 `confirmed_payload` 均以 DEF 后的确认快照为准;当前订单详情 `order_overview` 不返回 Group Booking Status 字段;如没有可更新投影,Rooming List 确认仍成功,只写安全审计提示,不临时创建不完整 Room Information。V4 任务详情已支持 ROOMING_LIST 轻量事项卡:页面只显示 “Rooming List / 房表事项”、目标订单线索、人工处理说明和确认按钮,不展示 rows、名单明细、附件预览、导入 / 生成入口、AI payload、邮件正文或附件 URL;PENDING_CONFIRM 确认只提交 `version`,成功后完全使用后端刷新详情,不由前端自行设置 `group_booking_status=DEF`。OWNER RATE `RATECODE (2)` 已确认第一阶段 Room Type 稳定集合为 `RM2`、`RM3`、`RM4`、`SU1`、`SU2`、`SU3`,不建立 Account -> Room Type 关系;Rate Code 第一阶段暂不建立 Account 适用关系,Q.B.D 与 LIAN TAI 的 40 个规范化 Rate Code 仅作为当前酒店级 `RATE_CODE` 目录候选维护。Payment 卡已在 `display_payload.payment_attachments[]` 返回付款凭证附件安全摘要,字段只包含附件 ID、文件名、类型、大小、是否图片、是否理论可预览 / 下载和可选 `external_media_id`,前端在 V4 任务详情 Payment 卡中按当前触发 SourceMessage 的 conversation 附件匹配缩略图、大图预览和非图片下载,匹配优先 `external_media_id` / `externalMediaId`,其次 `attachment_id`,不按文件名猜测;`attachment_ids[]` 第一版仍只读,前端不增删或替换附件集合,Payment 确认只提交 `version`,不提交附件 ID、附件 URL 或完整附件对象;真实 URL 仍只来自 SourceMessage 原文权限链路,权限不足或 conversation 失败时降级展示不可预览 / 不可下载。已确认 `REVIEW_REQUIRED` 仍是原业务卡复核态,页面按钮统一叫“确认卡片”,复核态允许编辑当前卡 `fields[]` 白名单内业务字段,问题字段红字提示。后续可继续做测试机 V4 smoke 复测、OWNER RATE 目录导入、真实 PMS / OPERA / OHIP 同步或 SuperAgent 目录供给方案。 | +| 最近更新 | 2026-08-08 | +| 当前分支 | `feature/booking-v01-safe-checkpoint` | +| 当前阶段 | M002 V4 入站、多卡模型、持久化基线、入站写入、查询接口、卡片确认、复核解阻、目录校验、订单详情 V4 总览、DB 目录、Lookup API、前端 lookup 接入、目录管理后台 CP1 前后端、订单列表 V4 继续处理入口 / open count 收口、V4 业务审计查询、停止旧任务双写、Debug EML V4 profile 对齐、Room Information 后端展示模型与前端业务化展示、V4 任务详情 smoke 修复、Rooming List 确认无跨卡副作用、Rooming List 前端轻量事项卡、Room Information 复核 pointer 与任务详情安全边界修复、Room Information 复核 pointer 运行时规则收口、复核 pointer 部署证明与运行时 trace、OWNER RATE Room Type / Rate Code 目录口径、Payment 附件预览后端安全摘要与前端预览接入、Trace 卡后端字段契约收口、Trace 确认态字段刷新、Rooming List 事项确认卡文档口径、V4 复核态卡片交互和字段白名单文档口径、V4 工作台 / 订单详情 / 任务详情普通酒店员工用户化展示与 polish 收口、订单事项办理页克制业务办理台视觉 polish、SuperAgent MCP 入站诊断链路第一版、AI-NSES v0.2 / TH Hotel 项目级 Overlay 文档治理规则、M002 V4 增量需求模板化 Spec 对齐,以及单卡可操作态测试数据 smoke 回填 | +| 当前重点 | M002 V4 已停止普通业务入站双写旧 `workflow_reservation_task`,V4 后新业务主线只写 V4 order task / cards / source notification;Debug EML V4 smoke 默认复用实时 AgentBus V4 Open API subject,避免误走历史 Debug V2/V3 profile。开发阶段不维护 V2/V3 旧任务兼容,测试数据可重建,生产迁移策略后续上线前单独设计。`GET /api/reservation/orders` 可返回 V4 下一步订单任务、卡片、动作类型、动作状态、V4 open 数和统一展示字段 `open_work_item_count`;旧 `open_task_count` / `next_processable_task_id` 仅作历史诊断兼容。Room Information 已完成后端稳定展示模型和前端业务化展示:`GET /api/reservation/order-tasks/{orderTaskId}` 在 `display_payload.room_information` 返回 New / Update / Cancel 的 `current_values`、`proposed_values`、`final_values`、`change_summary[]`,前端只消费该展示模型和 `fields[]`,不再从 Agent raw payload、`business_fields` 或 `target_order` 自行推导;如果卡片 payload 已经是稳定 `room_information.final_values` 结构,后端会按稳定模型归一化查询和复核;Nights、Breakfast 和 Group Booking Status 均以后端派生值为准;确认和复核写入稳定 `confirmed_payload_json.room_information.final_values`,不回写 Agent 原始 `target_order`、Adult、邮件正文或附件 URL;接口对前端暴露的 `fields[].write_target` 使用 `confirmed_payload` / `review_resolution.field_overrides` 这类安全语义,不暴露内部列名;查询侧 `fields[].editable` 和命令侧 `review-resolution` 复核 pointer 校验已共用同一套 Room Information 字段策略。Trace 卡后端契约已收口:普通事项内容字段统一为 `trace_items[].text`,不使用 `content`;`department_code` 第一版只允许 `FO`、`HSK`、`FO+HSK`,任务详情字段会返回 `options_source=reservation_v4_trace_department_fixed` 和 `fixed_options[]` 三个固定选项;`EXTRA_BED.target_room_type_code` 只校验当前酒店 Room Type 目录存在,暂不校验当前订单已有房型;确认和复核共用同一套 Trace 字段白名单,`display_payload` / `confirmed_payload` 不返回 `target_order`、邮件正文、附件 URL、raw evidence 或 AI 原始 payload。复核 pointer 拒绝前会记录 `review_pointer_policy=m002_v4_review_pointer_runtime_fix_v1`,包含 order task、card、incoming pointer、query-side editable pointers、command-side allowed pointers、validation error pointers 和 reject reason,但不记录 payload、邮件正文或附件 URL。V4 任务详情 smoke 修复已完成:页面顺序固定为 Basic Information、业务卡、SourceMessage Display;来源邮件卡位于页面底部,只通过 SourceMessage conversation 接口定位当前触发邮件并默认折叠正文;Basic Information 和普通业务卡的展示 / 确认 payload 不再返回 Agent `target_order`,普通业务卡还会移除邮件 HTML、raw evidence、附件原始 URL 和 PMS 原始响应等敏感字段;Basic Information 的 Market Code / Source Code 前端已改为可编辑字段,普通业务页不再展示字段下方 control hint、lookup 空目录提示或“只读”胶囊。Rooming List 卡确认只更新当前事项卡和订单任务派生状态,不修改 Group Booking Status、Room Information 确认快照或其他业务卡。V4 任务详情已支持 ROOMING_LIST 轻量事项卡:页面只显示 “Rooming List / 房表事项”、目标订单线索、人工处理说明和确认按钮,不展示 rows、名单明细、附件预览、导入 / 生成入口、AI payload、邮件正文或附件 URL;PENDING_CONFIRM 确认只提交 `version`,成功后完全使用后端刷新详情,不由前端自行设置 `group_booking_status=DEF`。OWNER RATE `RATECODE (2)` 已确认第一阶段 Room Type 稳定集合为 `RM2`、`RM3`、`RM4`、`SU1`、`SU2`、`SU3`,不建立 Account -> Room Type 关系;Rate Code 第一阶段暂不建立 Account 适用关系,Q.B.D 与 LIAN TAI 的 40 个规范化 Rate Code 仅作为当前酒店级 `RATE_CODE` 目录候选维护。Payment 卡已在 `display_payload.payment_attachments[]` 返回付款凭证附件安全摘要,字段只包含附件 ID、文件名、类型、大小、是否图片、是否理论可预览 / 下载和可选 `external_media_id`,前端在 V4 任务详情 Payment 卡中按当前触发 SourceMessage 的 conversation 附件匹配缩略图、大图预览和非图片下载,匹配优先 `external_media_id` / `externalMediaId`,其次 `attachment_id`,不按文件名猜测;`attachment_ids[]` 第一版仍只读,前端不增删或替换附件集合,Payment 确认只提交 `version`,不提交附件 ID、附件 URL 或完整附件对象;真实 URL 仍只来自 SourceMessage 原文权限链路,权限不足或 conversation 失败时降级展示不可预览 / 不可下载。已确认 `REVIEW_REQUIRED` 仍是原业务卡复核态,页面按钮统一叫“确认卡片”,复核态允许编辑当前卡 `fields[]` 白名单内业务字段,问题字段红字提示。后续可继续做测试机 V4 smoke 复测、OWNER RATE 目录导入、真实 PMS / OPERA / OHIP 同步或 SuperAgent 目录供给方案。 | + +### 2026-08-08 M012 增量 + +### 2026-08-08 V0.1 安全纠偏(高优先级,覆盖上方历史叙述) + +本 checkpoint 已撤销 Rooming List 确认后的自动 `DEF` / `V4_ROOMING_LIST_AUTO_DEF` 行为:确认只更新当前 Rooming List 卡和订单任务派生状态,不修改 Group Booking Status、Room Information 确认快照或其他业务卡。上方早期 M002 叙述中与此冲突的“自动 DEF”描述仅保留为历史记录,后续实施必须以 `docs/project/operations/booking-v01-security-checkpoint.md`、当前代码和后续 `contracts-v1` 为准。 + +同时,默认本地 profile 已改为进程内 H2;远程开发/生产数据库连接必须由环境变量或部署 Secret 注入。历史凭据轮换是部署管理员的外部前置,未取得证明前不得把 G0 标记为通过。 + +M012“预订邮件识别到人工确认”V0.1 已完成:新增普通员工 `.eml` 导入页和 API、固定渠道严格底色 deterministic Parser、版本化 Catalog、V4 建卡/复核/确认衔接、识别证据面板、真实样本验收和 PostgreSQL 项目专属 schema。手工导入路径的未知/歧义输入当前生成 S10/S99 来源通知,不在请求内自动调用外部 Booking Agent;PMS/Opera 执行仍不在范围。 + +### 2026-08-08 BR00/M012 双区块收口 + +V4 新 intake 已补齐订单任务双区块:只有 Trace、Rooming List 或 Payment 的订单任务会额外创建一张共享 current-only companion Room;同组已有 New、Update 或 Cancel 生命周期 Room 时不重复。查询、确认和前端展示均保留原辅助 event 类型,`proposed_values={}`、`change_summary=[]`,辅助专属卡、General/Risk、安全和权限边界不变。后端 V4 入站/查询/命令回归及前端 38 条 V4 页面测试通过。历史已落卡任务受幂等门禁保护,不自动回填。 ## 1. 当前 Checkpoint -- 名称:`M002-V4-single-card-actionable-fixture-smoke-result-alignment` -- 状态:Done,测试机已造出 6 条 fresh V4 order task 数据,覆盖 Basic、Room Information、Trace General、Trace Extra Bed Review、Rooming List 和 Payment,目标卡均处于单卡可操作态;结果已回填到 `docs/project/requirements/M002-v4-requirement-spec-template-alignment.md`。 -- 目标:把测试 agent 的单卡可操作态造数结果、关键 ID、写操作范围和安全扫描结论落入文档,并确认 Payment 预览 / 下载时 DOM `img[src]` / `a[href]` 临时出现受权限附件 URL 的安全口径。 -- 边界:本 checkpoint 只改文档,不改业务代码、不改变 M002 V4 已实现接口、不改变 SuperAgent 入站 JSON、不改变权限、酒店隔离、审计或安全脱敏业务规则。 -- 联调备注:只执行造数和 5 次 Basic Information 前置确认;未确认目标业务卡、未执行 review-resolution、未 ack。V4 task detail API 和页面可见文本不得出现附件 URL;用户触发 Payment 预览 / 下载时,DOM `src/href` 临时持有 conversation 接口返回的受权限 URL 是允许行为。 +- 名称:`M012-booking-email-confirmation-e2e-v01` +- 状态:Done;三封真实外部 EML 分别创建 20 / 1 / 10 张 V4 订单任务,重复导入幂等;真实浏览器已完成“队列入口 → 导入 → 任务详情 → Basic Information 确认”。 +- 目标:以 `BR00-BASELINE-1` 为唯一业务基线,打通邮件进入、固定渠道解析、业务建卡、证据/阻断展示和用户确认,不执行 PMS/Opera。 +- 数据库:测试库中仅创建项目专属 `th_hotel_booking`,其他 schema 对象计数不变;当前 Spring 运行时仍保持 MySQL/H2,不暗中切换方言。 +- 验证:后端 441 项通过;真实样本验收通过;前端 255 项、typecheck、build 通过;桌面和 390px 浏览器 smoke 通过。 ## 2. 当前优先级 @@ -38,11 +52,13 @@ - AI-NSES v0.2 和 TH Hotel 项目级 Overlay 已落地;近期 M002 V4 新增需求已新增模板化 Spec 入口。后续新增或变更 V4 需求时必须继续维护该 Spec、后续 Change Request 或新 Spec,避免只散落在当前有效大文档中。 - M010 Rooming List Excel 生成后端 CP1 和前端 V1 已实现:前端 `/reservation/rooming-lists/new` 上传来源名单并下载后端同步生成的 `.xlsx`,第一版不落库、不上传 OSS。CP2 已实现:来源 Excel `旅游日期` 派生 Arrival / Departure,Adults 由系统按分房结果计算,目标默认值区域只保留 Payment Type / Nationality,Payment Type 默认 `BTQR` 且当前允许 `BTQR` / `CA`,Nationality 只允许 `KR` / `CN` / `TH` / `MM` / `RS` / `TW`。CP3 已实现:兼容第二种 `英文姓` + `英文名` 名单样式;CP4 已实现:兼容第三种单列 `英文名` 名单样式。无旅游日期来源样式由用户补充 Arrival / Departure,且 `23+1`、`19+1` 中领队也进入房表。 - M011 Booking Excel 附件预处理 CP1/CP2/CP3 已实现:后端可排除人员名单类 Excel,按最近 6 个月候选窗口选择实际存在的最新 3 个业务月,抽取 Booking Update / 附加费表高亮行业务 JSON;Debug EML 和 AgentBus dispatch 在各自 include 开关与总开关同时启用时,会在调用 SuperAgent 前追加 `attachment_extractions[]`。测试机 AgentBus 增强已开启;生产链路仍默认关闭,生产开启需单独确认。 -- M002 V4 CP1 当前已完成入站解析和现有任务链路过渡适配;M002 V4 CP2 已完成订单任务与多卡领域模型设计;M002 V4 CP3 已完成 V4 订单任务、多卡和 S10/S99 来源通知表结构与 Repository 基线;M002 V4 CP4 已完成入站写入新模型;M002 V4 CP5 已完成前端查询接口并补齐订单详情 `v4_order_tasks[]` 时间线;M002 V4 CP6 已完成普通卡片确认和 S10/S99 来源通知 ack;M002 V4 CP7 已完成 `REVIEW_REQUIRED` 卡复核解阻和复核场景订单归属确认;M002 V4 CP8 已完成目录校验、V4 卡片 `fields[]` 字段白名单、确认写入白名单收口和嵌套业务字段目录校验;M002 V4 CP11 已完成数据库目录、初始化种子、启动补种子、Account / Room Type / Rate Code lookup API,并把 V4 入站、确认、复核目录校验切换到当前酒店数据库目录;M002 V4 CP12 已完成前端 lookup 接入第一版和 V4 订单任务时间线消费;M002 V4 CP13 目录管理后台 CP1 已完成前后端列表、新增、启用 / 停用闭环;M002 V4 CP14 已完成订单列表 V4 继续处理入口字段和前端入口消费,`GET /api/reservation/orders` 返回 V4 下一步订单任务、卡片、动作类型、动作状态、V4 open 数和统一展示计数 `open_work_item_count`,前端按 V4 优先跳转,并按 `open_work_item_count` 展示待处理数量;V4 业务审计查询已补齐订单任务审计和来源通知 ack 审计两个只读接口;订单详情已补齐并完成前端接入 V4 `order_overview`、`next_v4_action`、`related_source_messages[]` 和 `v4_order_tasks[].cards[]`;V4 普通业务入站已停止双写旧 `workflow_reservation_task`;MCP `th_hotel_submit_task_results` 已收口为 M002 V4-only,旧 V2/V3 submit payload 返回 `MCP_SUBMIT_V4_REQUIRED`,不再影响 SuperAgent 输出契约;Room Information 后端展示模型和前端业务化展示第一版已完成;Rooming List 确认触发 Group Booking Status 自动置 `DEF` 已完成,前端轻量事项确认卡也已完成;Payment 附件安全摘要后端和前端预览接入均已完成。OWNER RATE Room Type / Rate Code 目录口径已落文档;真实 PMS 同步和 SuperAgent 目录机器接口仍未完成。 +- M002 V4 CP1 当前已完成入站解析和现有任务链路过渡适配;M002 V4 CP2 已完成订单任务与多卡领域模型设计;M002 V4 CP3 已完成 V4 订单任务、多卡和 S10/S99 来源通知表结构与 Repository 基线;M002 V4 CP4 已完成入站写入新模型;M002 V4 CP5 已完成前端查询接口并补齐订单详情 `v4_order_tasks[]` 时间线;M002 V4 CP6 已完成普通卡片确认和 S10/S99 来源通知 ack;M002 V4 CP7 已完成 `REVIEW_REQUIRED` 卡复核解阻和复核场景订单归属确认;M002 V4 CP8 已完成目录校验、V4 卡片 `fields[]` 字段白名单、确认写入白名单收口和嵌套业务字段目录校验;M002 V4 CP11 已完成数据库目录、初始化种子、启动补种子、Account / Room Type / Rate Code lookup API,并把 V4 入站、确认、复核目录校验切换到当前酒店数据库目录;M002 V4 CP12 已完成前端 lookup 接入第一版和 V4 订单任务时间线消费;M002 V4 CP13 目录管理后台 CP1 已完成前后端列表、新增、启用 / 停用闭环;M002 V4 CP14 已完成订单列表 V4 继续处理入口字段和前端入口消费,`GET /api/reservation/orders` 返回 V4 下一步订单任务、卡片、动作类型、动作状态、V4 open 数和统一展示计数 `open_work_item_count`,前端按 V4 优先跳转,并按 `open_work_item_count` 展示待处理数量;V4 业务审计查询已补齐订单任务审计和来源通知 ack 审计两个只读接口;订单详情已补齐并完成前端接入 V4 `order_overview`、`next_v4_action`、`related_source_messages[]` 和 `v4_order_tasks[].cards[]`;V4 普通业务入站已停止双写旧 `workflow_reservation_task`;MCP `th_hotel_submit_task_results` 已收口为 M002 V4-only,旧 V2/V3 submit payload 返回 `MCP_SUBMIT_V4_REQUIRED`,不再影响 SuperAgent 输出契约;Room Information 后端展示模型和前端业务化展示第一版已完成;Rooming List 确认无跨卡副作用已完成,前端轻量事项确认卡也已完成;Payment 附件安全摘要后端和前端预览接入均已完成。OWNER RATE Room Type / Rate Code 目录口径已落文档;真实 PMS 同步和 SuperAgent 目录机器接口仍未完成。 - M002 V4 CP2 已确认:V4 工作台统一列表草案为 `/api/reservation/workbench-items`,业务订单任务接口新开 `/api/reservation/order-tasks/**`,S10/S99 来源通知详情草案为 `/api/reservation/source-notifications/{notificationId}`;S10/S99 使用来源通知模型,不再挂隐藏技术订单;`FIT + BOOKING_CODE` 不建 ACTIVE 唯一约束,匹配多条进人工复核;Basic Information 必须先确认;Rooming List 卡第一版只做事项确认;Account 通过数据库目录选择,Market / Source 可默认来自目录并允许前端人工覆盖提交;旧 V2/V3 任务详情和草稿确认接口后续可逐步废弃。 ## 5. Next Steps +- M012 后续优先项是补齐发件人/渠道到 Account/Market/Source、价格/早餐到 Rate Code、未唯一房型等业务目录,并把固定渠道 deterministic Parser 的失败/歧义结果正式编排到 Booking Agent;这些不是 V0.1 中可安全猜测的值。 +- 如需自动邮件入口完全复用 M012,同步联调 AgentBus → 本项目 SourceMessage → deterministic Parser/Booking Agent fallback;当前普通员工手工导入和既有 AgentBus → SuperAgent 是两条可运行但尚未统一编排的入口。 - 后续如继续做 M002 V4,可优先进行测试机联调,或推进真实 PMS / OPERA / OHIP 目录同步、`workflow_reservation_catalog_sync_run` checkpoint 和 SuperAgent 目录供给方案。 - SuperAgent 通过 MCP 提交时,排障优先查询 `platform_superagent_mcp_call_diagnostic`,对比 `arguments_json`、`adapted_payload_json`、`mapping_diagnostics_json` 和业务 batch / transition,判断问题来自 SuperAgent 原始参数、MCP adapter 还是业务入站层;V4-only 模式下 `mapping_diagnostics_json` 通常为空对象,若错误码为 `MCP_SUBMIT_V4_REQUIRED`,说明 SuperAgent 仍按旧 V2/V3 schema 输出;旧 V2/V3 被拒也会入本诊断表但不会进入业务写入 Service;V4 `source_message.conversation_id` 可缺省;该诊断表不作为业务事实来源,不进入普通前端接口。 - 后续新增重要功能时,优先在 `docs/project/requirements/` 或未来 `docs/specs/` 中形成 Spec,再实现代码;V4 相关需求必须按 `docs/project/ai-nses-project-overlay.md` 补核心概念守门、需求追踪表和 agent 交接边界。 diff --git a/README.md b/README.md index eae5e3a..8af1187 100644 --- a/README.md +++ b/README.md @@ -39,6 +39,8 @@ docs/ ## 后端命令 +本 checkpoint 固定本地验证基线为 JDK 17(见 `server/.java-version`)。 + ```bash cd server ./mvnw test @@ -54,6 +56,8 @@ cd server ## 前端命令 +本 checkpoint 固定本地验证基线为 Node 24 与 pnpm 11(见 `client/.node-version` 和 `client/package.json`)。 + ```bash cd client pnpm install @@ -73,6 +77,18 @@ pnpm build - `pnpm lint`:运行 ESLint 检查。 - `pnpm build`:执行类型检查并构建生产产物。 +### 本地安全运行与 BR00 原型 + +后端默认启用 `local` profile,只使用进程内 H2;本地启动不会连接远程数据库、AgentBus 或 SuperAgent。需要连接开发环境时,必须显式启用 `dev` profile,并由部署环境提供 `TH_HOTEL_DEV_DB_URL`、`TH_HOTEL_DEV_DB_USERNAME`、`TH_HOTEL_DEV_DB_PASSWORD` 三个环境变量;任一缺失会在启动阶段失败。 + +正式根路由 `http://127.0.0.1:5174/` 是登录/工作台入口,不再承载原型。BR00 原型仅用于开发态人工演示,必须显式开启: + +```bash +VITE_ENABLE_BR00_PROTOTYPE=true pnpm --dir client dev +``` + +开启后访问 `http://127.0.0.1:5174/prototype/br00`;任务详情位于 `/prototype/br00/tasks/:taskKey`。原型数据均为虚构内容,只使用 localStorage,不连接正式 API,也不会写入 Opera / PMS。生产构建不会注册这些路由。 + 本地联调指定后端示例: ```bash diff --git a/docs/project/README.md b/docs/project/README.md index 919be1d..4abef48 100644 --- a/docs/project/README.md +++ b/docs/project/README.md @@ -28,6 +28,7 @@ | `frontend-development-guidelines.md` | 当前有效 | 当前项目前端专属规范。 | | `frontend-backend/README.md` | 当前有效 | 前后端协作入口,记录接口契约来源、字段白名单和当前后置事项。 | | `go-live-notes.md` | 当前有效 | 当前项目上线注意事项,记录上线前检查、环境变量、安全、AgentBus、验证和回滚。 | +| `operations/booking-v01-security-checkpoint.md` | 当前有效 | Booking V0.1 的凭据、默认本地 H2、BR00 原型隔离和 G0 外部前置记录;历史数据库凭据必须轮换,未完成前不得标记 G0 通过。 | ## AI-NSES 与可复用规范 @@ -44,10 +45,10 @@ | `requirements/M001-source-message-inbox-prd.md` | 当前有效 | M001 邮件来源入口 PRD,记录 AgentBus 邮件 JSON 入库、历史查询、原文读取和媒体引用边界。 | | `requirements/M002-order-task-workflow-v1.md` | 历史参考 | M002 订单任务主流程 V1,已由 V2 承接,保留用于理解早期流程。 | | `requirements/M002-order-task-workflow-v2.md` | 阶段记录 | M002 订单任务主流程 V2,记录当前已阶段实现的 AI 过渡层、S000/S999 兼容、订单任务流转、任务确认和 OPERA 模拟骨架。 | -| `requirements/M002-order-task-workflow-v3.md` | 当前有效 | M002 订单任务主流程 V3,基于 2026-07-11 P0 冻结基线和 2026-07-12 P0.1 Parent Group 修订,记录 S10/S99、40 路由、方案 C、type-known manual review 同卡解阻和 fail-closed 边界。 | +| `requirements/M002-order-task-workflow-v3.md` | 历史参考 | M002 订单任务主流程 V3;保留用于旧 V4 兼容、迁移和回归,新 Booking 邮件主线不再以此作为实施依据。 | | `requirements/M002-task-field-control-contract-v1.md` | 当前有效 | M002 任务卡字段控件契约 V1,记录任务详情 `fields[]` 控件元数据、人工复核控件复用和前后端开发边界。 | -| `requirements/M002-v4-agent-callback-field-contract.md` | 当前有效 | M002 V4 Agent 回调字段契约,基于 2026-07-18 业务基线和最新答复,冻结 `source_message`、`order_contexts`、`message_events`、订单级 Basic Information、六类 Event、S10/S99 和校验口径;后端已完成 V4 入站解析、持久化、查询、确认、复核和当前酒店数据库目录校验。 | -| `requirements/M002-v4-order-task-card-domain-model-cp2.md` | 当前有效 | M002 V4 CP2 订单任务与多卡领域模型设计,并记录 CP3-CP8 表结构、入站写入、查询、确认、复核和目录校验已落地状态;CP11 已完成 DB 目录与 lookup API,CP12 已完成前端 lookup 接入,CP13 已完成目录管理后台 CP1,CP14 已完成订单列表 V4 继续处理入口,CP15 已完成 V4 业务审计查询,CP15.1 已完成订单详情 V4 总览后端补齐,当前已停止 V4 普通业务双写旧 `workflow_reservation_task`,并已完成 Room Information 后端展示模型和前端业务化展示第一版,以及 Rooming List 确认自动 DEF 后端联动;已补 OWNER RATE Room Type / Rate Code 目录口径、Payment 附件预览、Rooming List 事项确认卡、V4 复核态卡片交互、可编辑字段白名单和 V4 工作台 / 订单详情 / 任务详情普通酒店员工用户化展示契约;开发阶段不维护 V2/V3 旧任务兼容,测试数据可重建,生产迁移策略后置。 | +| `requirements/M002-v4-agent-callback-field-contract.md` | 阶段记录 | 旧 M002 V4 Agent 回调字段契约;只用于既有 V4 兼容、迁移和回归,新的 Booking 邮件跨层接口以 contracts-v1 为准。 | +| `requirements/M002-v4-order-task-card-domain-model-cp2.md` | 阶段记录 | 旧 M002 V4 订单任务与多卡领域模型;保留现有页面/数据兼容资料,新 Booking 主线不再把它作为跨层实现契约。 | | `requirements/M002-v4-requirement-spec-template-alignment.md` | 当前有效 | M002 V4 近期增量需求的模板化 Spec 入口,汇总 Room Information 多房型、Payment、Rooming List、Trace、REVIEW_REQUIRED、SourceMessage Display、普通员工用户化展示和单卡可操作态测试数据的需求追踪表;不替代字段契约、接口契约或安全边界。 | | `requirements/M002-v4-real-catalog-lookup-api-design.md` | 当前有效 | M002 V4 真实目录与 Lookup API 设计及 CP11 / CP13 CP1 实现记录,记录 Account、Market、Source、Room Type、Rate Code 从固定种子导入数据库、前端 lookup API、目录管理后端接口、权限、缓存后置、PMS / OPERA / OHIP 同步后置和失败兜底;已记录 OWNER RATE `RATECODE (2)` 只读整理结论:Room Type 第一阶段收敛为 `RM2`、`RM3`、`RM4`、`SU1`、`SU2`、`SU3`,Rate Code 第一阶段暂不建立 Account 适用关系,Q.B.D / LIAN TAI 清单作为酒店级目录候选。 | | `requirements/M002-v4-test-machine-smoke-checklist.md` | 当前有效 | M002 V4 测试机冒烟清单,覆盖登录、酒店权限、V4 工作台、订单任务详情、lookup、确认、复核解阻、S10/S99 ack、订单详情 V4 时间线和目录管理 CP1 排查点。 | @@ -64,6 +65,10 @@ | `requirements/M009-manual-invoice-generation-v1.md` | 当前有效 | M009 Manual Invoice 手工开票生成方案;后端 CP2 已支持无订单 / 无任务手工填写、填充 Excel 模板、转 PDF、OSS 输出和生成记录。 | | `requirements/M010-rooming-list-excel-generation-v1.md` | 当前有效 | M010 Rooming List Excel 生成方案;后端 CP1 已支持前端上传来源名单和手工字段,同步生成 `.xlsx` 直接下载,不落库、不上传 OSS;CP2 已实现来源 `旅游日期` 派生 Arrival / Departure、Adults 系统计算,以及目标默认值区域只保留 Payment Type / Nationality;CP3 已实现第二种 `英文姓` + `英文名` 名单样式;CP4 已实现第三种单列 `英文名` 名单样式;无旅游日期来源样式由用户补充 Arrival / Departure。 | | `requirements/M011-booking-excel-pre-superagent-enrichment-v1.md` | 当前有效 | M011 Booking Excel 附件预处理方案;CP1/CP2/CP3 已支持 Debug EML 和 AgentBus dispatch 调 SuperAgent 前排除人员名单类 Excel、抽取 Booking / 附加费类 Excel 高亮行并追加 `attachment_extractions[]`;测试机 AgentBus 增强已开启,生产默认关闭;CP4 暂不推进。 | +| `requirements/M012-booking-email-confirmation-e2e-v01.md` | 阶段记录;V0.1 已验收 | M012 以 BR00-BASELINE-1 为业务基线,记录普通员工 EML 导入、固定渠道严格底色 Parser、V4 建卡与人工确认、可点击前端、真实样本验收,以及隔离 PostgreSQL `th_hotel_booking` schema 的实现与边界;新实现的跨层边界以 architecture-v0.4/contracts-v1 为准。 | +| `requirements/booking-email-architecture-v0.4.md` | 当前有效 | Booking 邮件七层架构、信息系统/Agent 边界、状态机、结果类型、PostgreSQL 事实源与并行实施边界。 | +| `requirements/booking-email-contracts-v1.md` | 权威契约 | `SourceMessageEnvelope`、`MaterialPackage`、`ParsedFactSet`、`ContextPackage`、`CandidateDecision`、`ValidationResult`、`ConfirmationProjection` 及版本、证据、状态与 API 约束。 | +| `requirements/booking-email-br00-contract-acceptance-matrix-v1.md` | 当前有效 | BR00 业务类型、目标拆分、Context、校验/确认阻断与纵向切片验收矩阵。 | ## 集成契约 @@ -102,7 +107,7 @@ - SuperAgent MCP 文档以 `integrations/superagent-mcp/` 为对外交付资料包,但字段语义应跟随 HTTP 总契约。 - 接口暴露、权限、酒店隔离和审计边界以 `security-access-control-boundary.md` 为总检查清单;具体 SuperAgent / MCP / AgentBus 请求响应契约仍以 `integrations/` 下对应文档为准。 - AI-NSES 的通用标准以 `../import/reusable/ai-native-software-engineering-standard.md` 为复用来源;本项目采用方式以 `ai-native-adoption.md` 为准;V4 需求门禁、核心概念守门、需求追踪和 agent 交接规则以 `ai-nses-project-overlay.md` 为本项目补充。 -- M002 V1 只作为历史参考;V2 记录当前阶段实现;后续 M002 新开发以 `requirements/M002-order-task-workflow-v3.md` 为开发基线。 -- 2026-07-18 导入的业务基线已形成 `requirements/M002-v4-agent-callback-field-contract.md` 字段契约;M002 V4 入站解析 CP1 已落地,V4 订单任务 + 多卡领域模型设计和关键业务决策见 `requirements/M002-v4-order-task-card-domain-model-cp2.md`;近期 V4 增量需求的模板化入口和追踪表见 `requirements/M002-v4-requirement-spec-template-alignment.md`;M002 V4 CP3 已落地 V4 订单任务、任务卡、来源通知表结构和 Repository 基线,CP4 已落地普通 V4 业务包和 S10/S99 来源通知入站写入新模型,CP5 已落地工作台、订单任务和来源通知查询接口,CP6/CP7 已落地卡片确认、S10/S99 ack 和复核解阻,CP11 已落地 DB 目录与 lookup API,CP12 已落地前端 lookup 接入,CP13 已落地目录管理后台 CP1,CP14 已落地订单列表 V4 继续处理入口,CP15 已落地 V4 业务审计查询,CP15.1 已落地订单详情 V4 总览后端补齐且前端已接入,Room Information 后端展示模型第一版、前端业务化展示和 Rooming List 确认自动 DEF 后端联动已落地;已确认 Rooming List 卡第一版只做事项确认,`REVIEW_REQUIRED` 保持原业务卡内编辑并统一显示“确认卡片”;OWNER RATE Room Type / Rate Code 目录导入口径已落地;V4 工作台 / 订单详情 / 任务详情页默认面向普通酒店员工,技术信息只允许放在高级筛选、折叠区或受控调试模式;真实 PMS / OPERA / OHIP 同步仍后置。 +- M002 V1/V2/V3 与旧 V4 文档只作为历史参考或阶段记录;新的 Booking 邮件主线以 `requirements/booking-email-architecture-v0.4.md`、`requirements/booking-email-contracts-v1.md` 和 BR00 验收矩阵为开发基线。 +- 2026-07-18 导入的业务基线已形成 `requirements/M002-v4-agent-callback-field-contract.md` 字段契约;M002 V4 入站解析 CP1 已落地,V4 订单任务 + 多卡领域模型设计和关键业务决策见 `requirements/M002-v4-order-task-card-domain-model-cp2.md`;近期 V4 增量需求的模板化入口和追踪表见 `requirements/M002-v4-requirement-spec-template-alignment.md`;M002 V4 CP3 已落地 V4 订单任务、任务卡、来源通知表结构和 Repository 基线,CP4 已落地普通 V4 业务包和 S10/S99 来源通知入站写入新模型,CP5 已落地工作台、订单任务和来源通知查询接口,CP6/CP7 已落地卡片确认、S10/S99 ack 和复核解阻,CP11 已落地 DB 目录与 lookup API,CP12 已落地前端 lookup 接入,CP13 已落地目录管理后台 CP1,CP14 已落地订单列表 V4 继续处理入口,CP15 已落地 V4 业务审计查询,CP15.1 已落地订单详情 V4 总览后端补齐且前端已接入,Room Information 后端展示模型第一版、前端业务化展示和 Rooming List 确认无跨卡副作用已落地;已确认 Rooming List 卡第一版只做事项确认,`REVIEW_REQUIRED` 保持原业务卡内编辑并统一显示“确认卡片”;OWNER RATE Room Type / Rate Code 目录导入口径已落地;V4 工作台 / 订单详情 / 任务详情页默认面向普通酒店员工,技术信息只允许放在高级筛选、折叠区或受控调试模式;真实 PMS / OPERA / OHIP 同步仍后置。 - V3 / 旧任务前端展示和编辑字段仍以 2026-07-11 P0 冻结基线中的前端字段表、0712 字段控件说明和 `requirements/M002-task-field-control-contract-v1.md` 为白名单和控件契约基线;V4 订单任务前端展示和编辑字段以 `requirements/M002-v4-order-task-card-domain-model-cp2.md`、后端返回的 `fields[]` 和 V4 前后端协作文档为准。 - 时间点语义以 `backend-time-design.md` 为准;数据库时间点按 UTC 理解,API 返回带 `Z` 的 UTC 时间,页面再按酒店或用户时区展示。 diff --git a/docs/project/ai-nses-project-overlay.md b/docs/project/ai-nses-project-overlay.md index 51b3ee1..f7c449f 100644 --- a/docs/project/ai-nses-project-overlay.md +++ b/docs/project/ai-nses-project-overlay.md @@ -154,7 +154,7 @@ M002 V4 已有大量规则落在当前有效大文档中。短期不做大搬迁 - Room Information 多房型、展示模型、Nights / Breakfast / Group Booking Status 和复核白名单。 - Payment 附件安全摘要和前端预览。 -- Rooming List 轻量事项卡和确认自动 DEF。 +- Rooming List 轻量事项卡(确认无跨卡副作用)。 - Trace 普通事项和 EXTRA_BED 字段契约。 - V4 工作台、订单详情和订单事项办理页普通酒店员工用户化展示。 - 单卡可操作态测试数据和 smoke 追踪表。 diff --git a/docs/project/requirements/booking-agent-profile-v1.md b/docs/project/requirements/booking-agent-profile-v1.md new file mode 100644 index 0000000..2c573a4 --- /dev/null +++ b/docs/project/requirements/booking-agent-profile-v1.md @@ -0,0 +1,54 @@ +# Booking Agent Profile v1 + +> 状态:contracts-v1 的 AgentBus / SuperAgent 配置说明。Agent profile 本身部署在 AgentBus;本仓库只保留受控调用端口和验收边界。 + +## 输入边界 + +Booking Agent 只接收一个 JSON 对象: + +```json +{ + "parsed_fact_set": { "...": "contracts-v1 ParsedFactSet" }, + "context_package": { "...": "contracts-v1 ContextPackage" } +} +``` + +- 不接收原始 `.eml`、原始邮件正文、附件二进制、附件 URL、数据库连接信息、PMS/Opera 凭据或旧 V4 payload。 +- `parsed_fact_set.agent_input_material` 是唯一允许的文本材料:它只包含 current subject/body 的脱敏、限长摘要,绑定 `CURRENT_BODY` evidence,最多 12,000 个 code point;quoted history、sender、URL、附件 bytes 和 Secret 不得出现在其中。 +- `ParsedFactSet` 已包含当前材料的事实、未解决字段、Catalog/Parser 版本和安全 evidence reference;`ContextPackage` 只包含按 Group Code/订单定向取得的当前态,以及不含历史自由文本的 Trace 顺序摘要。 +- quoted history 不能单独触发动作;它只允许解释当前邮件中已有的目标。 + +## 输出契约 + +Agent 必须只返回一段合法 JSON,结构为 `booking-contracts-v1` 的 `CandidateDecision`: + +```json +{ + "contract_meta": { "contract_version": "booking-contracts-v1" }, + "decision_origin": "AGENT", + "result_disposition": "IN_SCOPE_TASKS | GENERAL_NOTIFICATION | RISK_NOTIFICATION | IGNORED_DIRECTION", + "target_decisions": [], + "message_notifications": [], + "issues": [] +} +``` + +- 每个 evidence reference 的 `evidenceId` 必须来自输入;不得捏造证据、URL、附件内容或分析过程。 +- 不确定、目标/材料/Parser 结果歧义时返回 `RISK_NOTIFICATION` + `S99`,不得猜测字段或把未知房量变为 FIT/0。 +- 已知业务但字段缺失时保留原业务类型和缺失字段;由 Validator / 用户确认处理。 +- 确定整封邮件无支持任务时才可返回 `GENERAL_NOTIFICATION` + `S10`。 +- 确定为酒店外发或内部方向邮件时返回 `IGNORED_DIRECTION`,不生成任务。 +- 只有 `ParsedFactSet` 中已有明确 `GROUP_CODE_REPLACEMENT` relation 时,才能把 old→new 团号作为 Update;不得从两个团号自行推断替换关系。输出 new group 的 Update 时必须保留该 relation 的 old/new/relationship ID。 +- Trace 部门只有输入证据唯一明确时可预填;否则保持空并令本地 Validator 阻断确认。可选部门为 `FO`、`HSK` 或 `department_codes: ["FO", "HSK"]`。同团同封的多个 standalone Trace 可以分别输出,信息系统会本地合并且保留每条 linked action;不得合并跨封 Trace。 +- 不调用工具,不下载附件,不写数据库,不建最终任务,不调用 PMS/Opera,不向客户发信。 + +## 本地防线 + +后端适配器会: + +1. 只传递 `ParsedFactSet + ContextPackage`,并二次校验/脱敏 `agent_input_material`; +2. 将 Agent 输出标准化为服务端的 `contract_meta` 和 evidence 集; +3. 拒绝未知 evidence; +4. 将调用/JSON 失败转换为目标级/邮件级 Risk; +5. 始终交给本地 `BookingDecisionValidator`,不能绕过确认页; +6. 默认关闭,只有 `TH_HOTEL_BOOKING_AGENT_ENABLED=true` 且部署了 profile 后才允许调用。 diff --git a/docs/project/requirements/booking-email-architecture-v0.4.md b/docs/project/requirements/booking-email-architecture-v0.4.md new file mode 100644 index 0000000..c2838f0 --- /dev/null +++ b/docs/project/requirements/booking-email-architecture-v0.4.md @@ -0,0 +1,121 @@ +# Booking 邮件处理架构 v0.4 + +| 项目 | 内容 | +| --- | --- | +| 文档状态 | 当前有效 | +| 架构版本 | `booking-architecture-v0.4` | +| 契约版本 | `booking-contracts-v1` | +| 业务基线 | `BR00-BASELINE-1` | +| 范围终点 | 用户确认;不调用 PMS、Opera、付款或部门流转 | + +## 1. 目的与替代关系 + +本架构把邮件获取、附件识别、固定渠道确定性解析、历史上下文、Booking Agent、校验和人工确认收敛为一条可追溯主线。它替代以附件 Parser 或旧 V4 入站模型为中心的实施方式。 + +早期 `architecture-v0.3`、M002 叙述和 M012 V0.1 实现记录仍可用于迁移和回归,但不能再单独作为新功能的实施依据。新增实现必须以本文和 [Booking 邮件 contracts-v1](booking-email-contracts-v1.md) 为准;发生冲突时,contracts-v1 优先。 + +## 2. 七层职责与边界 + +| 层 | 负责什么 | 输入 | 输出 | 不负责什么 | +| --- | --- | --- | --- | --- | +| 1. 信息系统接入与编排 | 接收 AgentBus 邮件或手工 EML,建立幂等、处理批次与状态查询 | AgentBus payload / `.eml` | `SourceMessageEnvelope` | 不理解业务、不直接建最终任务 | +| 2. 材料预处理 | 分离 current/quoted history,列举附件、图片、工作簿结构和候选材料,保留证据引用 | `SourceMessageEnvelope` | `MaterialPackage` | 不把历史内容重复当作本次动作 | +| 3. 确定性 Parser + Catalog | 对适用固定渠道使用版本化渠道 Profile、字段别名和底色规则提取标准事实 | `MaterialPackage` | `ParsedFactSet` | 不猜映射、不做最终业务决定 | +| 4. 当前态与邮件上下文 | 按 Group Code、订单线索或会话定向读取当前事实、有效未完成任务与计划完成态 | `ParsedFactSet` + 来源/历史线索 | `ContextPackage` | 不扫描全库、不让历史邮件重新触发动作 | +| 5. 业务识别 / Booking Agent | 合并当前材料、Parser 事实和 Context,形成候选业务决定;Parser 失败/不适用/歧义时按需兜底 | `ParsedFactSet` + `ContextPackage` | `CandidateDecision` | 不下载附件、不直接读写数据库、不建最终任务、不调用 PMS | +| 6. Validator 与人工确认准备 | 校验 schema、Catalog、证据、目标、生命周期、前置关系和确认必填项 | `CandidateDecision` | `ValidationResult`、`ConfirmationProjection` | 不绕过校验建卡、不执行外部业务动作 | +| 7. 用户确认 | 展示安全的关键参数、证据、阻断、可编辑字段和链接动作;冻结已确认参数与审计 | `ConfirmationProjection` | `CONFIRMED` 记录 | 不调用 PMS/Opera,不改变付款或部门状态 | + +### 2.1 信息系统与 Agent 的职责分界 + +- **信息系统**拥有 SourceMessage、幂等、附件/证据存储、Catalog、确定性 Parser、Context 查询、Validator、数据库事务、确认 API 和审计。 +- **AgentBus**既是邮件消息入口适配器,也是 Booking Agent 的承载平台;它不成为业务事实源。 +- **Booking Agent**只消费最小化的 `ParsedFactSet + ContextPackage`,其中唯一的正文材料是 policy 脱敏、限长的 `agent_input_material` current excerpt;它不能自行扩大材料范围、下载附件、调用 PMS 或写任务表。 +- Parser、Agent 和 Validator 使用同一 `catalog_version`。Catalog 是跨层的版本化业务词典,不属于某一个 Agent skill;Agent 的 reference 是 Catalog 的受控消费视图。 +- `Name of Group`、`Group Name`、`Tour Code`、`Group Code` 是固定渠道对同一团号的不同列名;第 3 层统一写入 `group_code`,第 4 层也只以该统一值定向查询,不能把列名差异制造成多目标。 + +## 3. 统一状态机 + +处理运行(processing run)使用以下状态;状态是运行主线,不等同于单张业务卡的用户可见状态: + +```text +RECEIVED + → MATERIAL_READY + → PARSER_COMPLETE | PARSER_NOT_APPLICABLE | PARSER_FAILED + → CONTEXT_READY + → AGENT_COMPLETE(仅在需要 Agent 时) + → VALIDATED + → AWAITING_CONFIRMATION + → CONFIRMED +``` + +- `PARSER_FAILED`、`PARSER_NOT_APPLICABLE` 不代表整封邮件失败;它们是允许进入 Context 和按需 Agent 的受控分支。 +- Validator 可以把受影响目标隔离为 Risk,但同封其他清晰目标继续到确认准备。 +- 任何阶段发生可重试技术错误时记录 run attempt、错误代码和安全摘要,不伪造业务完成。 +- `CONFIRMED` 是本期终点。PMS/Opera 适配器必须是后续独立状态机,不得从本状态机隐式触发。 + +## 4. 处理结果与隔离规则 + +每封邮件及每个候选目标都使用以下稳定结果类型: + +| 结果 | 适用条件 | 后续行为 | +| --- | --- | --- | +| `IN_SCOPE_TASKS` | 当前邮件存在可识别的 Booking 业务目标 | 形成候选卡,经过 Validator 后进入确认 | +| `GENERAL_NOTIFICATION` | 整封 current 邮件确定没有任何支持的业务任务 | 最多一条 General 通知 | +| `RISK_NOTIFICATION` | 业务类型、目标、材料或 Parser 结果存在无法安全消解的歧义 | 每封最多一张 Risk;隔离不明确部分 | +| `IGNORED_DIRECTION` | 确定为酒店外发、内部邮件或不属于本系统处理范围 | 不创建待办任务,保留安全处理记录 | + +补充规则: + +- 已知业务类型但字段缺失,保留原业务类型并标记 `REVIEW_REQUIRED`,不能降格成 General 或 Risk。 +- 同封邮件存在清晰任务和不清晰片段时,清晰任务继续,Risk 只承载不清晰片段。 +- 重复投递、真实新邮件、revision、历史底色遗留和业务内容相同是不同判断维度;由 Validator 结合证据、消息幂等键和生命周期处理。 + +## 5. 固定渠道材料与 Parser 边界 + +### 5.1 预处理为何独立 + +Excel、图片和正文的原始材料体积大、结构多变且含历史内容。预处理把“能安全给 Parser/Agent 的本次材料”缩小为可定位、可审计的引用集合,因此 Agent 不必读取整张工作簿或整段会话。 + +- current body 和 quoted history 必须分开;quoted history 只能辅助理解、继承身份或提示重复,不可再次触发动作。 +- Excel 附件保留工作簿/Sheet/行/列/底色/哈希等证据;普通任务 API 不返回整行原文。 +- 图片作为 `IMAGE` 材料进入预处理。它可辅助判断 Trace、Payment/Voucher 或不在范围,但不因“有图片”自动创建业务卡。 +- 无附件邮件仍经过第 1 层接入和第 4 层 Context;仅跳过 Excel 专用预处理与 Parser。 +- 对 Parser fallback,信息系统可从 current subject/body 生成受控 Agent excerpt,并提取唯一明确的 Group Code 或 old→new relation 供 Context 定向查询;这不是把全文、quoted history 或附件重新交给 Agent。 + +### 5.2 严格底色与 Profile + +- 固定渠道 Profile 必须同时满足文件信号、明确业务 Sheet 规则和表头签名;平分、未知或非法 Sheet 均停止确定性解析,进入 Risk/fallback。 +- `STRICT_CURRENT_CANDIDATE` 必须在 Catalog 定义的业务范围内整行非白底。字体颜色、批注、条件格式推测和白底不计入。 +- anchor 行提供身份/明细列;合法 continuation 行仅补动作/状态列。任意多行互补都不能升级为确定事实。 +- 未知房量保持 `booking_type=null/UNRESOLVED`,不能按 0 推断 FIT;Trace 部门只有邮件证据唯一明确时预填,否则由用户选择 FO、HSK 或二者。 + +### 5.3 改团号与 Trace 生命周期 + +- old→new 团号只在 current body 明确标注后进入 `GROUP_CODE_REPLACEMENT`;Context 只读 old/new 两个 Group Code,old 有效且 new 不存在才允许 Update 继续。两个普通团号、历史引用或多条矛盾关系均进入复核。 +- 同团同封的 standalone Trace 在信息系统内合并为一张候选卡,保留每条服务项和证据;跨封 Trace 绝不并入旧卡,Context 只以无自由文本的时间序摘要提供历史顺序。 +- Trace 的最终确认至少选择 `FO` 或 `HSK`,可同时选择二者;本期确认不触发部门流转。 + +## 6. 数据与事实源 + +- 新 Booking 主线的事实源是 PostgreSQL schema `th_hotel_booking`。处理运行、版本化契约、证据引用、候选、校验和确认投影均落入该 schema。 +- 旧 MySQL V4 数据仅作历史兼容读取;禁止未定义双写、跨库事务或把 MySQL 记录当作新主线事实源。 +- 每次读取 Context 必须按 Group Code、订单线索或已知 SourceMessage 定向查询;无目标线索时不能扫描全库找“最像”的订单。 +- 主数据(渠道白名单、sender → Account/Market/Source、Rate Code 映射)也是版本化事实。零候选、多候选和未配置均保留待用户补充,不能猜测。 + +## 7. 接口与并行工作边界 + +后续实现可以并行,但只能依赖 contracts-v1: + +- Track A:`BookingMessageOrchestrator` 和入口适配器。 +- Track B:Booking Agent profile、prompt、skill/reference 与离线 contract tests。 +- Track C:Context/lifecycle assembler。 +- Track D:PostgreSQL repository、Flyway、主数据与 processing run。 + +四条线不能直接依赖对方内部 Entity、Parser 私有 record 或 AgentBus payload。共享只通过 contracts-v1 的版本化数据结构、错误码和 evidence reference。 + +## 8. 实施前置与验收 + +G1 通过条件:信息系统、Agent、Context、数据库、Validator、前端和 QA 能在不引用旧 architecture-v0.3 的前提下,只基于 contracts-v1 明确输入、输出、版本字段、状态机、结果类型和失败边界后开始实现。 + +与现有 V0.1 的关系:V0.1 保留为受控纵向切片和回归基线;在 contracts-v1 适配完成前,不以其旧 V4 内部结构作为新模块之间的接口。 diff --git a/docs/project/requirements/booking-email-br00-contract-acceptance-matrix-v1.md b/docs/project/requirements/booking-email-br00-contract-acceptance-matrix-v1.md new file mode 100644 index 0000000..d9d1290 --- /dev/null +++ b/docs/project/requirements/booking-email-br00-contract-acceptance-matrix-v1.md @@ -0,0 +1,53 @@ +# BR00 业务类型 contracts-v1 验收矩阵 + +| 项目 | 内容 | +| --- | --- | +| 文档状态 | 当前有效 | +| 业务基线 | `BR00-BASELINE-1` | +| 契约版本 | `booking-contracts-v1` | +| 目的 | 把业务理解、契约、实现切片与验收证据对齐;不是旧 V4 卡片清单的替代品 | + +## 1. 共同判定规则 + +- 只由 current 邮件正文、当前附件和明确当前指令触发业务。quoted history 只用于理解、继承身份和重复提示。 +- `Name of Group`、`Group Name`、`Tour Code`、`Group Code` 都是**团号的来源别名**,统一标准化为唯一业务字段 `group_code`;不得把同一团号拆成四个独立身份字段。若有真正独立的展示名称,才可额外填 `group_name`;`tour_code` 仅保留兼容镜像,不能作为第二个目标。 +- 已知业务但字段缺失:保留原业务类型进入复核;不降格为 General/Risk。 +- 整封没有任何支持任务才产生一条 General。存在不可安全解释片段时每封最多一条 Risk;同封清晰任务继续生成。 +- 用户确认是本期终点。任何卡片、确认、Allotment source 关系、图片或付款说明都不得触发 PMS/Opera、付款核销或部门流转。 + +## 2. 类型矩阵 + +| 业务类型 | 识别与拆分 | Context 必要信息 | Validator / 确认阻断 | 当前实现状态与后续切片 | +| --- | --- | --- | --- | --- | +| `NEW_BOOKING` | 每个清晰预订目标一张候选;同一 `group_code` 下的多个房型/日期段可属于同一目标,不按团号别名误拆 | 是否已有同 Group Code/订单、sender 映射、Rate Code 候选 | Booking Type、可定位身份(`group_code` 或明确姓名)、入住/离店、房型+数量、Rate Code;Group 必须有 `group_code`,不要求凭空填写 `group_name`;房量未知不得推 FIT | 固定渠道纵向切片已存在;迁移到 contracts-v1/PostgreSQL 主线 | +| `UPDATE_BOOKING` | `AMEND`、`AMD`、`AMEND TO` 等归一;每封实际 Update、每个目标生成新的 Update 候选 | 目标当前确认态、有效未完成任务、old→new Group Code 链、revision | 目标必须唯一或由用户选择;前置 New/Update 关系、Cancel 后冲突、变更字段与证据 | 固定渠道纵向切片已存在;连续生命周期在 Phase 4 收口 | +| `CANCEL_BOOKING` | 当前邮件明确取消指令;不能把 quoted history 的旧 Cancel 再触发 | 目标当前态、未完成 Update/Cancel、关联证据 | 目标/前置链/重复判断;确认只是冻结取消参数,不结束订单 | 固定渠道纵向切片已存在;Cancel 后冲突在 Phase 4 收口 | +| `TRACE_RESERVATION_NOTES` | Extra Bed 是 Trace,不是房型;同一 Group Code、同一 current 邮件的多个 Trace 合并 | 同 Group/订单、相邻 lifecycle 任务、既有 Trace | Department 仅在邮件证据唯一明确时预填;否则确认前必须选 FO、HSK 或两者 | 基础卡已存在;文字/图片证据和跨封顺序在 Phase 4 收口 | +| `ROOMING_LIST` | 当前附件/正文表明房表事项;一 Group Code 一项 | 目标识别或未知目标线索 | 只展示/下载 Excel,不解析旅客、不改 DEF;Group Code 不明仍应生成目标未识别通知 | 原生通知卡已存在;材料展示和下载在 Phase 4 收口 | +| `PAYMENT` | 当前附件/图片/正文表明付款凭证或替换说明 | 目标识别、附件/图片与当前邮件的关联 | 只展示图片/替换说明;不核对到账、不改订单状态;目标不明保留通知 | 基础附件摘要已存在;图片路径在 Phase 4 收口 | +| `ALLOTMENT` | 每个 actual 团独立识别为 New;source 团与 actual 团的关系必须显式表达 | source 团当前库存/状态、每个 actual 的准入结果 | 先验证每个 actual;只汇总通过准入的房量给 source;source 不存在/不足不回滚安全 actual,只提示人工 | 未作为已完成切片;Phase 4 独立主线最后收口 | +| 图片 / Voucher 媒体 | 图片不是单独业务类型;结合 current 正文判断其支持 Trace、Payment/替换说明或不在范围 | 当前正文、附件关系、目标线索 | 证据不足不猜业务类型;可形成 Risk 或 General/ignored,不能自行创建“Voucher 订单” | Phase 4 与 Payment/图片一并完成 | +| `GENERAL_NOTIFICATION` | 整封 current 邮件经材料、Parser 和业务词典确认没有支持任务 | 仅消息级最小上下文 | 不得因已知业务缺字段而生成 General | 基础通知已有;迁移后由 contracts-v1 统一输出 | +| `RISK_NOTIFICATION` | 业务类型、目标、材料或 Parser 结论有不可消解歧义 | 受影响目标/材料/历史摘要 | 每封最多一张;只隔离歧义片段;Agent invalid 也必须经 Validator 进入 Risk | 基础通知已有;目标级隔离在 Phase 3 收口 | +| `IGNORED_DIRECTION` | 可确定为酒店外发、内部邮件或不属于处理范围 | 邮件方向、sender/recipient、受控规则 | 不创建待办或业务卡,保留安全处理记录 | 新 contracts-v1 主线能力,随 Orchestrator 实现 | + +## 3. 核心样例到契约的断言 + +| 场景 | 必须形成的事实 | 禁止推断 | +| --- | --- | --- | +| `【U-TWN8.5】 12` | 房型线索 `U-TWN`、价格证据 `850`、数量 `12`;与备注共同形成当前动作线索 | 不从价格直接猜 Rate Code | +| `【U-TWN】 6)(850...)` | 房型线索 `U-TWN`、数量 `6`、价格证据 `850` | 不因格式差异丢失 New Booking 语义 | +| `NEW BOOKING ยกเลิก` 与 `NEW BOOKING CXL` | Parser 可保留动作候选及原始证据;业务/生命周期最终解释由 Catalog+Context+Validator | 不穷举所有自然语言组合后把未覆盖文本静默当普通 New | +| Excel 非白底整行 | 严格候选行和行/列/Sheet 证据 | 不能靠任意一个底色单元格、字体颜色或多行互补建立确定事实 | +| 无附件 current 邮件 | `MaterialPackage(NO_ATTACHMENT)`,仍进入 Context 和业务识别 | 不能绕过 SourceMessage 或直接生成 General | +| 同一信息再次出现 | 重复/陈旧提示与消息幂等证据 | 不能静默丢弃真实新邮件或把两封邮件强行合并 | + +## 4. 验收最低集 + +每个业务类型在实现完成前都必须至少有: + +1. 一个去隐私的 contracts-v1 正例与一个错误/歧义例。 +2. Parser、Agent(如适用)和 Validator 对同一输入的版本、evidence reference 与目标范围断言。 +3. PostgreSQL `th_hotel_booking` 的 processing run、候选、校验和确认投影持久化断言。 +4. 前端的展示/阻断/确认行为断言;确认后不产生 PMS/Opera、付款或部门副作用。 +5. 对应真实或脱敏 E2E 样例;真实邮件只通过 opt-in 路径读取。 diff --git a/docs/project/requirements/booking-email-contracts-v1.md b/docs/project/requirements/booking-email-contracts-v1.md new file mode 100644 index 0000000..513bdca --- /dev/null +++ b/docs/project/requirements/booking-email-contracts-v1.md @@ -0,0 +1,168 @@ +# Booking 邮件 contracts-v1 + +| 项目 | 内容 | +| --- | --- | +| 文档状态 | 权威契约 | +| 契约版本 | `booking-contracts-v1` | +| 对应架构 | [Booking 邮件处理架构 v0.4](booking-email-architecture-v0.4.md) | +| 适用终点 | 用户确认;PMS/Opera 不在本契约执行范围 | + +## 1. 共同信封与版本规则 + +七层之间传递的每个顶层对象必须包含 `contract_meta` 和 `evidence_refs[]`。禁止靠调用方上下文、数据库隐式默认值或 Agent prompt 隐式补齐版本。 + +| 字段 | 必填 | 说明 | +| --- | --- | --- | +| `contract_version` | 是 | 固定 `booking-contracts-v1`。不兼容变更必须新版本。 | +| `catalog_version` | 是 | 本次使用的业务目录版本;尚未执行目录处理时填 `catalog-not-applied`。 | +| `parser_version` | 是 | 本次 Parser 版本;未执行时填 `parser-not-run`。 | +| `agent_profile_version` | 是 | Booking Agent profile 版本;未调用时填 `agent-not-invoked`。 | +| `processing_run_id` | 是 | 一次处理运行的稳定 ID,重试使用同一 run、不同 attempt。 | +| `source_message_id` | 是 | 平台 SourceMessage 的稳定 ID;不可使用邮件主题代替。 | +| `source_revision` | 是 | 同一来源消息在材料重取或重放后的可追溯版本。 | +| `evidence_refs` | 是 | 最小化证据引用;不嵌入原始邮件、完整附件、Secret 或外链 URL。 | + +`evidence_ref` 至少包含 `evidence_id`、`kind`、`source_message_id`、`locator`、`content_hash`、`is_current_material`。`kind` 允许 `CURRENT_BODY`、`QUOTED_HISTORY`、`ATTACHMENT`、`WORKBOOK_SHEET`、`WORKBOOK_ROW`、`IMAGE`、`OCR_TEXT`、`CONTEXT_RECORD`、`USER_CORRECTION`。`locator` 只能表达安全定位(例如 Sheet/行号、附件逻辑 ID、上下文记录 ID),不能含签名 URL 或原文全文。 + +所有 issue 使用同一结构:`code`、`severity`(`INFO`/`WARNING`/`BLOCKER`)、`scope`(`MESSAGE`/`MATERIAL`/`TARGET`/`FIELD`)、`message_key`、`evidence_refs[]`、可选 `retryable`。用户可见文本由 `message_key` 和前端文案生成,避免把原文写进 API。 + +## 2. SourceMessageEnvelope + +**层 1 输出。** 统一 AgentBus 与手工 EML,不携带业务判断。 + +| 字段 | 说明 | +| --- | --- | +| `message_origin` | `AGENTBUS` 或 `MANUAL_EML`。 | +| `external_message_id`、`conversation_id`、`in_reply_to` | 邮件身份与会话链路;缺失时保留 null,不用主题猜。 | +| `idempotency_key` | 基于可信消息身份/内容摘要形成;只处理外部重复投递,不合并两封真实邮件。 | +| `sender`、`recipients`、`subject` | 最小化安全摘要或受控引用;不作为唯一业务事实。 | +| `received_at` | 收件时间点(UTC)。 | +| `current_body_ref`、`quoted_history_ref` | 对正文 current/history 分离后的证据引用。 | +| `attachment_descriptors[]` | 逻辑附件 ID、文件名摘要、媒体类型、大小、内容哈希、受控原件引用。 | + +不可接受:入口直接调用 Parser/Agent 后跳过 SourceMessage、入口把 AgentBus 的原始 JSON 当领域对象、或根据邮件主题创建订单。 + +## 3. MaterialPackage + +**层 2 输出。** 描述可供解析/理解的材料,不表达最终业务类型。 + +| 字段 | 说明 | +| --- | --- | +| `message_envelope` | `SourceMessageEnvelope` 的最小必要摘要与 ID。 | +| `current_materials[]` | 本次可触发业务的 current body、当前附件、当前图片、明确版本指令。 | +| `quoted_history_materials[]` | 仅用于解释、继承身份、重复检查的历史材料。 | +| `workbook_inspections[]` | 文件哈希、Sheet 名称、表头签名、候选行/列、底色证据、Profile 候选与检测结果。 | +| `image_inspections[]` | 图片证据与可选 OCR 安全摘要;不把 OCR 当唯一事实。 | +| `material_selection_status` | `READY`、`NO_ATTACHMENT`、`UNSUPPORTED`、`AMBIGUOUS`、`FAILED`。 | +| `issues[]` | 材料层问题,例如超限、文件损坏、多个 Profile 平分、非法 Sheet。 | + +规则:current 与 quoted 必须可区分;没有附件时输出 `NO_ATTACHMENT` 但仍为有效 package;固定渠道只把严格候选行送入确定性 Parser,其他行只能作为复核证据。 + +## 4. ParsedFactSet + +**层 3 输出。** Parser 的标准事实集合;它不等于最终业务决定。 + +| 字段 | 说明 | +| --- | --- | +| `parser_applicability` | `APPLICABLE`、`NOT_APPLICABLE`、`FAILED`、`AMBIGUOUS`。 | +| `channel_profile_code` | 成功解析时的固定渠道 Profile;不能唯一确定时为 null。 | +| `facts[]` | 可追溯的标准事实,必须逐项带 `fact_id`、`confidence_kind=DETERMINISTIC`、`evidence_refs[]`。 | +| `unresolved_fields[]` | 未能确定的字段及原因;未知房量、Rate Code 映射等必须保留。 | +| `fallback_reasons[]` | 需要 Booking Agent 或 Risk 的明确原因代码。 | +| `issues[]` | Profile、底色、字段格式、解析失败等问题。 | +| `agent_input_material` | 可选、受控的 Agent current-message 文本;只在本地 policy 脱敏、限长后出现。 | + +`facts[]` 的稳定字段包括: + +- `action_hint`:`NEW_BOOKING`、`UPDATE_BOOKING`、`CANCEL_BOOKING` 或 null;`booking_type` 只在房量足以确定时为 `FIT`/`GROUP`,否则为 null。 +- `target_identity`:`group_code` 是团号统一字段;`Name of Group`、`Group Name`、`Tour Code`、`Group Code` 进入该字段。`group_name` 只用于邮件明确给出的独立展示名称;`tour_code` 是历史兼容镜像,不能与 `group_code` 形成两个目标。`name_values` 只保存真正的客人/联系人姓名;字段未知必须为 null。 +- `stay`:`arrival_date`、`departure_date`、`nights`、`room_items[]`、价格原始证据。 +- `room_items[]`:`room_type_code_hint`、`room_count`、`rate_hint`、`evidence_refs[]`;Extra Bed 不能写入房型。 +- `related_hints[]`:Trace、Rooming List、Payment、Allotment source/actual、明确 `GROUP_CODE_REPLACEMENT` old→new 关系等候选线索。 + +`agent_input_material` 是为了让 Parser fallback 能理解无固定渠道的正文,而不是第二份原始邮件:它只能绑定一个 `CURRENT_BODY` evidence,内容仅来自 current subject/body,按 `booking-agent-current-message-v1` 脱敏并限制为最多 12,000 个 code point。它必须排除 quoted history、原始附件、附件 URL、sender 原文和 Secret;该受控摘要可随 `PARSED_FACT_SET` 在项目 schema 保留至 `retention_until`,以支持同一 run 的异步 Agent/retry,不得用它还原原始邮件。 + +`GROUP_CODE_REPLACEMENT` 只接受 current body 中明确标注的 old→new 指令。单封普通文本中出现两个团号、主题猜测或 quoted history 都不能生成关系。该 relation 在 Parser fallback 中是无动作 Context/Agent clue;固定渠道仅能绑定到同一 new group code 的 `UPDATE_BOOKING` fact。 + +Parser 不得:将 `room_count=0` 解释为 FIT、在 Profile 平分/未知/非法 Sheet 时产生确定事实、用多行互补制造 anchor 事实、或因字段缺失把已知动作改写成 General/Risk。 + +## 5. ContextPackage + +**层 4 输出。** 面向一封当前邮件与已识别目标的最小上下文,而不是历史全量 dump。 + +| 字段 | 说明 | +| --- | --- | +| `context_scope` | `MESSAGE` 或一个/多个 `TARGET`;每个 target 有独立查询边界。 | +| `target_resolutions[]` | 输入线索、零/一/多候选、解析状态和证据;多候选不自动选择。 | +| `current_state` | 已确认事实、有效未完成任务、计划完成态;带数据来源与更新时间。 | +| `conversation_context` | 当前邮件的必要历史摘要、revision 关系与重复线索;历史内容不重新触发动作。 | +| `lifecycle_context` | New/Update/Cancel 前置链、old→new Group Code、Cancel 后冲突、Trace 顺序。 | +| `allotment_context` | source 团与 actual 团候选关系、库存/扣减可用性;不是最终扣减命令。 | +| `issues[]` | 上下文缺失、多目标冲突、历史证据冲突等。 | + +读取规则:优先 Group Code、明确订单 ID、已确认消息关联;无可靠目标时返回未识别,而不是全文/全库模糊扫描。 + +当 `GROUP_CODE_REPLACEMENT` 存在时,Context 必须只读取 old/new 两个明确 Group Code:old 有效已确认链且 new 不存在才是 `RESOLVED`;old 已取消/不存在为 `UNRESOLVED`,new 已存在为 `CONFLICT`。`group_code_replacements[]` 必须保留 relation ID、old/new、状态、候选 ID 和 issue。Trace 历史按 Group Code 和时间顺序只提供安全摘要(任务 ID、状态、FO/HSK、服务类型);跨封 Trace 永远是新卡,历史自由文本、附件定位和 quoted 内容不能进入 Context。 + +## 6. CandidateDecision + +**层 5 输出。** 可以来自纯确定性合成或 Booking Agent;两者使用同一结构。 + +| 字段 | 说明 | +| --- | --- | +| `decision_origin` | `DETERMINISTIC`、`AGENT`、`MIXED`。 | +| `result_disposition` | `IN_SCOPE_TASKS`、`GENERAL_NOTIFICATION`、`RISK_NOTIFICATION`、`IGNORED_DIRECTION`。 | +| `target_decisions[]` | 每个目标独立的候选动作、目标身份、字段、linked/derived actions、证据和 issues。 | +| `message_notifications[]` | General/Risk/ignored 的消息级结果;Risk 每封最多一条。 | +| `agent_trace_ref` | Agent 调用 ID/版本/安全摘要;纯 Parser 时为空。 | +| `issues[]` | 对整封消息的无法分配问题。 | + +`target_decision` 的 `business_type` 为:`NEW_BOOKING`、`UPDATE_BOOKING`、`CANCEL_BOOKING`、`TRACE_RESERVATION_NOTES`、`ROOMING_LIST`、`PAYMENT`、`ALLOTMENT`;`action_kind` 由业务类型和当前态决定。Allotment 必须显式输出 actual 与 source 的关联,不能把多个 actual 或 source 扣减隐匿在一张普通 New 卡里。 + +Booking Agent 的受控输入只允许 `ParsedFactSet + ContextPackage`;`ParsedFactSet.agent_input_material` 是唯一可见的正文材料,且受上文 policy 约束。若 Parser `NOT_APPLICABLE` 或 `FAILED`,也必须先创建最小的 `ParsedFactSet`,明确未解析原因,而不是把原始附件或 quoted history 直接交给 Agent。 + +## 7. ValidationResult + +**层 6 的校验输出。** 只有 `validation_status=VALID` 的目标才可产生确认投影。 + +| 字段 | 说明 | +| --- | --- | +| `validation_status` | `VALID`、`REVIEW_REQUIRED`、`RISK`、`REJECTED`。 | +| `validated_targets[]` | 目标级通过/阻断结果,不让一个目标阻断同封其他清晰目标。 | +| `schema_checks[]` | contracts-v1 结构和版本检查。 | +| `business_checks[]` | Catalog、必填、目标、生命周期、前置任务、linked action、重复/revision 检查。 | +| `blockers[]` | 必须由用户补齐或修复才可确认的条目。 | +| `risk_notification` | 仅隔离无法安全决定的部分;每封至多一张。 | + +Validator 必须校验:版本一致性、证据存在、目标解析、字段必填、Catalog 映射、当前生命周期、已确认/未完成任务、外部重复投递、真实新邮件、revision、历史底色遗留和业务内容相同。Agent 输出无效时,目标级进入 Risk,不能绕过 Validator 建卡。 + +## 8. ConfirmationProjection + +**层 6 面向前端的安全输出。** 它不是原始 CandidateDecision 的直通 JSON。 + +| 字段 | 说明 | +| --- | --- | +| `projection_status` | `AWAITING_CONFIRMATION`、`REVIEW_REQUIRED` 或不可生成。 | +| `confirmation_items[]` | 用户可见任务/通知,按目标拆分。 | +| `display_fields[]` | 已归一化的关键字段、展示值、来源证据、可编辑性与校验规则。 | +| `blocked_fields[]` | 缺失/冲突字段及需用户选择的候选;不暴露内部 payload。 | +| `linked_actions[]` | 如 Allotment source/actual、Trace 合并关系;只显示本期可确认参数。 | +| `safe_evidence[]` | 文件/Sheet/行/图片等安全引用与脱敏摘要。 | +| `processing_run` | run ID、当前状态、可重试状态与安全错误摘要。 | + +确认 API 只冻结用户确认的参数和审计,必须携带 `processing_run_id` 与并发版本。确认成功不调用 PMS/Opera,也不执行付款、库存扣减或部门流转。 + +## 9. 编排、持久化与 API 约束 + +1. AgentBus 与手工 EML 都调用同一个 `BookingMessageOrchestrator`,并产生一致的 `SourceMessageEnvelope` 幂等语义。 +2. 同步完成且无需异步 Agent 时返回 `201`;进入 Agent 或异步处理时返回 `202` 与 `processing_run_id`。 +3. 状态查询为 `GET /api/reservation/booking-processing-runs/{runId}`;已有 `POST /api/reservation/booking-email-intakes` 逐步适配为统一入口。 +4. PostgreSQL `th_hotel_booking` 保存 run、attempt、版本、证据引用、候选、校验和确认投影;`PARSED_FACT_SET` 中只允许保存受 policy 约束的 Agent 摘要,所有这些项目 schema 数据按 `retention_until` 三个月清理。旧 MySQL 只能被 Context 兼容读取,不能参与新主线写入或跨库事务。 +5. 所有持久化/接口代码必须使用 `contract_version` 做版本门禁;未知未来版本 fail closed 并形成安全 Risk/技术错误记录。 + +## 10. 兼容与测试要求 + +- Parser 与 Booking Agent 对相同事实必须输出可比较的 `CandidateDecision`;差异只能通过显式 `decision_origin` 和 issue 表达。 +- 每个 Contract 都需 JSON/Java fixture、schema validation、正向/错误案例及 evidence reference 检查。 +- 真实邮件只作为 opt-in 外部验收;仓库只保存去隐私 fixture 与样本哈希/Profile 断言。 +- 后续对字段、枚举、状态机或业务动作做破坏性变更时,必须新增 contracts-v2,而不是静默改 v1。