# 前端提醒后端待补接口

## 1. 文档定位

本文记录前端页面开发时希望后端新增、补齐或稳定的接口草案。本文中的路径、入参和返参是前端视角的最小诉求，不代表后端已经承诺实现；进入开发前需要后端按当前包结构、权限、安全和业务规则二次确认。

## 2. 当前待补接口总览

| 优先级 | 接口 | 页面 / 场景 | 状态 |
| --- | --- | --- | --- |
| P0 | 订单列表接口 `GET /api/reservation/orders` | 订单列表页、首页工作台 | 已完成第一版 |
| P0 | 任务列表接口 `GET /api/reservation/tasks` | 任务列表菜单、订单详情任务入口 | 已完成第一版，已补来源邮件会话字段和 `order_status` 筛选 |
| P0 | 订单详情接口 `GET /api/reservation/orders/{orderId}` | 订单详情页 | 已完成第一版，已补 `tasks[]` 每个任务的来源邮件会话字段 |
| P0 | 任务详情读取接口 `GET /api/reservation/tasks/{taskId}` | 任务详情页动态渲染 | 已完成第一版，已补来源邮件字段和 3.0 字段元数据 |
| P0 | 任务详情操作接口 | 任务详情保存、确认、OPERA、审计 | 已完成；前端可直接接入 |
| P0 | 邮件会话详情接口 `GET /api/source-messages/{sourceMessageId}/conversation` | 邮件会话详情页 | 已完成第一版 |
| 联调 | 演示数据 seed 接口 `POST /api/system/reservation/demo-data` | 本地 / test 前端页面看效果 | 已完成；仅 dev/test 受控使用 |
| 联调 | Debug EML 上传接口 `POST /api/system/debug/eml-superagent-runs` | Debug 页面上传 `.eml` 看 SuperAgent 结果 | 已完成第一版；仅 dev/test 受控使用 |
| P1 | S10/S99 源邮件只读通知卡与旧 S000/S999 兼容 | 任务列表、任务详情来源邮件查看 | 已完成第一版：旧 S000/S999 兼容，新结构化 S10/S99 可入站并在任务列表 / 详情只读展示 |
| P1 | type-known manual review 同卡复核解阻 | 任务详情复核 | 已完成第一版：原业务任务卡复核、字段修正、订单归属确认、READY 流转 |
| P1 | 任务卡前端字段白名单元数据接口 | 字段白名单调试、版本对齐 | 未完成；若任务详情已透出完整元数据，可后置 |
| 后置 | 普通任务切换订单接口 | 任务详情订单归属调整 | 未完成；已确认后置 |

## 2.1 后端当前接口完成度核对

本节按 2026-07-08 当前后端 Controller 和 result record 核对，避免重复要求后端实现已经存在的接口。

| 接口 / 能力 | 当前后端状态 | 前端是否可直接接入 | 仍需后端处理 |
| --- | --- | --- | --- |
| `GET /api/reservation/tasks` | 已完成第一版，已补来源邮件会话字段和所属订单状态筛选 | 可以 | `order_status` 按任务所属订单状态过滤；不传时保持当前全部任务列表行为。 |
| `GET /api/reservation/orders/{orderId}` | 已完成第一版，已补 `tasks[]` 来源邮件会话字段 | 可以 | 暂无。 |
| `GET /api/reservation/tasks/{taskId}` | 已完成第一版，已补任务顶层来源邮件字段和 `fields[]` 3.0 元数据 | 可以 | 当前 Controller 不接收 `hotel_id`；如后续多酒店隔离需要前端显式传酒店上下文，请后端补可选入参或确认按 taskId 全局唯一即可。 |
| `PUT /api/reservation/tasks/{taskId}/draft` | 已完成 | 可以 | 当前 Controller 不接收 `hotel_id`；如写操作需要酒店上下文幂等 / 权限校验，请后端补可选入参或请求体字段。 |
| `POST /api/reservation/tasks/{taskId}/confirm` | 已完成 | 可以 | 当前 Controller 不接收 `hotel_id`；如写操作需要酒店上下文幂等 / 权限校验，请后端补可选入参或请求体字段。 |
| `GET /api/reservation/tasks/{taskId}/audits` | 已完成 | 可以 | 当前 Controller 不接收 `hotel_id`；如审计查询需要酒店上下文隔离，请后端补可选入参。 |
| `POST /api/reservation/tasks/{taskId}/opera-operations/{operationId}/execute` | 已完成第一版模拟操作 | 可以 | 暂无；真实 OPERA 写入另行确认。 |
| `POST /api/reservation/tasks/{taskId}/opera-operations/{operationId}/retry` | 已完成第一版模拟重试 | 可以 | 暂无；真实 OPERA 重试另行确认。 |
| `POST /api/reservation/tasks/{taskId}/manual-review-conversions` | 已完成 | 可以 | 暂无。 |
| `POST /api/reservation/tasks/{taskId}/manual-review-resolutions` | 已完成第一版 | 可以 | 只用于 type-known manual review；第一版 `confirmed_order_id` 必须等于当前任务订单，不开放普通任务任意切换订单。 |
| `GET /api/source-messages` | 已完成安全摘要列表 | 可以 | 不能替代邮件会话全文接口。 |
| `GET /api/source-messages/{id}` | 已完成单条安全摘要 | 可以 | 不能替代邮件会话全文接口。 |
| `GET /api/source-messages/{id}/original` | 已完成单封原文受控读取 | 谨慎接入 | 只能读单封邮件，不能返回同一 conversation 全量邮件。 |
| `GET /api/reservation/orders` | 已完成第一版 | 可以 | 默认查询全部订单状态；`open_task_count` 排除 `COMPLETED` 和 `FAILED`。 |
| `GET /api/source-messages/{sourceMessageId}/conversation` | 已完成第一版，已补 `html_body_sanitized` 和 `html_render_mode` | 可以 | 返回完整 text/html、后端清洗后的 HTML、媒体外链和关联订单 / 任务摘要；前端不传原文读取 key，页面展示优先使用 `html_body_sanitized`。 |
| `POST /api/system/reservation/demo-data` | 已完成 | 仅本地 / test 联调可用 | 默认关闭，必须后端配置访问口令；不能作为生产页面接口。 |
| `POST /api/system/debug/eml-superagent-runs` | 已完成第一版 | 仅 dev/test Debug 页面可用 | 默认关闭，必须后端配置访问口令、阿里云 OSS 和 SuperAgent Open API；第一版只展示 SuperAgent 结果，不创建订单和任务；已能识别旧 S000/S999 和新结构化 S10/S99。 |
| `GET /api/source-message-conversations/{externalConversationId}` | 未发现后端实现 | 不可以 | 历史讨论过的候选路径，当前不提供；前端统一使用 `GET /api/source-messages/{sourceMessageId}/conversation`。 |
| `GET /api/reservation/message-notifications` | 未发现后端实现 | 不可以 | 第一版不做独立接口；旧 S000/S999 已通过 `SOURCE_MESSAGE_ONLY` 任务展示，0711 P0 新 S10/S99 也继续复用任务列表 / 任务详情只读展示。 |
| `GET /api/reservation/task-card-field-whitelist` | 未发现后端实现 | 不可以 | 若任务详情 `fields[]` 已补齐 3.0 元数据，可后置。 |

