收口预约只读接口权限与酒店隔离

This commit is contained in:
andy
2026-07-16 11:27:23 +07:00
parent 9a2812fe74
commit 5c0a5d21d0
22 changed files with 877 additions and 63 deletions

View File

@@ -15,6 +15,8 @@
- 前端不得保存或传递后端 Secret、replay access key、Provider API Key、Oracle 凭证、AgentBus Token。
- 后端数据库 ID 未来应尽量以字符串形式给前端,避免 JavaScript 长整型精度问题;如果当前接口仍返回数字,前端不要自行做数学运算。
- 接口字段发生变化前,需要先更新本目录沟通文档或对应需求文档。
- 前端接口新增或字段变更时,后端需同步更新 `docs/project/security-access-control-boundary.md`前端也应按该文档区分普通业务、系统管理、Debug 和第三方接口。
- 前端页面不得把 Debug、Demo、Replay、Probe 等系统调试接口当成普通用户能力;这类入口需要环境开关和专门权限。
## 3. 字段来源注意事项
@@ -50,19 +52,19 @@
| `POST /api/auth/login` | 用户名密码登录 | 成功后返回 `access_token`、当前用户、可访问酒店、权限码和可见菜单token 只放 `sessionStorage`,不要放 `localStorage`、URL、日志或错误上报。 |
| `GET /api/auth/me` | 恢复当前登录态 | 前端启动后带 `Authorization: Bearer <access_token>` 调用401 时清理 token 并进入登录页。 |
| `POST /api/auth/logout` | 登出当前 session | 带 `Authorization: Bearer <access_token>`;成功后前端必须清理本地 token 和当前用户上下文。 |
| `GET /api/reservation/orders` | 查询订单列表 | 默认返回全部订单状态;按后端维护的订单最近业务活动时间倒序,当前落库字段为 `workflow_reservation_order.latest_activity_at`,前端不要自行重排;`open_task_count` 排除 `COMPLETED``FAILED`;隐藏技术订单不返回,因此 S10/S99 和旧 S000/S999 不会在订单列表形成订单。 |
| `GET /api/reservation/tasks` | 查询任务列表 / 工作台 | 未传 `order_id` 时按来源消息接收时间倒序,传 `order_id` 时按同订单队列顺序正序;用 `can_process``readonly_reason_code` 控制入口按钮;列表不返回 AI 原始 payload、邮件正文或附件 URL已返回来源邮件会话摘要字段并支持 `order_status` 按任务所属订单状态筛选;旧 S000/S999 和新 S10/S99 都以 `task_type=SOURCE_MESSAGE_ONLY` 只读任务返回,列表已透出 `result_type``ai_task_type``route_code``system_process_category`。 |
| `GET /api/reservation/orders/{orderId}` | 查询订单详情与任务时间线 | `include_tasks=false` 可只取订单摘要;时间线按后端队列顺序返回,前端不要自行按创建时间重排;`tasks[]` 已返回来源邮件会话摘要字段和 V3 路由字段;隐藏技术订单详情不可作为普通订单页打开。 |
| `GET /api/reservation/tasks/{taskId}` | 查询任务详情 | 以返回的可处理状态和只读原因控制按钮,不只看任务状态;`fields[]` 已包含 P0 字段元数据;源邮件只读通知卡字段列表和 OPERA 操作列表为空;结构化 S10/S99 通过 `source_message_only_result.agent_assessment``notification``manual_review` 展示;普通业务任务可通过 `adapter_contract_errors[]``unhandled_intents[]` 查看同批次未建任务的诊断信息type-known manual review 会返回顶层 `review_status``review_resolution``manual_review`。 |
| `GET /api/reservation/orders` | 查询订单列表 | 必须带 `Authorization: Bearer <access_token>`,需要 `RESERVATION_ORDER_READ`默认返回全部订单状态;按后端维护的订单最近业务活动时间倒序,当前落库字段为 `workflow_reservation_order.latest_activity_at`,前端不要自行重排;`open_task_count` 排除 `COMPLETED``FAILED`;隐藏技术订单不返回,因此 S10/S99 和旧 S000/S999 不会在订单列表形成订单。 |
| `GET /api/reservation/tasks` | 查询任务列表 / 工作台 | 必须带 Bearer token需要 `RESERVATION_TASK_READ`未传 `order_id` 时按来源消息接收时间倒序,传 `order_id` 时按同订单队列顺序正序;用 `can_process``readonly_reason_code` 控制入口按钮;列表不返回 AI 原始 payload、邮件正文或附件 URL已返回来源邮件会话摘要字段并支持 `order_status` 按任务所属订单状态筛选;旧 S000/S999 和新 S10/S99 都以 `task_type=SOURCE_MESSAGE_ONLY` 只读任务返回,列表已透出 `result_type``ai_task_type``route_code``system_process_category`。 |
| `GET /api/reservation/orders/{orderId}` | 查询订单详情与任务时间线 | 必须带 Bearer token需要 `RESERVATION_ORDER_READ`,后端按订单所属酒店做访问校验;`include_tasks=false` 可只取订单摘要;时间线按后端队列顺序返回,前端不要自行按创建时间重排;`tasks[]` 已返回来源邮件会话摘要字段和 V3 路由字段;隐藏技术订单详情不可作为普通订单页打开。 |
| `GET /api/reservation/tasks/{taskId}` | 查询任务详情 | 必须带 Bearer token需要 `RESERVATION_TASK_READ`,后端按任务所属酒店做访问校验;以返回的可处理状态和只读原因控制按钮,不只看任务状态;`fields[]` 已包含 P0 字段元数据;源邮件只读通知卡字段列表和 OPERA 操作列表为空;结构化 S10/S99 通过 `source_message_only_result.agent_assessment``notification``manual_review` 展示;普通业务任务可通过 `adapter_contract_errors[]``unhandled_intents[]` 查看同批次未建任务的诊断信息type-known manual review 会返回顶层 `review_status``review_resolution``manual_review`。 |
| `PUT /api/reservation/tasks/{taskId}/draft` | 保存任务草稿 | 只保存草稿,不代表用户最终确认。 |
| `POST /api/reservation/tasks/{taskId}/confirm` | 最终确认任务 | 后端会做第一版字段校验,通过后进入 `READY`。 |
| `POST /api/reservation/tasks/{taskId}/manual-review-conversions` | Fallback 人工转换 | 只用于 manual_review / fallback不用于普通任务切换订单。 |
| `POST /api/reservation/tasks/{taskId}/manual-review-resolutions` | type-known manual review 同卡复核解阻 | 只用于已知业务类型的 `result_type=manual_review` 任务;提交 `field_overrides[]` 和当前订单归属确认,通过后进入 `READY` 并生成两条 OPERA 模拟操作。 |
| `POST /api/reservation/tasks/{taskId}/opera-operations/{operationId}/execute` | 执行 OPERA 模拟操作 | 当前是模拟,不调用真实 OPERA。 |
| `POST /api/reservation/tasks/{taskId}/opera-operations/{operationId}/retry` | 重试失败 OPERA 模拟操作 | 重试会追加 attempt 历史,前端不要覆盖旧失败记录。 |
| `GET /api/reservation/tasks/{taskId}/audits` | 查询任务审计流水 | 用于展示人工确认、转换、模拟操作等轨迹。 |
| `GET /api/source-messages` | 查询来源消息安全摘要 | 列表不返回邮件正文、HTML、附件 URL 或原始 payload。 |
| `GET /api/source-messages/{id}` | 查询来源消息安全详情 | 只用于安全摘要详情。 |
| `GET /api/reservation/tasks/{taskId}/audits` | 查询任务审计流水 | 必须带 Bearer token需要 `RESERVATION_AUDIT_READ`,后端按任务所属酒店做访问校验;用于展示人工确认、转换、模拟操作等轨迹。 |
| `GET /api/source-messages` | 查询来源消息安全摘要 | 必须带 Bearer token需要 `SOURCE_MESSAGE_READ`列表不返回邮件正文、HTML、附件 URL 或原始 payload。 |
| `GET /api/source-messages/{id}` | 查询来源消息安全详情 | 必须带 Bearer token需要 `SOURCE_MESSAGE_READ`,后端按消息所属酒店做访问校验;只用于安全摘要详情。 |
| `GET /api/source-messages/{id}/original` | 读取来源消息原文 | 需要受控访问头,返回 HTML 时前端展示前必须 sanitize。 |
| `GET /api/source-messages/{sourceMessageId}/conversation` | 读取邮件会话详情 | 返回同一外部会话全部邮件的完整 text/html、`html_body_sanitized`、附件外链、内联图片和关联订单 / 任务摘要;前端不传原文读取 key展示 HTML 时优先使用 `html_body_sanitized`。 |
| `POST /api/system/debug/eml-superagent-runs` | Debug 页面上传 `.eml` 并调用 SuperAgent | 仅 dev/test 受控调试使用;会写入 SourceMessage Inbox但不创建订单和任务。 |
@@ -86,7 +88,7 @@
| `GET /api/source-messages/{sourceMessageId}/conversation` | 新增邮件会话详情接口,并补齐 `html_body_sanitized` / `html_render_mode`。 | 当前唯一推荐路径是这个接口;前端渲染邮件 HTML 时优先使用 `html_body_sanitized`;不要调用历史讨论过的 `/api/source-message-conversations/{externalConversationId}`。 |
| `POST /api/system/debug/eml-superagent-runs` | 新增 Debug EML 上传到 SuperAgent 调试接口,并补齐独立 Debug 外部消息 ID、原始 Message-ID 保留、安全 HTML 字段和入口通知识别。 | 只用于调试页面;请求为 multipart/form-data必须传 `X-TH-Hotel-Debug-Upload-Key`,但该 key 不能写进前端源码、构建产物、URL、localStorage 或错误上报SuperAgent 返回旧 S000/S999 或新 S10/S99 入口通知时都不应被前端视为 JSON 解析失败。 |
酒店上下文注意Reservation 列表、订单详情、任务列表和 Debug EML 上传的 `hotel_id` 第一版都是可选参数。前端默认可以不传;后端按当前登录用户酒店上下文或平台酒店表唯一 `ACTIVE` 酒店解析。如果前端传了当前选中酒店后端会校验该酒店是否可访问。
酒店上下文注意Reservation 列表、订单详情、任务列表和 Debug EML 上传的 `hotel_id` 第一版都是可选参数。对已收口的 Reservation / SourceMessage 只读接口,前端必须先登录并带 Bearer token不传 `hotel_id`后端按当前登录用户默认酒店或对象所属酒店校验,传了当前选中酒店后端会校验该酒店是否可访问。Debug EML 仍按调试入口规则受控,不属于本轮登录权限收口范围。
### 5.2 登录权限接入注意
@@ -102,13 +104,17 @@ POST /api/auth/logout
- 登录成功后只把 `access_token` 保存到 `sessionStorage`;刷新同一浏览器会话可恢复,关闭浏览器后需要重新登录。
- 所有需要登录态的后端请求使用 `Authorization: Bearer <access_token>`
- 当前后端第一版不强制拦截既有 Reservation / SourceMessage 业务接口;但是前端接入登录后应统一带上 Bearer token方便后续审计 actor 和权限收口
- 当前后端强制拦截第一批 Reservation / SourceMessage 只读接口任务列表、订单列表、订单详情、任务详情、任务审计列表、SourceMessage 摘要列表和摘要详情。调用这些接口必须带 Bearer token
- 第一批只读接口权限码分别是:`RESERVATION_TASK_READ``RESERVATION_ORDER_READ``RESERVATION_AUDIT_READ``SOURCE_MESSAGE_READ`。前端菜单、按钮和路由守卫应使用 `/api/auth/me` 返回的 `permissions[]``menus[]`
- 后端会按当前登录用户的可访问酒店集合做隔离;显式传 `hotel_id` 时会校验该酒店是否可访问,按 `orderId``taskId``sourceMessageId` 定位的详情接口会反查对象实际所属酒店并校验访问权。
- Reservation 写操作、邮件原文 / conversation 完整正文、Debug / Demo / Replay / Probe 等接口仍按 `../security-access-control-boundary.md` 的分阶段计划继续收口,前端不要自行假设它们和第一批只读接口完全一致。
- `/api/auth/me` 返回 `user``default_hotel_id``hotels[]``permissions[]``menus[]`;菜单入口应优先使用 `menus[]`不要继续硬编码订单列表、任务队列、Debug EML。
- `menus[]` 只包含可见菜单;订单详情、任务详情和邮件会话详情是隐藏详情路由,不会作为菜单项返回。
- `DEBUG_EML_SUPERAGENT` 菜单第一版只授予 `SYSTEM_ADMIN`;这只表示页面入口是否可见,不代表后端会把 `X-TH-Hotel-Debug-Upload-Key` 下发给前端。
- `user.id` 是字符串;前端不要把任何后端 ID 转成 JavaScript number。
- 登录失败统一显示用户名或密码错误,不要根据错误文案推断账号是否存在或是否禁用。
- 401 的 `AUTH_TOKEN_REQUIRED` / `AUTH_SESSION_INVALID` 应统一走清理 token、回登录页的逻辑。
- 403 的 `FRONTEND_PERMISSION_DENIED` 表示当前用户没有对应业务权限;`HOTEL_ACCESS_DENIED` 表示用户无权访问目标酒店或对象所属酒店,前端应展示无权限状态,不要重试或静默降级为 404。
### 5.3 来源邮件会话字段说明

