From 14eda89b0b0c7d4a86d2ff0744d207834aa4043d Mon Sep 17 00:00:00 2001 From: andy Date: Fri, 24 Jul 2026 10:23:04 +0700 Subject: [PATCH] =?UTF-8?q?=E5=9B=9E=E5=A1=ABV4=E5=8D=95=E5=8D=A1=E5=8F=AF?= =?UTF-8?q?=E6=93=8D=E4=BD=9C=E6=80=81smoke=E7=BB=93=E6=9E=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- PROJECT_STATE.md | 12 +++++----- .../backend-to-frontend-notes.md | 4 ++-- .../frontend-to-backend-api-requests.md | 2 +- ...002-v4-order-task-card-domain-model-cp2.md | 1 + ...-v4-requirement-spec-template-alignment.md | 24 +++++++++++++++++-- .../security-access-control-boundary.md | 2 +- 6 files changed, 33 insertions(+), 12 deletions(-) diff --git a/PROJECT_STATE.md b/PROJECT_STATE.md index ac11063..ca3390a 100644 --- a/PROJECT_STATE.md +++ b/PROJECT_STATE.md @@ -4,16 +4,16 @@ | --- | --- | | 最近更新 | 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 对齐 | +| 当前阶段 | 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 目录供给方案。 | ## 1. 当前 Checkpoint -- 名称:`M002-V4-requirement-spec-template-alignment` -- 状态:Done,已新增 `docs/project/requirements/M002-v4-requirement-spec-template-alignment.md`,把近期 V4 增量需求整理为模板化 Spec 入口和需求追踪表。 -- 目标:汇总 Room Information 多房型 / 展示模型 / 派生字段、Payment 附件预览、Rooming List 轻量事项卡、Trace 专属卡、REVIEW_REQUIRED 原卡复核、SourceMessage Display 底部折叠、普通酒店员工用户化展示和单卡可操作态测试数据需求。 +- 名称:`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、不改变权限、酒店隔离、审计或安全脱敏业务规则。 -- 联调备注:单卡可操作态测试数据仍待测试 agent 返回结果;返回后应回填本文追踪表或追加测试记录。 +- 联调备注:只执行造数和 5 次 Basic Information 前置确认;未确认目标业务卡、未执行 review-resolution、未 ack。V4 task detail API 和页面可见文本不得出现附件 URL;用户触发 Payment 预览 / 下载时,DOM `src/href` 临时持有 conversation 接口返回的受权限 URL 是允许行为。 ## 2. 当前优先级 @@ -46,7 +46,7 @@ - 后续如继续做 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 交接边界。 -- 单卡可操作态测试数据结果返回后,回填 `M002-v4-requirement-spec-template-alignment.md` 的追踪表或追加测试记录。 +- 单卡可操作态测试数据已回填;后续演示或回归如果需要重新造数,应继续使用 fresh runId,避免复用旧 SourceMessage 时间线造成阻塞误判。 - M010 CP2 字段收口已完成;预览、历史记录、OSS 下载、订单 / 任务预填或客户字段目录化仍后置,需单独开前后端 checkpoint。 - M011 CP4 暂不推进;当前停留在 CP3 边界,只增强 SuperAgent 输入,不直接落订单、任务或长期解析历史。后续如确实需要运营查询或长期追踪,再单独设计 Excel 解析批次 / 行级持久化表。 diff --git a/docs/project/frontend-backend/backend-to-frontend-notes.md b/docs/project/frontend-backend/backend-to-frontend-notes.md index 7f061ed..850063e 100644 --- a/docs/project/frontend-backend/backend-to-frontend-notes.md +++ b/docs/project/frontend-backend/backend-to-frontend-notes.md @@ -183,10 +183,10 @@ POST /api/auth/logout - `messages[]` 按邮件来源接收时间正序返回,前端不要重新按创建时间或任务时间排序。 - 返回内容包含完整 `text_body`、`html_body`、`inline_images[]`、`attachments[]`、`related_orders[]`、`related_tasks[]`。 - `html_body` 是原始 HTML 兼容字段;`html_body_sanitized` 是后端第一版清洗结果,已移除脚本标签、事件属性和危险协议链接。前端生产展示必须优先使用 `html_body_sanitized`,并可用 `html_render_mode=SANITIZED_HTML` 判断渲染模式。 -- 第一版仅处理 HTML 内容安全;`inline_images[]` 和 `attachments[]` 的 `externalUrl` 来自本系统 OSS 服务,暂不做额外拦截,但前端仍不得写入普通日志、错误上报、localStorage 或 URL query。 +- 第一版仅处理 HTML 内容安全;`inline_images[]` 和 `attachments[]` 的 `externalUrl` 来自本系统 OSS 服务,暂不做额外拦截。用户触发 Payment 图片预览或非图片下载时,前端 DOM 的 `img[src]` / `a[href]` 可以临时使用本接口返回的受权限附件 URL,但前端仍不得把该 URL 写入普通日志、错误上报、localStorage、URL query、确认 payload 或页面可见文本。 - 会话详情接口由后端内部写原文读取审计,actor 使用当前登录用户稳定 ID;前端不传 `X-TH-Hotel-Source-Original-Read-Key`、`X-TH-Hotel-Actor` 或 `X-TH-Hotel-Access-Scene`。 - 会话详情外层字段主要是 snake_case,但媒体对象沿用原文读取接口字段,当前是 `mediaType`、`fileName`、`contentType`、`sizeBytes`、`externalUrl`、`externalMediaId` 这种 camelCase,前端类型定义需要单独处理。 -- Payment 卡附件预览规则:业务卡里的 `attachment_ids[]` 是付款凭证引用,第一版只读展示并确认卡片,不允许前端增删或替换附件集合;后端已在任务详情 `display_payload.payment_attachments[]` 返回安全摘要辅助展示。图片附件按 `content_type` 或会话媒体 `contentType` 以 `image/` 开头判断,在卡片中展示缩略图,点击后打开大图预览;非图片附件统一展示文件名、类型、大小和下载按钮,不在 Payment 卡中内嵌 PDF / Word / Excel 预览。预览和下载必须先通过会话接口定位当前 SourceMessage,再按 `externalMediaId` / `payment_attachments[].external_media_id` 或附件 ID 匹配,不能按文件名、本系统内部媒体 row ID 或跨酒店 SourceMessage 媒体猜测。 +- Payment 卡附件预览规则:业务卡里的 `attachment_ids[]` 是付款凭证引用,第一版只读展示并确认卡片,不允许前端增删或替换附件集合;后端已在任务详情 `display_payload.payment_attachments[]` 返回安全摘要辅助展示。图片附件按 `content_type` 或会话媒体 `contentType` 以 `image/` 开头判断,在卡片中展示缩略图,点击后打开大图预览;非图片附件统一展示文件名、类型、大小和下载按钮,不在 Payment 卡中内嵌 PDF / Word / Excel 预览。预览和下载必须先通过会话接口定位当前 SourceMessage,再按 `externalMediaId` / `payment_attachments[].external_media_id` 或附件 ID 匹配,不能按文件名、本系统内部媒体 row ID 或跨酒店 SourceMessage 媒体猜测;测试安全扫描时,V4 task detail API 和页面可见文本不得出现附件 URL,但用户触发预览 / 下载后 DOM `src/href` 临时出现受权限 URL 是允许行为。 ### 5.5 订单列表接入注意 diff --git a/docs/project/frontend-backend/frontend-to-backend-api-requests.md b/docs/project/frontend-backend/frontend-to-backend-api-requests.md index 44eb551..5b787a1 100644 --- a/docs/project/frontend-backend/frontend-to-backend-api-requests.md +++ b/docs/project/frontend-backend/frontend-to-backend-api-requests.md @@ -46,7 +46,7 @@ | `GET /api/source-messages/{id}` | 已完成单条安全摘要 | 可以 | 不能替代邮件会话全文接口。 | | `GET /api/source-messages/{id}/original` | 已完成单封原文权限读取 | 谨慎接入 | 必须带 Bearer token,需要同时拥有 `SOURCE_MESSAGE_READ` 和 `SOURCE_MESSAGE_ORIGINAL_READ`;只能读单封邮件,不能返回同一 conversation 全量邮件。 | | `GET /api/reservation/orders` | 已完成第一版 | 可以 | 默认查询全部订单状态;订单列表待处理展示使用 `open_work_item_count`;V4 普通业务已停止双写旧任务,旧 `open_task_count` 仅作为历史诊断计数。 | -| `GET /api/source-messages/{sourceMessageId}/conversation` | 已完成第一版,已补 `html_body_sanitized` 和 `html_render_mode` | 可以 | 必须带 Bearer token,需要同时拥有 `SOURCE_MESSAGE_READ` 和 `SOURCE_MESSAGE_ORIGINAL_READ`;返回完整 text/html、后端清洗后的 HTML、媒体外链和关联订单 / 任务摘要;前端不传原文读取 key,页面展示优先使用 `html_body_sanitized`。V4 Payment 卡图片大图预览和非图片下载也复用该权限链路,只能使用当前触发 SourceMessage 且被 `attachment_ids[]` 引用的附件。 | +| `GET /api/source-messages/{sourceMessageId}/conversation` | 已完成第一版,已补 `html_body_sanitized` 和 `html_render_mode` | 可以 | 必须带 Bearer token,需要同时拥有 `SOURCE_MESSAGE_READ` 和 `SOURCE_MESSAGE_ORIGINAL_READ`;返回完整 text/html、后端清洗后的 HTML、媒体外链和关联订单 / 任务摘要;前端不传原文读取 key,页面展示优先使用 `html_body_sanitized`。V4 Payment 卡图片大图预览和非图片下载也复用该权限链路,只能使用当前触发 SourceMessage 且被 `attachment_ids[]` 引用的附件;用户触发预览 / 下载时,DOM `img[src]` / `a[href]` 可临时持有本接口返回的受权限附件 URL,但不得写入确认 payload、日志、URL query、localStorage、错误上报或页面可见文本。 | | `POST /api/system/reservation/demo-data` | 已完成 | 仅本地 / test 联调可用 | 默认关闭,必须后端配置访问口令;不能作为生产页面接口。 | | `POST /api/system/debug/eml-superagent-runs` | 已完成第一版 | 仅 dev/test Debug 页面可用 | 默认关闭,必须后端配置访问口令、阿里云 OSS 和 SuperAgent Open API;Debug 服务自身只展示 SuperAgent 结果,不直接创建订单和任务;如 SuperAgent 通过正式回调 / MCP 写入业务结果,V4 smoke 必须创建 V4 order task / cards,不再创建旧 `workflow_reservation_task`;MCP submit 已收口为 M002 V4-only,旧 V2/V3 payload 会返回 `MCP_SUBMIT_V4_REQUIRED`;已能识别旧 S000/S999 和新结构化 S10/S99。 | | `GET /api/source-message-conversations/{externalConversationId}` | 未发现后端实现 | 不可以 | 历史讨论过的候选路径,当前不提供;前端统一使用 `GET /api/source-messages/{sourceMessageId}/conversation`。 | diff --git a/docs/project/requirements/M002-v4-order-task-card-domain-model-cp2.md b/docs/project/requirements/M002-v4-order-task-card-domain-model-cp2.md index d72b530..37150ae 100644 --- a/docs/project/requirements/M002-v4-order-task-card-domain-model-cp2.md +++ b/docs/project/requirements/M002-v4-order-task-card-domain-model-cp2.md @@ -674,6 +674,7 @@ Payment 卡附件展示规则: - 后端已在 Payment 卡 `display_payload.payment_attachments[]` 中返回安全摘要,由 `attachment_ids[]` 匹配当前触发 SourceMessage 的包级附件或同酒店 SourceMessage 媒体摘要生成。匹配只认包级附件 ID / `external_media_id`,不认本系统媒体表内部 row ID,也不按文件名猜测。字段为 `attachment_id`、`file_name`、`content_type`、`size_bytes`、`is_image`、`preview_available`、`download_available`,可选 `external_media_id` / `unavailable_reason_code`;不得包含 `externalUrl`、OSS URL、签名参数或附件原始二进制。 - 图片判断以 `content_type` 以 `image/` 开头为主;图片在 Payment 卡内展示缩略图,点击后打开大图预览。缩略图和大图实际 URL 不从 `GET /api/reservation/order-tasks/{orderTaskId}` 返回,前端必须在具备 `SOURCE_MESSAGE_READ + SOURCE_MESSAGE_ORIGINAL_READ` 时调用 `GET /api/source-messages/{sourceMessageId}/conversation`,定位当前 SourceMessage 后按 `external_media_id` / `attachment_id` 匹配对应附件。 - 非图片附件统一显示文件列表,至少展示文件名、类型和大小,并提供下载动作;第一版不在 Payment 卡内嵌 PDF、Word、Excel 或压缩包预览。 +- 2026-07-24 已确认:用户触发图片预览或文件下载时,前端 DOM 的 `img[src]` 或 `a[href]` 可以临时持有 conversation 接口返回的受权限附件 URL。该允许范围只覆盖当前用户、当前 SourceMessage、被 Payment `attachment_ids[]` 引用的附件和当前页面渲染 / 下载动作;V4 task detail API、页面可见文本、确认 payload、日志、错误上报、URL query 和 localStorage 仍不得暴露附件 URL。 - 入站 `PAYMENT.attachment_ids[]` 无法匹配同包 `source_message.attachments[].id` 时,不创建用户可处理 Payment 卡,只写 `adapter_contract_error` transition 或按 S10 / 技术异常规则处理。只有 `attachment_ids[]` 已合法匹配、但用户缺少原文读取权限、会话接口失败、附件 URL 缺失或媒体预览链路暂不可用时,Payment 卡才展示安全摘要和“无法预览 / 无法下载”的状态,不应把附件 URL 或错误详情暴露给普通用户。 - 前端不得把附件外链写入日志、错误上报、URL query、localStorage 或确认 payload;Payment 第一版确认卡片时只提交 `version` 和必要审计说明,不提交 `attachment_ids[]`、附件 URL 或完整附件对象。后续如需支持人工选择 / 增删付款凭证附件,必须另行定义数组编辑契约和后端审计口径。 diff --git a/docs/project/requirements/M002-v4-requirement-spec-template-alignment.md b/docs/project/requirements/M002-v4-requirement-spec-template-alignment.md index eaba809..d477383 100644 --- a/docs/project/requirements/M002-v4-requirement-spec-template-alignment.md +++ b/docs/project/requirements/M002-v4-requirement-spec-template-alignment.md @@ -93,6 +93,7 @@ Reservation V4 还必须满足 `docs/project/ai-nses-project-overlay.md` 的项 - 图片附件在卡片内展示缩略图,点击打开大图预览。 - 非图片附件统一显示文件列表和下载动作,不在卡片内嵌 PDF、Word、Excel 或压缩包预览。 - 图片预览和非图片下载的真实 URL 只能通过 `GET /api/source-messages/{sourceMessageId}/conversation` 原文权限链路取得。 +- 已确认允许用户触发图片预览或文件下载时,前端 DOM 的 `img[src]` 或 `a[href]` 临时持有 conversation 接口返回的受权限附件 URL;该 URL 仍不得出现在 V4 task detail API、页面可见文本、确认 payload、日志、URL query、localStorage 或错误上报中。 - Payment 确认只提交 `version`,不提交 `attachment_ids[]`、附件 URL 或完整附件对象。 ### 7.3 Rooming List @@ -138,6 +139,7 @@ Reservation V4 还必须满足 `docs/project/ai-nses-project-overlay.md` 的项 - 造数应使用唯一 runId,不复用旧 SourceMessage 时间线导致阻塞误判。 - 为了让目标业务卡可操作,可以先确认同 order task 内 Basic Information;目标卡本身不得提前确认。 - 每条样例应记录 orderId、orderTaskId、sourceMessageId、目标 cardId、version、卡片状态、允许动作和安全扫描结果。 +- 2026-07-24 测试机已完成 6 条 fresh V4 order task 数据集,覆盖 Basic、Room Information、Trace General、Trace Extra Bed Review、Rooming List 和 Payment;只执行造数和必要 Basic 前置确认,未确认目标业务卡、未执行 review-resolution、未 ack。 ## 8. 接口或交互契约 @@ -176,15 +178,33 @@ Reservation V4 还必须满足 `docs/project/ai-nses-project-overlay.md` 的项 | REVIEW_REQUIRED 原卡复核、按钮显示“确认卡片” | Done | Done | Passed | V4 领域模型、前后端协作文档 | Implemented | | SourceMessage Display 底部展示、正文默认折叠 | Done | Done | Passed | V4 领域模型、安全边界、前后端协作文档 | Implemented | | V4 工作台 / 订单详情 / 任务详情普通员工用户化展示 | N/A | Done | Passed | V4 领域模型、前后端协作文档 | Implemented | -| 单卡可操作态测试数据 | N/A | N/A | Pending | 本文 | Approved | +| 单卡可操作态测试数据 | N/A | N/A | Passed | 本文第 9.1 节 | Implemented | | 模板化 Spec 对齐 | N/A | N/A | N/A | 本文、AI-NSES Overlay、项目索引 | Implemented | +### 9.1 单卡可操作态 Smoke 回填 + +2026-07-24 测试机数据集 `M002-CARD-DEMO-1784726894698` 已完成。该数据集用于演示和验证每类目标业务卡处于单卡可操作态,目标卡均未提前确认。 + +| 样例 | orderId | orderTaskId | sourceMessageId | targetCardId | 目标状态 | +| --- | --- | --- | --- | --- | --- | +| BASIC | `2079921478960455682` | `2079921478968844290` | `2079921475227525122` | `2079921478994010113` | `PENDING_CONFIRM`,`confirmable=true` | +| ROOM | `2079921487558778881` | `2079921487571361794` | `2079921484266250241` | `2079921487625887745` | `PENDING_CONFIRM`,`confirmable=true` | +| TRACE_GENERAL | `2079921506877743106` | `2079921506886131713` | `2079921501228015618` | `2079921506915491842` | `PENDING_CONFIRM`,`confirmable=true` | +| TRACE_EXTRA_BED_REVIEW | `2079921521973043201` | `2079921521985626113` | `2079921516902129666` | `2079921522035957761` | `REVIEW_REQUIRED`,`reviewable=true` | +| ROOMING_LIST | `2079921534555955202` | `2079921534576926722` | `2079921531255037954` | `2079921534610481153` | `PENDING_CONFIRM`,`confirmable=true` | +| PAYMENT | `2079921555439394817` | `2079921555447783426` | `2079921543749869569` | `2079921555477143553` | `PENDING_CONFIRM`,`confirmable=true` | + +写操作范围:只执行 ROOM、TRACE_GENERAL、TRACE_EXTRA_BED_REVIEW、ROOMING_LIST、PAYMENT 五条样例的 Basic Information 前置确认,请求体均为 `{ "version": 0 }`;未确认目标业务卡、未执行复核提交、未确认来源通知。 + +安全结论:6 条 V4 task detail API 均未返回 `ai_payload_json`、`raw_evidence`、`html_body`、`text_body`、`target_order`、附件 URL、`externalUrl`、`download_url` 或 `signedUrl`;页面可见文本也未展示上述敏感字段或 URL。Payment 页面在图片预览 / PDF 下载能力中,DOM 属性出现 conversation 接口返回的受权限附件 URL,按第 7.2 节口径允许,不视为 V4 task detail API 或页面可见文本泄漏。 + ## 10. 验收标准 - Given 一个新的 V4 需求改变业务卡、接口、页面交互或安全边界,When 分派给后端 / 前端 / 测试 agent,Then 必须先引用本文或后续 Change Request,并列出需求追踪表。 - Given 一个普通酒店员工打开任务列表、订单总览或订单事项办理页,When 页面默认加载,Then 不应在主信息层级展示 V4 模型、JSON Pointer、payload、内部 ID、route 或 adapter 诊断。 - Given Room Information 存在多个 `room_items[]`,When 打开 V4 任务详情,Then API 和页面都应展示多行房型,不把组合 code 当成单个合法房型。 - Given Payment 卡引用图片和非图片附件,When 打开 V4 任务详情,Then 任务详情 API 只返回附件安全摘要,前端通过 SourceMessage 原文权限链路展示图片预览和非图片下载。 +- Given 用户触发 Payment 图片预览或非图片下载,When 浏览器渲染预览或下载入口,Then DOM `src/href` 可以临时使用 conversation 接口返回的受权限附件 URL,但页面可见文本、V4 task detail API、确认 payload、日志和本地存储仍不得暴露该 URL。 - Given Rooming List 卡被确认且同订单 Group 有可更新 Room Information 快照,When 刷新详情,Then Group Booking Status 显示 `DEF-Definite` 并可查到自动 DEF 审计。 - Given Trace 卡确认或复核成功,When 刷新详情,Then `fields[].value` 显示已确认值,旧 validation errors 清空。 @@ -193,7 +213,7 @@ Reservation V4 还必须满足 `docs/project/ai-nses-project-overlay.md` 的项 - 单元测试:本文不新增代码测试;后续代码变更仍按对应前后端模块测试要求执行。 - 集成测试:本文不改变接口;已有 smoke 已覆盖主要 V4 卡片链路。 - 手工验证:本次文档 checkpoint 使用 `git diff --check` 验证 Markdown 格式。 -- 后续 smoke:需要测试 agent 继续补“单卡可操作态”数据集并回填结果。 +- 后续 smoke:单卡可操作态数据集已回填;后续如需要可继续用 fresh runId 造演示数据,避免复用旧 SourceMessage 时间线造成阻塞误判。 ## 12. 未确认问题 diff --git a/docs/project/security-access-control-boundary.md b/docs/project/security-access-control-boundary.md index 6a33eac..6ada945 100644 --- a/docs/project/security-access-control-boundary.md +++ b/docs/project/security-access-control-boundary.md @@ -87,7 +87,7 @@ | --- | --- | --- | --- | --- | | `GET /api/source-messages` | `FRONTEND_USER` | 已强制 Bearer 登录 + `SOURCE_MESSAGE_READ`;列表条件中的酒店按当前用户可访问酒店校验 | 保持登录 + `SOURCE_MESSAGE_READ` + 酒店访问权 | 只读摘要不写审计 | | `GET /api/source-messages/{id}` | `FRONTEND_USER` | 已强制 Bearer 登录 + `SOURCE_MESSAGE_READ`;按消息实际所属酒店校验访问权 | 保持登录 + `SOURCE_MESSAGE_READ` + 消息所属酒店访问权 | 只读摘要不写审计 | -| `GET /api/source-messages/{id}/conversation` | `FRONTEND_USER` | 已强制 Bearer 登录 + `SOURCE_MESSAGE_READ` + `SOURCE_MESSAGE_ORIGINAL_READ`;按消息实际所属酒店校验访问权;返回会话完整 text/html 和媒体 URL | 保持登录 + `SOURCE_MESSAGE_READ` + `SOURCE_MESSAGE_ORIGINAL_READ` + 消息所属酒店访问权;V4 任务详情页来源邮件卡读取正文、Payment 图片大图预览和非图片下载都必须走本接口,并且只使用当前触发该 order task 的 SourceMessage 内容和被 Payment `attachment_ids[]` 引用的附件;Payment 摘要匹配不得使用跨酒店 SourceMessage 或本系统内部媒体 row ID | 必须写原文读取审计,actor 使用当前登录用户稳定 ID;前端展示 HTML 优先使用 `html_body_sanitized`;前端不得把附件 `externalUrl` 写入确认 payload、日志、错误上报、URL query 或 localStorage | +| `GET /api/source-messages/{id}/conversation` | `FRONTEND_USER` | 已强制 Bearer 登录 + `SOURCE_MESSAGE_READ` + `SOURCE_MESSAGE_ORIGINAL_READ`;按消息实际所属酒店校验访问权;返回会话完整 text/html 和媒体 URL | 保持登录 + `SOURCE_MESSAGE_READ` + `SOURCE_MESSAGE_ORIGINAL_READ` + 消息所属酒店访问权;V4 任务详情页来源邮件卡读取正文、Payment 图片大图预览和非图片下载都必须走本接口,并且只使用当前触发该 order task 的 SourceMessage 内容和被 Payment `attachment_ids[]` 引用的附件;Payment 摘要匹配不得使用跨酒店 SourceMessage 或本系统内部媒体 row ID | 必须写原文读取审计,actor 使用当前登录用户稳定 ID;前端展示 HTML 优先使用 `html_body_sanitized`;用户触发 Payment 图片预览或非图片下载时,DOM `img[src]` / `a[href]` 可以临时持有本接口返回的受权限附件 URL;前端不得把附件 `externalUrl` 写入确认 payload、日志、错误上报、URL query 或 localStorage,也不得作为页面可见文本展示 | | `GET /api/source-messages/{id}/original` | `FRONTEND_USER` | 已强制 Bearer 登录 + `SOURCE_MESSAGE_READ` + `SOURCE_MESSAGE_ORIGINAL_READ`;按消息实际所属酒店校验访问权;不再使用原文读取 access key | 保持登录 + `SOURCE_MESSAGE_READ` + `SOURCE_MESSAGE_ORIGINAL_READ` + 消息所属酒店访问权 | 必须写原文读取审计,actor 使用当前登录用户稳定 ID | ### 3.4 系统管理后台接口