## 3. 任务列表 / 工作台接口字段补齐

建议路径：

```text
GET /api/reservation/tasks
```

当前状态：后端已按 P0 最小诉求实现第一版，前端任务列表页可以直接接入该接口。接口已返回任务摘要、订单展示键、来源消息 ID / 主题、来源邮件会话摘要和实时可处理状态，不返回完整 AI payload、邮件正文或附件 URL。

本轮前端新增“任务列表”菜单，并且任务列表、订单详情任务队列都需要能跳转到该任务来源消息所在的完整邮件会话。因此建议在现有返回项上补齐来源邮件会话摘要字段。

已完成字段：

| 字段 | 说明 |
| --- | --- |
| `task_id` | 任务 ID。 |
| `order_id` | 关联订单 ID。 |
| `hotel_id` | 酒店上下文 ID。 |
| `display_order_key` | 前端优先展示的业务号或临时订单号。 |
| `temporary_order_no` | 临时订单号。 |
| `task_type` | 系统主任务类型。 |
| `result_type` | AI 结果类型，例如 `normal_task`、`manual_review`、`source_message_review_notification`。 |
| `ai_task_type` | SuperAgent 原始任务类型，例如 `New Booking`、`S10`、`S99`。 |
| `task_subtype` | 任务 subtype。 |
| `route_code` | M002 V3 路由码，例如 `R01_NEW_FIT_RESERVATION_NORMAL`、`S10`、`S99`。 |
| `system_process_category` | 系统处理分类，例如 `BUSINESS_TASK`、`SOURCE_MESSAGE_NOTIFICATION`。 |
| `task_status` | 任务状态。 |
| `card_name` | 任务卡展示名称。 |
| `queue_sequence` | 同订单队列顺序。 |
| `queue_participation` | 是否参与订单执行队列。 |
| `can_process` | 当前是否可处理。 |
| `readonly_reason_code` | 只读原因代码。 |
| `source_message_id` | 来源 SourceMessage Inbox ID。 |
| `source_subject` | 来源消息主题摘要。 |
| `created_at` | 任务创建时间。 |
| `updated_at` | 任务更新时间。 |

建议入参：

| 参数 | 必填 | 说明 |
| --- | --- | --- |
| `hotel_id` | 否 | 酒店 ID。单酒店阶段默认可为空，由后端按当前用户上下文或平台酒店表唯一 `ACTIVE` 酒店解析；显式传值时后端会校验访问权限。 |
| `order_id` | 否 | 按订单过滤。 |
| `task_type` | 否 | 当前任务列表筛选只提供 `NEW_BOOKING`、`UPDATE_BOOKING`、`CANCEL_BOOKING`、`MANUAL_REVIEW`、`SOURCE_MESSAGE_ONLY`；不再提供历史 `INFORMATIONAL_MESSAGE` 筛选项。0711 P0 结构化 S10/S99 复用 `SOURCE_MESSAGE_ONLY` 只读源邮件通知卡。 |
| `task_status` | 否 | 任务状态过滤。 |
| `task_subtype` | 否 | 任务卡 subtype 过滤。 |
| `order_status` | 否 | 按任务所属订单状态过滤，支持 `TEMPORARY`、`ACTIVE`、`ENDED`、`LOGIC_DELETED`；不传时保持当前行为。 |
| `queue_participation` | 否 | 是否参与订单执行队列。 |
| `keyword` | 否 | Group Code、Confirmation No、临时订单号、来源消息安全摘要关键词。 |
| `page_num` | 否 | 页码，建议从 1 开始。 |
| `page_size` | 否 | 每页条数。 |

建议返参：

```json
{
  "items": [
    {
      "task_id": "10001",
      "order_id": "20001",
      "hotel_id": "HOTEL-TEST",
      "display_order_key": "GRP-001",
      "temporary_order_no": "TMP-20260708-001",
      "task_type": "UPDATE_BOOKING",
      "result_type": "normal_task",
      "ai_task_type": "Payment Evidence",
      "task_subtype": "payment_evidence",
      "route_code": "R10_PAYMENT_EVIDENCE_NORMAL",
      "system_process_category": "BUSINESS_TASK",
      "task_status": "PENDING_CONFIRM",
      "card_name": "Payment Evidence",
      "queue_sequence": 2,
      "queue_participation": true,
      "can_process": false,
      "readonly_reason_code": "PREVIOUS_TASK_NOT_FINISHED",
      "source_message_id": "30001",
      "source_subject": "Booking Update",
      "source_sender_summary": "guest@example.com",
      "source_received_at": "2026-07-08T02:58:00Z",
      "external_conversation_id": "thread-20260708-001",
      "conversation_message_count": 6,
      "created_at": "2026-07-08T03:00:00Z",
      "updated_at": "2026-07-08T03:10:00Z"
    }
  ],
  "page": {
    "page_num": 1,
    "page_size": 20,
    "total": 1
  }
}
```

本轮已新增字段：