View File

@@ -0,0 +1,192 @@
# TH Hotel 接口暴露、权限与审计边界
## 1. 文档定位
本文是当前项目的接口安全边界总表,用于后续新增接口、大改调用方、调整权限或补审计时统一判断:
- 哪些接口给前端用户调用。
- 哪些接口给第三方系统调用。
- 哪些能力只能后端内部使用,不能暴露给前端或第三方。
- 每类接口应采用什么鉴权方式、权限码、酒店隔离和审计策略。
如本文与具体接口契约冲突:
- SuperAgent / MCP / AgentBus 对外契约以 `docs/project/integrations/superagent-api-contract.md``docs/project/integrations/superagent-mcp/README.md` 和对应集成文档为准。
- 前端展示和字段契约以 `docs/project/frontend-backend/README.md` 指向的当前有效文档为准。
- 权限、审计、暴露边界以本文为补充检查清单,接口变更时必须同步更新。
## 2. 调用方分类
| 分类 | 中文说明 | 典型调用方 | 默认鉴权方式 |
| --- | --- | --- | --- |
| `PUBLIC` | 公开基础接口,只能返回非敏感健康或登录入口信息 | 浏览器、运维探活 | 无登录;不能返回业务数据 |
| `FRONTEND_USER` | 普通业务前端接口 | 登录后的酒店业务用户 | Bearer session token + 权限码 + 酒店访问权 |
| `FRONTEND_ADMIN` | 系统管理后台接口 | 系统管理员 | Bearer session token + 管理权限码 + 管理审计 |
| `FRONTEND_DEBUG` | 调试或演示接口 | 开发、测试、受控管理员 | 环境开关 + 登录权限或临时 access key + 调试审计 |
| `THIRD_PARTY_SUPERAGENT` | SuperAgent HTTP 对接接口 | SuperAgent Runtime / Skill | HMAC-SHA256 + timestamp + nonce + body hash |
| `THIRD_PARTY_AGENTBUS` | AgentBus 实时消息入口 | AgentBus WebSocket | AgentBus Token + 环境开关 + 入库幂等 |
| `THIRD_PARTY_MCP` | SuperAgent MCP 写入工具 | SuperAgent MCP Client | Bearer Token + 工具级能力限制 |
| `INTERNAL_ONLY` | 后端内部能力,不对外直接暴露 | Worker、Adapter、Repository、Mapper | 不提供外部入口;通过 Service / Port 调用 |
## 3. 当前接口边界矩阵
### 3.1 公开和登录接口
| 接口 / 能力 | 分类 | 当前管控 | 目标管控 | 审计要求 |
| --- | --- | --- | --- | --- |
| `GET /api/health` | `PUBLIC` | 无登录;只返回健康状态 | 保持公开,但不得返回配置、版本 Secret 或数据库细节 | 不需要业务审计 |
| `POST /api/auth/login` | `PUBLIC` | 用户名密码登录,返回一次性 `access_token` | 增加登录失败频率控制和登录安全审计可后置 | 建议补登录安全审计 |
| `GET /api/auth/me` | `FRONTEND_USER` | 必须 Bearer token | 保持强制登录,返回权限、菜单和酒店上下文 | 不需要每次写业务审计 |
| `POST /api/auth/logout` | `FRONTEND_USER` | 必须 Bearer token | 保持强制登录,撤销当前 session | 可记录安全审计 |
### 3.2 前端业务接口
| 接口 / 能力 | 分类 | 当前管控 | 目标管控 | 审计要求 |
| --- | --- | --- | --- | --- |
| `GET /api/reservation/tasks` | `FRONTEND_USER` | 已强制 Bearer 登录 + `RESERVATION_TASK_READ`;支持可选 `hotel_id` 并校验酒店访问权 | 保持登录 + `RESERVATION_TASK_READ` + 酒店访问权 | 只读查询默认不写业务审计 |
| `GET /api/reservation/orders` | `FRONTEND_USER` | 已强制 Bearer 登录 + `RESERVATION_ORDER_READ`;支持可选 `hotel_id` 并校验酒店访问权 | 保持登录 + `RESERVATION_ORDER_READ` + 酒店访问权 | 只读查询默认不写业务审计 |
| `GET /api/reservation/orders/{orderId}` | `FRONTEND_USER` | 已强制 Bearer 登录 + `RESERVATION_ORDER_READ`;按订单实际所属酒店校验访问权 | 保持登录 + `RESERVATION_ORDER_READ` + 订单所属酒店访问权 | 只读查询默认不写业务审计 |
| `GET /api/reservation/tasks/{taskId}` | `FRONTEND_USER` | 已强制 Bearer 登录 + `RESERVATION_TASK_READ`;按任务实际所属酒店校验访问权 | 保持登录 + `RESERVATION_TASK_READ` + 任务所属酒店访问权 | 只读查询默认不写业务审计 |
| `PUT /api/reservation/tasks/{taskId}/draft` | `FRONTEND_USER` | 第一版未全量强制登录actor 仍待迁移 | 登录 + `RESERVATION_TASK_EDIT` + 酒店访问权 | 写草稿审计可按业务需要记录 |
| `POST /api/reservation/tasks/{taskId}/confirm` | `FRONTEND_USER` | 第一版未全量强制登录actor 仍待迁移 | 登录 + `RESERVATION_TASK_CONFIRM` + 酒店访问权 | 必须写业务审计 |
| `POST /api/reservation/tasks/{taskId}/manual-review-conversions` | `FRONTEND_USER` | 第一版已写业务审计,但 actor 待迁移 | 登录 + `RESERVATION_MANUAL_REVIEW_RESOLVE` + 酒店访问权 | 必须写业务审计和原因 |
| `POST /api/reservation/tasks/{taskId}/manual-review-resolutions` | `FRONTEND_USER` | 第一版已写业务审计,但 actor 待迁移 | 登录 + `RESERVATION_MANUAL_REVIEW_RESOLVE` + 酒店访问权 | 必须写业务审计 |
| `POST /api/reservation/tasks/{taskId}/opera-operations/{operationId}/execute` | `FRONTEND_USER` | 当前为 OPERA 模拟 | 登录 + `RESERVATION_OPERA_SIM_EXECUTE` + 酒店访问权 | 必须写业务审计和 attempt |
| `POST /api/reservation/tasks/{taskId}/opera-operations/{operationId}/retry` | `FRONTEND_USER` | 当前为 OPERA 模拟 | 登录 + `RESERVATION_OPERA_SIM_EXECUTE` + 酒店访问权 | 必须写业务审计和 attempt |
| `GET /api/reservation/tasks/{taskId}/audits` | `FRONTEND_USER` | 已强制 Bearer 登录 + `RESERVATION_AUDIT_READ`;按任务实际所属酒店校验访问权 | 保持登录 + `RESERVATION_AUDIT_READ` + 酒店访问权 | 查询审计不再写审计 |
### 3.3 来源邮件接口
| 接口 / 能力 | 分类 | 当前管控 | 目标管控 | 审计要求 |
| --- | --- | --- | --- | --- |
| `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` | 返回会话完整 text/html 和媒体 URL后端内部写原文读取审计 | 登录 + `SOURCE_MESSAGE_READ`,如返回完整正文则还需 `SOURCE_MESSAGE_ORIGINAL_READ` | 必须写原文读取审计 |
| `GET /api/source-messages/{id}/original` | `FRONTEND_USER` | 当前使用受控原文读取 key | 迁移为登录 + `SOURCE_MESSAGE_ORIGINAL_READ` + 酒店访问权access key 仅作兼容或关闭 | 必须写原文读取审计 |
### 3.4 系统管理后台接口
| 接口 / 能力 | 分类 | 当前管控 | 目标管控 | 审计要求 |
| --- | --- | --- | --- | --- |
| `/api/admin/users/**` | `FRONTEND_ADMIN` | 已强制登录和 `SYSTEM_USER_MANAGE` | 保持;禁用用户撤销 session | 写操作必须记录 `platform_admin_audit_log` |
| `/api/admin/roles/**` | `FRONTEND_ADMIN` | 已强制登录和 `SYSTEM_ROLE_MANAGE` | 保持;内置角色只读 | 写操作必须记录管理审计 |
| `/api/admin/permissions` | `FRONTEND_ADMIN` | 已强制登录和 `SYSTEM_ROLE_MANAGE` | 保持只读;前端不能自造权限码 | 不需要写审计 |
| `/api/admin/menus/**` | `FRONTEND_ADMIN` | 已强制登录和 `SYSTEM_MENU_MANAGE` | 保持;菜单可见性不替代后端权限 | 写操作必须记录管理审计 |
| `/api/admin/hotels/**` | `FRONTEND_ADMIN` | 已强制登录和 `HOTEL_MANAGE` | 保持;单酒店阶段只能一家 `ACTIVE` | 写操作必须记录管理审计 |
| `GET /api/admin/audits` | `FRONTEND_ADMIN` | 已强制登录和 `SYSTEM_ADMIN_CONSOLE_ACCESS` | 保持;不返回 Secret、密码或 token | 查询审计不再写审计 |
### 3.5 调试和系统接口
| 接口 / 能力 | 分类 | 当前管控 | 目标管控 | 审计要求 |
| --- | --- | --- | --- | --- |
| `POST /api/system/debug/eml-superagent-runs` | `FRONTEND_DEBUG` | 环境开关 + `X-TH-Hotel-Debug-Upload-Key` | dev/test 可保留 access key长期目标为登录 + `SYSTEM_DEBUG_EML_RUN` + 环境开关 | 写 Debug run必要时补管理 / 调试审计 |
| `GET /api/system/debug/eml-superagent-runs/{runId}` | `FRONTEND_DEBUG` | 环境开关 + access key | 登录 + `SYSTEM_DEBUG_EML_RUN`;避免向普通用户暴露 AI 原始结果 | 只读调试可记录访问日志 |
| `POST /api/system/debug/eml-superagent-runs/stream` | `FRONTEND_DEBUG` | 环境开关 + access key | 登录 + `SYSTEM_DEBUG_EML_RUN`;生产默认关闭 | 写 Debug run 和安全错误摘要 |
| `GET /api/system/agentbus-probe` | `FRONTEND_DEBUG` | 当前系统状态接口 | 登录 + `SYSTEM_AGENTBUS_PROBE_READ` 或系统管理入口权限 | 不返回 Token、raw frame 或邮件正文 |
| `POST /api/system/reservation/demo-data` | `FRONTEND_DEBUG` | 环境开关 + demo access key | dev/test 使用;生产必须关闭 | 写入演示数据时建议记录调试审计 |
### 3.6 第三方机器接口
| 接口 / 能力 | 分类 | 当前管控 | 目标管控 | 审计要求 |
| --- | --- | --- | --- | --- |
| `POST /api/ai-query/v1/case-context` | `THIRD_PARTY_SUPERAGENT` | HMAC 鉴权 | 保持 HMAC不使用用户 Bearer token | 记录请求 ID、client_id 和安全错误 |
| `POST /api/ai-query/v1/object-detail` | `THIRD_PARTY_SUPERAGENT` | HMAC 鉴权 | 保持 HMAC返回最小必要上下文 | 记录请求 ID、client_id 和安全错误 |
| `POST /api/ai-query/v1/conversation-tasks` | `THIRD_PARTY_SUPERAGENT` | HMAC 鉴权 | 保持 HMAC不返回邮件原文 | 记录请求 ID、client_id 和安全错误 |
| `POST /api/ai-query/v1/conversation-source` | `THIRD_PARTY_SUPERAGENT` | HMAC 鉴权 | 保持 HMAC只按契约返回需要字段 | 记录请求 ID、client_id 和安全错误 |
| `POST /api/integrations/superagent/task-results` | `THIRD_PARTY_SUPERAGENT` | HMAC + nonce + timestamp + body hash | 保持;外部 `source_message_id` 必须匹配 Inbox | 记录 batch、transition、错误和幂等结果 |
| `/mcp` | `THIRD_PARTY_MCP` | Bearer Token提交工具可独立开关 | 保持;工具级能力限制,不暴露无关接口 | 记录工具调用结果和业务入站结果 |
| AgentBus WebSocket | `THIRD_PARTY_AGENTBUS` | AgentBus Token + capture 开关 | 保持;只入 SourceMessage不直接建业务任务 | 记录 SourceMessage、payload hash 和 dispatch run |
### 3.7 后端内部能力
| 能力 | 分类 | 暴露规则 | 审计 / 追踪 |
| --- | --- | --- | --- |
| Repository / Mapper / Entity | `INTERNAL_ONLY` | 不对 Controller、前端或第三方直接暴露 | 通过 Service 写审计 |
| SuperAgent Open API Client | `INTERNAL_ONLY` | 只能后端 Adapter 使用Secret 不出后端 | 通过 debug run 或 dispatch run 追踪 |
| OSS Adapter | `INTERNAL_ONLY` | 前端只能拿后端返回的安全 URL不能拿 OSS Secret | 上传和读取入口记录安全摘要 |
| AgentBus dispatch worker | `INTERNAL_ONLY` | 只由后端调度或受控管理入口触发 | `platform_superagent_dispatch_run` |
| Flyway / bootstrap 初始化 | `INTERNAL_ONLY` | 不提供运行时外部接口 | 通过部署记录和数据库 history 追踪 |
| 未来 OPERA / OHIP Adapter | `INTERNAL_ONLY` | 浏览器不得直接调用;只能业务服务触发 | 必须记录操作、attempt 和外部结果摘要 |
## 4. 权限码规划口径
当前管理后台权限码已经落地。业务接口收口时建议新增或确认以下权限码,不要求一次性全部实现:
| 权限码 | 中文含义 | 适用接口 |
| --- | --- | --- |
| `RESERVATION_ORDER_READ` | 查看订单列表和订单详情 | 订单列表、订单详情 |
| `RESERVATION_TASK_READ` | 查看任务列表和任务详情 | 任务列表、任务详情 |
| `RESERVATION_TASK_EDIT` | 保存任务草稿或编辑可写字段 | 草稿保存 |
| `RESERVATION_TASK_CONFIRM` | 最终确认任务 | 任务确认 |
| `RESERVATION_MANUAL_REVIEW_RESOLVE` | 处理人工复核和 Fallback 转换 | 复核解阻、Fallback 转换 |
| `RESERVATION_OPERA_SIM_EXECUTE` | 执行或重试 OPERA 模拟 / 未来真实操作 | OPERA execute / retry |
| `RESERVATION_AUDIT_READ` | 查看业务审计流水 | 任务审计列表 |
| `SOURCE_MESSAGE_READ` | 查看来源邮件安全摘要 | SourceMessage 列表、详情、会话摘要 |
| `SOURCE_MESSAGE_ORIGINAL_READ` | 查看邮件正文、HTML 和附件外链 | original / conversation 完整正文 |
| `SYSTEM_DEBUG_EML_RUN` | 使用 Debug EML 调试链路 | Debug EML 上传、查询、stream |
| `SYSTEM_AGENTBUS_PROBE_READ` | 查看 AgentBus 安全状态 | AgentBus probe |
如果新增权限码,必须同步:
1. `PlatformPermissionCode` 枚举。
2. 内置角色权限矩阵。
3. `docs/project/security-access-control-boundary.md`
4. 前后端协作文档中对应页面按钮或菜单说明。
## 5. 酒店隔离规则
- 前端用户接口必须从当前登录用户解析可访问酒店集合。
- 显式传入 `hotel_id` 时,后端必须校验该用户是否可访问该酒店。
- 未传 `hotel_id` 时,单酒店阶段可按用户默认酒店或系统唯一 `ACTIVE` 酒店解析。
- 直接按 `taskId``orderId``sourceMessageId` 定位的接口,必须反查对象所属 `hotel_id` 并校验访问权;当前已覆盖 Reservation 订单详情、任务详情、任务审计列表和 SourceMessage 摘要详情。
- 第三方 SuperAgent 接口第一版不依赖用户酒店权限,但必须使用系统酒店解析 SourceMessage并防止跨酒店误匹配。
- AgentBus 入站不接受外部随意指定酒店;单酒店阶段由系统唯一 `ACTIVE` 酒店解析。
## 6. 审计分层
| 审计类型 | 当前载体 | 必须记录的动作 |
| --- | --- | --- |
| 管理审计 | `platform_admin_audit_log` | 用户、角色、权限、菜单、酒店的写操作 |
| 业务审计 | `workflow_reservation_audit_log` | 任务确认、人工复核、订单归属确认、OPERA 执行 / 重试 |
| 邮件原文读取审计 | `platform_source_message_original_access_audit` | 读取邮件正文、HTML、附件外链 |
| SuperAgent 入站追踪 | `workflow_reservation_ai_batch``workflow_reservation_ai_transition` | task-results / MCP 提交、路由、adapter error |
| AgentBus 分发追踪 | `platform_superagent_dispatch_run` | SourceMessage 自动分发 SuperAgent、重试、失败摘要 |
| 安全审计 | 后续可新增平台安全审计表 | 登录失败、签名失败、nonce 重放、越权访问 |
业务侧后续收口重点:
- 业务写操作 actor 从本地占位迁移到当前登录用户。
- 第三方入站 actor 保持机器身份,例如 `SUPERAGENT``MCP``AGENTBUS`
- 审计快照不得写入密码、token、secret、完整邮件正文、附件签名 URL 或支付敏感信息。
## 7. 接口变更同步规则
新增或修改任何 Controller、第三方入口、调试入口或后台 worker 触发入口时,必须先回答:
1. 这个接口给谁调用:前端用户、管理员、第三方系统,还是内部 worker
2. 是否需要登录?如果需要,权限码是什么?
3. 是否涉及 `hotel_id`?如何校验用户可访问酒店?
4. 是否返回敏感数据正文、HTML、附件 URL、AI 原始 payload、trace、Secret
5. 是否是写操作写什么审计actor 从哪里来?
6. 是否生产允许?是否需要环境开关?
7. 是否影响 SuperAgent、MCP、AgentBus 或前端契约?
如果任一答案为“是”,必须同步更新以下文档中相关部分:
- 本文档。
- `AGENTS.md``docs/project/backend-development-guidelines.md` 中的开发规则,如果新增了通用规范。
- `docs/project/frontend-backend/backend-to-frontend-notes.md`,如果影响前端。
- `docs/project/integrations/superagent-api-contract.md` 或 MCP / AgentBus 集成文档,如果影响第三方。
- 对应需求文档,例如 M002、M004、M006、M007。
## 8. 建议实施顺序
后续开发权限收口时建议按以下顺序推进:
1. 已完成 CP1Reservation / SourceMessage 第一批只读查询接口已收口登录、权限码和酒店访问权包括任务列表、订单列表、订单详情、任务详情、任务审计列表、SourceMessage 摘要列表和摘要详情。
2. 再收口邮件原文和会话完整正文读取:迁移到 `SOURCE_MESSAGE_ORIGINAL_READ`,保留审计。
3. 再收口 Reservation 写操作草稿、确认、人工复核、OPERA 模拟。
4. 迁移业务审计 actor 到当前登录用户。
5. 最后处理 Debug、Demo、Replay、AgentBus Probe 等系统调试入口。
每一步都应保持第三方机器接口不被误拦截SuperAgent / MCP / AgentBus 继续使用机器鉴权。