| 字段 | 说明 |
| --- | --- |
| `source_sender_summary` | 来源消息发件人展示值，当前不打码，用于任务列表快速判断来源。 |
| `source_received_at` | 邮件来源接收时间，优先取 AgentBus payload `received_at`，用于任务列表排序和展示。 |
| `external_conversation_id` | 来源消息所属邮件会话 ID，用于打开完整邮件会话详情。 |
| `conversation_message_count` | 会话内邮件数量，用于提示用户该入口是整段会话，不是单封邮件。 |
| `result_type` / `ai_task_type` / `route_code` / `system_process_category` | V3 路由展示字段，用于任务卡标签、筛选和 S10/S99 只读卡判断。 |

## 4. 订单详情与任务时间线接口字段补齐

建议路径：

```text
GET /api/reservation/orders/{orderId}
```

当前状态：后端已按 P0 最小诉求实现第一版。接口返回订单摘要和同订单任务时间线；`include_tasks=false` 时只返回订单摘要。任务时间线已补齐每个任务的来源邮件会话摘要。

订单详情低保真已确认沿用“订单摘要 + 同订单任务队列 + 当前任务卡 + OPERA 模拟操作 + 审计时间线”。同订单任务队列里的每个任务都需要自己的“查看邮件会话”入口，因为不同任务可能来自不同邮件或不同邮件会话。因此建议补齐 `tasks[]` 中每个任务的来源邮件会话字段。

建议入参：

| 参数 | 必填 | 说明 |
| --- | --- | --- |
| `orderId` | 是 | 订单 ID。 |
| `hotel_id` | 否 | 酒店 ID。单酒店阶段默认可为空，由后端解析；显式传值时后端会校验访问权限。 |
| `include_tasks` | 否 | 是否返回任务时间线，默认 `true`。 |
| `include_source_summary` | 否 | 是否返回来源消息摘要，默认 `true`；第一版参数保留，前端暂不要依赖它做字段裁剪。 |

建议返参：

```json
{
  "order": {
    "order_id": "20001",
    "hotel_id": "HOTEL-TEST",
    "order_status": "ACTIVE",
    "temporary_order_no": "TMP-20260708-001",
    "confirmation_number": "CNF123456",
    "group_code": "GRP-001",
    "block_code": null,
    "allotment_code": null,
    "display_name": "GRP-001",
    "created_at": "2026-07-08T03:00:00Z",
    "updated_at": "2026-07-08T03:10:00Z"
  },
  "tasks": [
    {
      "task_id": "10001",
      "task_type": "NEW_BOOKING",
      "result_type": "normal_task",
      "ai_task_type": "New Booking",
      "task_subtype": "NEW_BOOKING",
      "route_code": "R01_NEW_FIT_RESERVATION_NORMAL",
      "system_process_category": "BUSINESS_TASK",
      "task_status": "COMPLETED",
      "card_name": "New Booking",
      "queue_sequence": 1,
      "queue_participation": true,
      "can_process": false,
      "readonly_reason_code": "TASK_FINISHED",
      "source_message_id": "30001",
      "source_subject": "Booking Request",
      "source_sender_summary": "guest@example.com",
      "source_received_at": "2026-07-08T02:58:00Z",
      "external_conversation_id": "thread-20260708-001",
      "conversation_message_count": 6,
      "created_at": "2026-07-08T03:00:00Z"
    }
  ],
  "warnings": []
}
```

本轮已新增字段：

| 字段 | 说明 |
| --- | --- |
| `source_message_id` | 任务对应的来源 SourceMessage Inbox ID。 |
| `source_subject` | 来源消息主题摘要。 |
| `source_sender_summary` | 来源消息发件人展示值，当前不打码。 |
| `source_received_at` | 邮件来源接收时间，优先取 AgentBus payload `received_at`。 |
| `external_conversation_id` | 来源消息所属邮件会话 ID。 |
| `conversation_message_count` | 会话内邮件数量。 |
| `result_type` / `ai_task_type` / `route_code` / `system_process_category` | V3 路由展示字段，和任务列表字段语义一致。 |

## 5. 订单列表接口

建议路径：

```text
GET /api/reservation/orders
```

当前状态：后端已完成第一版。默认查询全部订单状态；`open_task_count` 排除 `COMPLETED` 和 `FAILED`，`next_processable_task_id` 按同订单队列可处理状态实时计算。

建议入参：

| 参数 | 必填 | 说明 |
| --- | --- | --- |
| `hotel_id` | 否 | 酒店 ID。单酒店阶段默认可为空，由后端解析；显式传值时后端会校验访问权限。 |
| `order_status` | 否 | `TEMPORARY`、`ACTIVE`、`ENDED`、`LOGIC_DELETED`。 |
| `group_code` | 否 | 按 Group Code 精确或模糊查询，后端决定。 |
| `confirmation_number` | 否 | 按 Confirmation No 查询。 |
| `keyword` | 否 | 前端搜索框统一关键词；后端匹配订单字段，也会匹配来源消息安全摘要命中的 SourceMessage ID。 |
| `page_num` | 否 | 页码。 |
| `page_size` | 否 | 每页条数。 |

建议返参：

```json
{
  "items": [
    {
      "order_id": "20001",
      "hotel_id": "HOTEL-TEST",
      "order_status": "ACTIVE",
      "display_order_key": "GRP-001",
      "temporary_order_no": null,
      "confirmation_number": "CNF123456",
      "group_code": "GRP-001",
      "display_name": "GRP-001",
      "open_task_count": 2,
      "next_processable_task_id": "10002",
      "updated_at": "2026-07-08T03:10:00Z"
    }
  ],
  "page": {
    "page_num": 1,
    "page_size": 20,
    "total": 1
  }
}
```

## 6. 前端联调演示数据 seed 接口

建议路径：

```text
POST /api/system/reservation/demo-data
```

当前状态：后端已完成第一版。该接口只用于本地 / test 联调造数，默认关闭，不是生产业务页面接口。

启用条件：

| 配置 | 说明 |
| --- | --- |
| `reservation.demo-data.enabled=true` | dev 默认开启；test 需显式启用，也可用环境变量 `RESERVATION_TEST_DEMO_DATA_ENABLED=true`。 |
| `reservation.demo-data.access-key` | 配置访问口令；dev 优先使用 `RESERVATION_DEV_DEMO_DATA_ACCESS_KEY`，test 优先使用 `RESERVATION_TEST_DEMO_DATA_ACCESS_KEY`，旧通用变量 `RESERVATION_DEMO_DATA_ACCESS_KEY` 仅作为兼容兜底。 |
| `X-TH-Hotel-Demo-Data-Key` | 请求头必须携带，与后端配置口令一致。 |

请求示例：

```json
{
  "run_label": "frontend-smoke"
}
```

返回说明：

| 字段 | 说明 |
| --- | --- |
| `demo_run_id` | 本次 seed 唯一关键词，可用于任务列表 / 订单列表搜索。 |
| `source_messages[]` | 生成的来源消息 ID、外部消息 ID 和外部会话 ID。 |
| `orders[]` | 生成的订单 ID、订单状态和展示键。 |
| `tasks[]` | 生成的任务 ID、任务类型、任务 subtype 和任务状态。 |
| `entrypoints` | 可直接访问的任务列表、订单列表、订单详情、任务详情、邮件会话详情 URL。 |

第一版 seed 覆盖：队列阻塞、已完成 OPERA 模拟、OPERA 失败可重试、Fallback 人工复核、历史 Message Notification 只读任务、邮件会话完整 HTML / 附件 / 内联图片。旧 S000/S999 特殊只读任务可通过 SuperAgent 回调补充；0711 P0 新入口的 S10/S99 已纳入后端 P0 fixtures 回归测试参考。

## 6.1 M002 V3 当前状态和后续待补能力

本节记录 0711 P0 基线确认后，前端关心的 V3 能力状态。已完成项可以直接接入；后置项需要另开 checkpoint。

| 能力 | 页面 / 场景 | 状态 | 前端最小诉求 |
| --- | --- | --- | --- |
| 结构化 `S10/S99` 入站 | 任务列表、任务详情、Debug EML 结果展示 | 已完成第一版 | 后端接收 `result_type=source_message_review_notification + route_code=S10/S99`，创建只读源邮件通知卡；任务列表可见，订单列表不可见；返回 `route_code`、入口说明、`agent_assessment`、`notification` 和 S99 的入口 `manual_review`。 |
| 旧 `S000/S999` 兼容映射 | 任务列表、任务详情 | 已完成第一版 | 旧数据继续可见；前端可按 `S000→S10`、`S999→S99` 展示统一文案。 |
| 40 条 P0.1 路由元数据 | 任务列表筛选、订单任务时间线、任务详情标题、字段展示 | 已完成第一版 | 后端保存并返回 AI 原始 `result_type/ai_task_type/task_subtype`、`route_code` 和系统处理分类；前端不要只依赖系统主任务类型判断卡片。 |
| P0.1 稳定 route_code | 任务列表筛选、订单任务时间线、任务详情标题 | 已完成第一版 | `route_code` 保持历史稳定，不因路由总数变 40 而连续重编号；前端仍可能看到 `R41_FALLBACK_BUSINESS_EVENT_REVIEW` 和 `R42_UNHANDLED_CURRENT_INTENT`。 |
| Parent split 父事件卡型 | 任务列表、订单任务时间线、任务详情标题 | 已完成第一版 | 0712 P0.1 后，Parent split 父事件展示为 `Parent Group / Cancel Allotment / cancel_allotment_control_block`；`route_code=R08_CANCEL_ALLOTMENT_CONTROL_BLOCK_NORMAL` 展示为普通业务卡，`route_code=R08_CANCEL_ALLOTMENT_CONTROL_BLOCK_REVIEW` 展示为同卡人工复核业务卡；`linked_parent_release_after_child_split` 仅作为关系字段，不作为任务 subtype 筛选项。 |
| `unhandled_current_intents[]` 展示块 | 任务详情 | 已完成第一版 | 后端保存并在任务详情 `unhandled_intents[]` 返回未覆盖业务意图，只用于展示和源邮件查看，不自动建业务任务卡。 |
| `adapter_contract_error` | 任务详情、错误提示 | 已完成第一版 | 命中 P1/P2 未闭合或路由冲突时，任务详情 `adapter_contract_errors[]` 返回稳定错误 code 和原始片段，不转成 Fallback。 |
| type-known manual review 同卡解阻 | 任务详情复核 | 已完成第一版 | `manual_review` 不再全部等同 Fallback；已知业务卡型返回原业务卡信息、`review_status`、`review_resolution` 和可编辑 pointer 字段，解阻后进入 `READY`。 |
| 复核场景订单归属确认 | 任务详情复核 | 已完成第一版 | 后端提供复核确认时的订单归属确认；当前第一版只能确认当前任务所属订单，后续如要选择其他订单需另行细化。 |
| P0 fixtures 回归基线 | 联调回归 | 已完成第一版 | 后端已将 0711 P0 fixtures 纳入测试参考；前端对 S10/S99、同卡复核和只读诊断块的展示应继续按本节稳定字段接入。 |

### 6.2 前端本轮接入状态（2026-07-11）

本轮前端已按 M002 V3 P0 完成以下接入，后端不需要重复补接口：

- 任务列表已按 `result_type`、`route_code`、`system_process_category` 识别 `source_message_review_notification`、`adapter_contract_error`、`unhandled_current_intent` 只读诊断任务；S10/S99 和旧 S000/S999 都不展示订单入口。
- 任务详情已展示 `result_type`、`ai_task_type`、`task_subtype`、`route_code`、`system_process_category`、`review_status`、来源邮件入口、`source_message_only_result`、`manual_review`、`adapter_contract_errors[]` 和 `unhandled_intents[]`。
- Parent Group P0.1 前端已按 `route_code=R08_CANCEL_ALLOTMENT_CONTROL_BLOCK_NORMAL/REVIEW` 展示 `Parent Group / Cancel Allotment / cancel_allotment_control_block`；review 场景继续走同卡人工复核解阻，不展示为 `adapter_contract_error`。
- type-known `result_type=manual_review` 已在原业务任务卡展示复核状态和缺失字段，并调用 `POST /api/reservation/tasks/{taskId}/manual-review-resolutions` 解阻，不再创建第二张人工复核任务卡。
- 第一版解阻 UI 已改为优先使用任务详情 `fields[].field_pointer`，并同时提交 P0 主 `fields[].field_path`；旧扁平 `legacy_field_path` / `legacy_field_values` 仅用于 `field_contract_version=code-v1` 历史任务过渡回显，不作为新前端主动提交路径。
- 前端只读规则已收口：S10/S99、适配契约异常、未处理意图、前置任务阻塞和同卡人工复核待解阻状态都不显示保存草稿、确认任务、人工转换或 OPERA 执行 / 重试入口。
- 前端 fixture 已补 V3 最小结构样例：`source_message` 完整对象、`message_events[]` 的 `event_role`、`current_or_history`、`source_event_index`、四字段 `case_keys`、`relevant_message_excerpt`、`attachments`、`file_references`、`context_used`、`extracted_fields`、`manual_review`。

仍建议后端确认：

- `GET /api/reservation/tasks` 是否会在结构化 S10/S99 行中稳定返回 `task_type=SOURCE_MESSAGE_ONLY`，或允许返回 `MESSAGE_NOTIFICATION` 并只依赖 `result_type/route_code/system_process_category`；前端当前两种都兼容。
- `adapter_contract_error` / `unhandled_current_intent` 如果未来也作为独立列表行返回，请保持 `source_message_id` 可用，便于前端继续提供邮件会话入口。
- 同卡人工复核解阻成功后是否一定返回 `opera_operations[]`。当前文档写“两条 OPERA 模拟操作”，前端实现按实际返回刷新，不假设固定数量。
- Parent Group `manual_review.reason_code=target_object_unclear` 场景需要任务详情稳定透出 `context_used.parent_identity_candidates[]`。当前 `ReservationTaskDetailResult` 后端 DTO 仅透出 `manual_review`，前端已兼容顶层 `context_used.parent_identity_candidates[]` 或 `manual_review.context_used.parent_identity_candidates[]`，但若后端不透出 candidates，页面只能显示空态提示。

前端注意：不要把访问口令写入前端仓库、浏览器环境变量或构建产物；该接口只能由本地联调人员手动调用或由受控测试脚本调用。

## 7. 邮件会话详情接口

建议优先路径：

```text
GET /api/source-messages/{sourceMessageId}/conversation
```

历史候选路径，当前不提供：

```text
GET /api/source-message-conversations/{externalConversationId}
```

当前状态：`GET /api/source-messages/{sourceMessageId}/conversation` 已完成第一版。前端入口从某个任务的 `source_message_id` 进入，后端根据该 SourceMessage 找到 `external_conversation_id`，再返回同一邮件会话下的全部邮件。

中文说明：

- “全部邮件”指同一个 `externalConversationId` 下的历史邮件、当前邮件和后续回复，不是只展示任务对应的单封来源邮件。
- 邮件会话详情页需要展示完整正文或清洗后的 HTML、附件、内联图片、发件人展示值、发送 / 接收时间、主题和关联订单 / 任务。
- 前端不在页面上做业务截断或隐藏；但仍只调用本项目后端接口，不直接访问邮箱、AgentBus、数据库或外部附件 URL Secret。
- 如果后端仍需要审计原文读取，应由后端在该业务接口内部处理；前端不保存 `X-TH-Hotel-Source-Original-Read-Key` 一类受控访问 key。
- 2026-07-08 后端已新增 `html_body_sanitized` 和 `html_render_mode`；前端页面展示邮件 HTML 时应优先使用 `html_body_sanitized`，`html_body` 只作为原始内容兼容字段，不建议生产直渲。
- 第一版仅处理 HTML 内容清洗；附件和内联图片 URL 来自本系统 OSS 服务，暂不做额外拦截或代理转换。

建议入参：

| 参数 | 必填 | 说明 |
| --- | --- | --- |
| `sourceMessageId` | 是 | 入口来源消息 ID。后端据此定位 `externalConversationId`。 |

当前第一版不额外接收 `hotelId`、`includeBody`、`includeRelated`。后端默认按 SourceMessage 自身酒店上下文查询同会话邮件，返回完整 text/html、清洗后的 HTML 和关联订单 / 任务摘要，并在内部写原文读取审计。

建议返参：

```json
{
  "conversation": {
      "external_conversation_id": "thread-20260708-001",
      "hotel_id": "HOTEL-TEST",
      "channel": "EMAIL",
      "subject": "Re: Booking Update",
      "message_count": 6,
      "first_received_at": "2026-07-06T01:10:00Z",
      "last_received_at": "2026-07-08T03:28:00Z"
  },
  "messages": [
    {
      "id": "30001",
      "external_message_id": "msg-001",
      "external_conversation_id": "thread-20260708-001",
      "sender_summary": "guest@example.com",
      "subject": "Booking Request",
      "received_at": "2026-07-06T01:10:00Z",
      "source_sent_at": "2026-07-06T01:08:00Z",
      "text_body": "完整邮件正文",
      "html_body": "<p>完整邮件 HTML</p>",
      "html_body_sanitized": "<p>完整邮件 HTML</p>",
      "html_sanitize_required": true,
      "html_render_mode": "SANITIZED_HTML",
      "inline_images": [],
      "attachments": [
        {
          "mediaType": "ATTACHMENT",
          "fileName": "rooming-list.xlsx",
          "contentType": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
          "sizeBytes": 10240,
          "externalUrl": "由后端决定是否返回可访问 URL",
          "externalMediaId": "media-001"
        }
      ],
      "related_orders": [
        {
          "order_id": "20001",
          "display_order_key": "GRP-001",
          "order_status": "ACTIVE"
        }
      ],
      "related_tasks": [
        {
          "task_id": "10001",
          "order_id": "20001",
          "task_type": "NEW_BOOKING",
          "task_subtype": "NEW_BOOKING",
          "task_status": "PENDING_CONFIRM",
          "card_name": "New Booking"
        }
      ]
    }
  ]
}
```

## 8. 任务详情接口字段元数据扩展

建议路径：

```text
GET /api/reservation/tasks/{taskId}
```

当前状态：后端已有任务详情接口，前端任务详情页可以接入。该接口已返回 `fields[]`、草稿、确认 payload、可处理状态和 OPERA 模拟操作；本轮已透出来源邮件会话字段，以及旧 `docs/import/20260708/任务卡前端展示字段表 3.0.xlsx` 中 P0 需要的字段元数据。0711 P0 后续开发应迁移到 `docs/import/20260711/开发交付_P0冻结基线_2026-07-11/01_Adapter_Frontend/任务卡前端字段变更说明_3.0_to_当前版_2026-07-10.xlsx` 和同目录路由说明。

任务详情页面相关已完成接口：

| 接口 | 用途 | 后端状态 |
| --- | --- | --- |
| `GET /api/reservation/tasks/{taskId}` | 读取任务详情、字段矩阵、当前值、可处理状态、OPERA 操作摘要。 | 已完成第一版，已补本节字段。 |
| `PUT /api/reservation/tasks/{taskId}/draft` | 保存任务卡草稿。 | 已完成。 |
| `POST /api/reservation/tasks/{taskId}/confirm` | 最终确认任务卡字段。 | 已完成。 |
| `GET /api/reservation/tasks/{taskId}/audits` | 查询任务审计流水。 | 已完成。 |
| `POST /api/reservation/tasks/{taskId}/opera-operations/{operationId}/execute` | 执行 OPERA 模拟操作。 | 已完成第一版模拟。 |
| `POST /api/reservation/tasks/{taskId}/opera-operations/{operationId}/retry` | 重试失败的 OPERA 模拟操作。 | 已完成第一版模拟。 |
| `POST /api/reservation/tasks/{taskId}/manual-review-conversions` | 将 Fallback / manual_review 转换为具体任务类型。 | 已完成。 |
| `POST /api/reservation/tasks/{taskId}/manual-review-resolutions` | type-known manual review 在原业务任务卡上提交字段修正和订单归属确认。 | 已完成第一版。 |

已完成的 `fields[]` 字段：

| 字段 | 说明 |
| --- | --- |
| `row_number` | 字段矩阵行号。 |
| `card_name` | 任务卡名称。 |
| `display_area` | 前端展示区域。 |
| `field_path` | 字段路径。 |
| `display_name` | 展示名。 |
| `visible` | 是否展示。 |
| `editable` | 是否可编辑。 |
| `input_editable` | 是否输入方式编辑。 |
| `select_editable` | 是否下拉方式编辑。 |
| `date_picker` | 是否日期选择。 |
| `number_input` | 是否数字输入。 |
| `file_display` | 是否文件展示。 |
| `table_editable` | 是否表格编辑。 |
| `enum_options` | 枚举选项。 |
| `required_rule` | 必填规则。 |
| `display_condition` | 展示条件。 |
| `validation_rule` | 校验规则。 |
| `write_path` | 写入路径。 |
| `opera_write_participation` | 是否参与 OPERA 写入。 |
| `opera_parameter_mapping` | OPERA 参数映射。 |
| `notes` | 备注。 |
| `value` | 当前回显值。 |

本轮已补字段：

| 位置 | 字段 | 说明 |
| --- | --- | --- |
| 顶层 | `source_subject` | 任务来源消息主题摘要。 |
| 顶层 | `source_sender_summary` | 任务来源消息发件人展示值，当前不打码。 |
| 顶层 | `source_received_at` | 任务来源邮件接收时间，优先取 AgentBus payload `received_at`。 |
| 顶层 | `external_conversation_id` | 任务来源消息所属邮件会话 ID。 |
| 顶层 | `conversation_message_count` | 会话内邮件数量。 |
| `fields[]` | `result_type` | 3.0 字段表中的结果类型，用于前端调试和字段分组校验。 |
| `fields[]` | `task_type` | 3.0 字段表中的任务主类型。 |
| `fields[]` | `task_subtype` | 3.0 字段表中的任务 subtype / 业务动作。 |
| `fields[]` | `default_value_source` | 3.0 字段表中的默认值 / 回显来源。 |

### 8.1 Type-known manual review 同卡复核解阻

当前状态：后端已完成第一版。`result_type=manual_review` 且 `system_task_type` 不是 `MANUAL_REVIEW` 时，前端在原业务任务卡上展示复核模式，不进入 Fallback 转换页面。

任务详情增量字段：

| 字段 | 说明 |
| --- | --- |
| `review_status` | `PENDING` 表示等待复核，`RESOLVED` 表示已解阻。 |
| `review_resolution` | 已解阻后的复核结果；未解阻时为 `null`。 |
| `manual_review` | SuperAgent 原始复核说明、缺失字段、阻塞点、建议人工动作；只读展示。 |

解阻接口：

```text
POST /api/reservation/tasks/{taskId}/manual-review-resolutions
Content-Type: application/json
```

请求示例：

```json
{
  "confirmed_order_id": "20001",
  "reason": "确认 PMS 房型代码后解阻。",
  "field_overrides": [
    {
      "field_pointer": "/extracted_fields/room_items/0/pms_room_type_code",
      "field_path": "extracted_fields.room_items.0.pms_room_type_code",
      "value": "RM3"
    }
  ]
}
```

0711 P0 房型复核说明：前端应优先提交 `/extracted_fields/room_items/0/pms_room_type_code` 或任务详情 `fields[].field_path=extracted_fields.room_items.0.pms_room_type_code`。后端仍兼容旧扁平 key / pointer，也支持只提交 `field_path`。如果同时提交 `field_pointer` 和 `field_path`，两者必须指向同一字段。响应里的 `review_resolution.field_overrides[].field_path` 使用 P0 主路径；前端只提交 `field_path` 时，后端会返回 P0 主 `field_pointer`；前端提交旧 pointer 时，`field_pointer` 保留前端原始值，`legacy_field_path` 仅用于旧页面过渡。

返回示例：

```json
{
  "task_id": "10001",
  "order_id": "20001",
  "task_status": "READY",
  "review_status": "RESOLVED",
  "review_resolution": {
    "schema_version": "manual-review-resolution-v1",
    "confirmed_order_id": "20001",
    "resolved_at": "2026-07-11T00:00:00Z",
    "field_overrides": [
      {
        "field_pointer": "/extracted_fields/room_items/0/pms_room_type_code",
        "field_path": "extracted_fields.room_items.0.pms_room_type_code",
        "legacy_field_path": "extracted_fields.pms_room_type_code",
        "value": "RM3"
      }
    ]
  },
  "confirmed_payload": {
    "schema_version": "field_matrix-p0-room-items-v1",
    "field_values": {
      "extracted_fields.room_items.0.pms_room_type_code": "RM3"
    },
    "legacy_field_values": {
      "extracted_fields.pms_room_type_code": "RM3"
    },
    "effective_payload": {
      "extracted_fields": {
        "room_items": [
          {
            "pms_room_type_code": "RM3"
          }
        ]
      }
    }
  },
  "opera_operations": [
    {"operation_code": "SIMULATE_PRECHECK"},
    {"operation_code": "SIMULATE_WRITE"}
  ]
}
```

前端注意：

- `field_overrides[]` 必须提供 `field_pointer` 或 `field_path`。`field_pointer` 必须是 RFC 6901 JSON Pointer；`field_path` 可以是 P0 主路径或旧扁平路径。两者都只能指向任务详情 `fields[]` 中当前可编辑字段；只读字段、未知字段或两者指向不一致会返回 `TASK_REVIEW_POINTER_INVALID`。
- 同一次请求不能重复提交同一字段；重复 `field_pointer` 或重复映射到同一 `field_path` 会返回 `TASK_REVIEW_POINTER_DUPLICATE`。
- `confirmed_order_id` 第一版必须等于当前任务 `order_id`；普通任务任意切换订单继续后置。
- type-known manual review 不能调用通用 `POST /api/reservation/tasks/{taskId}/confirm`；必须调用本节解阻接口，否则后端返回 `TASK_REVIEW_RESOLUTION_REQUIRED`。
- `review_resolution.resolved_at` 是 UTC `Z` 时间点。
- 解阻成功后刷新任务详情，按钮状态以新的 `task_status=READY` 和 `availability` 为准。
- `confirmed_payload.field_values` 按 P0 主 `field_path` 保存；`legacy_field_values` 是旧扁平兼容回显；`effective_payload` 是后端第一版嵌套结构，不是 OPERA 最终参数。

建议返参增量示例：

```json
{
  "task_id": "10001",
  "order_id": "20001",
  "source_message_id": "30001",
  "source_subject": "Booking Update",
  "source_sender_summary": "guest@example.com",
  "source_received_at": "2026-07-08T02:58:00Z",
  "external_conversation_id": "thread-20260708-001",
  "conversation_message_count": 6,
  "system_task_type": "NEW_BOOKING",
  "task_card_type": "NEW_BOOKING",
  "task_status": "PENDING_CONFIRM",
  "field_contract_version": "20260711-p0",
  "fields": [
    {
      "row_number": 2,
      "card_name": "New Booking",
      "result_type": "RESERVATION",
      "task_type": "NEW_BOOKING",
      "task_subtype": "NEW_BOOKING",
      "display_area": "基础信息",
      "field_path": "case_keys.group_code",
      "display_name": "Group Code",
      "visible": "是",
      "editable": "否",
      "default_value_source": "AI识别结果 / 已确认草稿回显",
      "value": "GRP-001"
    }
  ]
}
```

中文说明：

- 如果前端只做“按后端字段直接渲染”，现有 `fields[]` 可以支撑第一版表单展示；本轮已经扩展 `ReservationTaskFieldResult`，避免前端维护第二套字段矩阵。
- `result_type`、`task_type`、`task_subtype`、`default_value_source` 当前从后端字段矩阵定义透出。
- 如果后端已有更细的字段来源或适用场景元数据，可后续再扩展 `field_source`、`applicable_scenario`，不作为本轮 P0 阻塞项。
- 前端默认不需要为 `GET /api/reservation/orders`、`GET /api/reservation/tasks`、`GET /api/reservation/orders/{orderId}` 自动拼 `hotel_id`；如已接入酒店选择器，可以传当前选中酒店，后端会校验访问权限。当前 `GET /api/reservation/tasks/{taskId}` 以及任务写操作 Controller 不接收 `hotel_id`；第一版先按 ID 定位，后续多酒店隔离 / 权限方案统一补齐。

## 9. S10/S99 源邮件只读通知卡与历史兼容

当前状态：后端不提供独立 Message Notification 列表 / 详情接口。旧 SuperAgent 入口返回 `S000,source_message_id` 或 `S999,source_message_id` 时，后端会创建 `SOURCE_MESSAGE_ONLY` 只读特殊任务；0711 P0 结构化 `S10/S99` 也复用同一只读任务模型。前端已通过 `GET /api/reservation/tasks?task_type=SOURCE_MESSAGE_ONLY` 和 `GET /api/reservation/tasks/{taskId}` 展示；任务列表筛选只保留 `SOURCE_MESSAGE_ONLY`、`S10`、`S99`，不再提供 `S000`、`S999` 历史筛选项。

0711 P0 新入口已迁移为结构化 `S10/S99`：

- `S10`：`result_type=source_message_review_notification`，`route_code=S10`，表示未匹配当前支持的业务事件。
- `S99`：`result_type=source_message_review_notification`，`route_code=S99`，表示输入不足或无法形成业务素材包。
- 旧 `S000` 前端语义映射为 `S10`。
- 旧 `S999` 前端语义映射为 `S99`。

历史 `INFORMATIONAL_MESSAGE` 仍可通过任务列表 / 任务详情兼容展示，但新数据不要依赖它。

展示规则：

- 旧 `task_type=SOURCE_MESSAGE_ONLY`、`task_subtype=S000/S999`：按只读源邮件通知卡展示。
- 新 `route_code=S10/S99`：按只读源邮件通知卡展示。
- 任务列表可见，订单列表不可见。
- 任务详情只允许查看来源邮件、会话、附件和 SuperAgent 原始返回。
- 任务详情通过 `source_message_only_result` 返回 `entry_result_code`、`entry_result_meaning`、`entry_result_description`、`entry_result_source_message_id`、`result_type`、`route_code`、`agent_assessment`、`notification`、S99 的入口 `manual_review` 和 `raw_answer`。
- 不显示编辑、确认、人工转换、执行 OPERA 或重试 OPERA 按钮。
- 不参与订单任务执行顺序阻塞。

当前不建议新增路径：

```text
GET /api/reservation/message-notifications
GET /api/reservation/message-notifications/{taskId}
```

列表建议入参：

| 参数 | 必填 | 说明 |
| --- | --- | --- |
| `hotel_id` | 否 | 酒店 ID。单酒店阶段默认可为空，由后端解析；显式传值时后端会校验访问权限。 |
| `order_id` | 否 | 按临时订单或真实订单过滤。 |
| `keyword` | 否 | 邮件主题、摘要、发送人关键词。 |
| `page_num` | 否 | 页码。 |
| `page_size` | 否 | 每页条数。 |

详情建议返参：

```json
{
  "task_id": "10009",
  "order_id": "20009",
  "task_type": "SOURCE_MESSAGE_ONLY",
  "task_subtype": "S000",
  "task_status": "COMPLETED",
  "queue_participation": false,
  "readonly": true,
  "visible_reason": "S000 pure information entry result",
  "relevant_message_excerpt": "Noted with thanks.",
  "entry_result_code": "S000",
  "entry_result_description": "纯信息类邮件",
  "attachments": [],
  "source_message_id": "30009",
  "external_conversation_id": "thread-20260708-009",
  "created_at": "2026-07-08T03:00:00Z"
}
```

V3 S10 结构化详情当前增量：

```json
{
  "task_id": "10010",
  "readonly": true,
  "result_type": "source_message_review_notification",
  "route_code": "S10",
  "agent_assessment": {
    "status": "no_booking_action_detected",
    "reason_code": "no_booking_action_detected"
  },
  "notification": {
    "notification_type": "source_message_review",
    "show_source_message": true,
    "requires_user_decision": true
  },
  "manual_review": null,
  "source_message_id": "30010"
}
```

## 9.1 V3 诊断展示块

任务详情接口已新增两个只读数组：

| 字段 | 说明 |
| --- | --- |
| `adapter_contract_errors[]` | 同一 SuperAgent 入站批次中未生成任务的 Adapter 契约错误。 |
| `unhandled_intents[]` | 同一 SuperAgent 入站批次中无法映射到业务任务卡的未处理意图。 |

数组元素字段：

| 字段 | 说明 |
| --- | --- |
| `transition_id` | AI transition ID。 |
| `source_event_index` | AI current 事件序号。 |
| `array_index` | AI 返回数组顺序。 |
| `result_type` | AI 结果类型。 |
| `ai_task_type` | AI 原始任务类型。 |
| `task_subtype` | 业务动作 subtype，可能为空。 |
| `route_code` | V3 路由码。 |
| `system_process_category` | 系统处理分类。 |
| `adapter_error_code` | 契约错误代码；未处理意图通常为空。 |
| `adapter_error_message` | 契约错误安全摘要。 |
| `payload_fragment` | 对前端展示安全的 AI item 片段。 |

前端注意：这两个数组不是任务队列，不提供编辑、确认、执行 OPERA 或重试入口；只用于解释为什么同一封邮件中的某些 event 没有变成业务任务。

## 10. 任务卡前端字段白名单元数据接口

是否需要该接口待确认。如果任务详情接口 `fields[]` 已透出 3.0 所需元数据，则第一版可以不做独立白名单接口；如果后续需要字段矩阵调试页、版本对齐页或前端预加载全部任务卡配置，再补独立接口。

建议路径：

```text
GET /api/reservation/task-card-field-whitelist
```

建议入参：

| 参数 | 必填 | 说明 |
| --- | --- | --- |
| `task_type` | 否 | 按系统主任务类型过滤。 |
| `task_subtype` | 否 | 按任务卡 subtype 过滤。 |
| `version` | 否 | 字段白名单版本，例如 `20260711-p0`。 |

建议返参：

```json
{
  "version": "20260711-p0",
  "items": [
    {
      "task_type": "UPDATE_BOOKING",
      "task_subtype": "RATE_CHANGE",
      "field_path": "rate.rate_code",
      "display_name": "Rate Code",
      "visible": true,
      "editable": true,
      "input_type": "select",
      "options": []
    }
  ]
}
```

## 11. 已确认后置接口

普通任务切换订单接口继续后置，前端暂不开发提交能力。后续如果恢复开发，建议另行确认：

```text
POST /api/reservation/tasks/{taskId}/order-binding
```

待确认入参：

```json
{
  "target_order_id": "20002",
  "reason": "人工确认该任务属于另一个订单"
}
```

待确认返参：

```json
{
  "task_id": "10001",
  "previous_order_id": "20001",
  "target_order_id": "20002",
  "task_status": "PENDING_CONFIRM",
  "audit_id": "90001"
}
```

## 12. 待确认问题

- 订单列表、任务列表当前统一使用 `items + page` 分页结构；邮件会话详情不分页，返回同一会话全部邮件。
- 邮件会话详情接口已优先使用 `GET /api/source-messages/{sourceMessageId}/conversation`。
- 任务详情 `fields[]` 已由后端直接透出 P0 需要的 3.0 元数据；独立字段白名单接口后置。
- 独立 Message Notification 页面继续后置；旧 S000/S999 和新 S10/S99 都先在任务列表和任务详情展示。
- 邮件会话全文读取的审计策略由后端内部处理；前端不保存原文读取 key。
- `GET /api/reservation/tasks` 结构化 S10/S99 行的 `task_type` 返回值请后端最终确认：前端已兼容 `SOURCE_MESSAGE_ONLY` 和 `MESSAGE_NOTIFICATION`，但文档口径最好稳定一个。
- `manual-review-resolutions` 成功响应中的 `opera_operations[]` 数量请后端最终确认；前端不写死两条，只按返回内容刷新展示。
