# 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` + 酒店访问权 | 查询审计不再写审计 |
| `POST /api/reservation/invoices/manual-generations` | `FRONTEND_USER` | 已实现 M009 CP2；强制 Bearer 登录 + `RESERVATION_INVOICE_GENERATE` + 酒店访问权；`task_id` / `order_id` 可为空，传入时反查对象所属酒店 | 保持登录 + `RESERVATION_INVOICE_GENERATE` + 酒店访问权；后续如增加历史列表或预填接口需单独登记权限 | 写业务审计，记录来源类型、模板版本、生成结果摘要；生成失败写入生成记录安全错误摘要 |

### 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` | 已强制 Bearer 登录 + `SOURCE_MESSAGE_READ` + `SOURCE_MESSAGE_ORIGINAL_READ`；按消息实际所属酒店校验访问权；返回会话完整 text/html 和媒体 URL | 保持登录 + `SOURCE_MESSAGE_READ` + `SOURCE_MESSAGE_ORIGINAL_READ` + 消息所属酒店访问权 | 必须写原文读取审计，actor 使用当前登录用户稳定 ID |
| `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 系统管理后台接口

| 接口 / 能力 | 分类 | 当前管控 | 目标管控 | 审计要求 |
| --- | --- | --- | --- | --- |
| `/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`；`GET /tree`、`PUT /tree-order` 已沿用该权限 | 保持；菜单可见性不替代后端权限；批量树排序只允许修改 `parent_id` 和 `sort_order`，`sort_order` 为空时按请求顺序生成稳定排序 | 写操作必须记录管理审计，树排序审计记录调整前后的父级和排序；树查询不写审计 |
| `/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 和安全错误摘要 |
| `POST /api/system/document-conversions/excel-to-pdf` | `FRONTEND_DEBUG` | 环境开关 + `X-TH-Hotel-Document-Conversion-Key`；只支持 `.xls` / `.xlsx`，PDF 输出到 OSS | 长期目标为登录 + 文件转换调试权限 + 环境开关；生产默认关闭 | CP2 不落库；必要时通过网关访问日志和 OSS 对象路径追踪，后续自动转换任务落库后补转换审计 |
| `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` | 查看业务审计流水 | 任务审计列表 |
| `RESERVATION_INVOICE_GENERATE` | 生成 Reservation Proforma Invoice | Manual Invoice 生成、未来任务 / 订单预填生成 |
| `SOURCE_MESSAGE_READ` | 查看来源邮件安全摘要 | SourceMessage 列表、详情、会话摘要 |
| `SOURCE_MESSAGE_ORIGINAL_READ` | 查看邮件正文、HTML 和附件外链 | original / conversation 完整正文；必须叠加 `SOURCE_MESSAGE_READ` 使用 |
| `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. 前后端协作文档中对应页面按钮或菜单说明。

### 4.1 新增接口权限固定流程

后续新增需要前端用户或管理员调用的接口时，必须按同一套流程维护权限，避免“接口能调用但系统设置里管不了”或“前端隐藏了但后端没拦”的不一致。

固定流程：

1. **确认接口分类。** 先判断接口属于 `FRONTEND_USER`、`FRONTEND_ADMIN`、`FRONTEND_DEBUG`、第三方机器接口还是 `INTERNAL_ONLY`。只有前端用户和管理员接口进入用户角色权限模型；SuperAgent、AgentBus、MCP 继续使用机器鉴权，不使用用户 Bearer 权限码。
2. **定义稳定权限码。** 在 `PlatformPermissionCode` 增加稳定英文权限码，例如 `RESERVATION_TASK_ASSIGN`。权限码只表达能力边界，不绑定中文文案、不绑定某个按钮样式。
3. **补启动同步元数据。** 在权限启动同步逻辑中补权限名称、权限分组和状态，确保 `platform_permission` 能自动拥有该权限码。
4. **补内置角色默认矩阵。** 明确 `SYSTEM_ADMIN`、业务操作员、只读角色等内置角色是否默认拥有该权限。内置角色矩阵仍以代码为准；自定义角色后续通过系统设置页面分配。
5. **后端接口强制校验。** 在 Controller 或统一入口中显式调用对应鉴权服务，例如 `requirePermission(PlatformPermissionCode.X.name())`。只读接口同时校验对象所属酒店；写接口还要校验状态、幂等、事务和审计。
6. **前端类型和交互同步。** 在前端权限类型中加入新权限码，路由、菜单、按钮和操作入口按 `/api/auth/me` 返回的 `permissions[]` 控制展示。前端控制只提升体验，不能替代后端权限校验。
7. **系统设置可分配。** 权限启动同步后，系统设置的角色权限页面应能看到该权限码；需要给自定义角色授权时，通过系统设置勾选，用户重新登录或刷新上下文后生效。
8. **补测试。** 至少覆盖无 token、无权限、有权限、跨酒店或对象归属校验。第三方接口要补“不被用户登录拦截误伤”的回归测试。
9. **补文档。** 本文矩阵中登记接口分类、权限码、酒店隔离和审计要求；影响前端时同步 `docs/project/frontend-backend/backend-to-frontend-notes.md`；影响 SuperAgent / MCP / AgentBus 时同步对应集成契约。

最小验收口径：

- 新接口没有 token 时返回该分类约定的 401。
- 已登录但缺权限时返回该分类约定的 403。
- 有权限但访问无权酒店或无权对象时返回酒店 / 对象访问拒绝。
- 权限码能在系统设置角色权限页面看到并分配给自定义角色。
- 前端只做路由、菜单、按钮显示控制，后端仍能拦截直接调用。
- 第三方机器接口不被用户 Bearer 权限模型误拦截。

## 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. 已完成 CP1：Reservation / SourceMessage 第一批只读查询接口已收口登录、权限码和酒店访问权，包括任务列表、订单列表、订单详情、任务详情、任务审计列表、SourceMessage 摘要列表和摘要详情。
2. 已完成 CP2：邮件原文和会话完整正文读取已迁移到 `SOURCE_MESSAGE_READ` + `SOURCE_MESSAGE_ORIGINAL_READ`，并按消息所属酒店校验访问权；原文读取审计 actor 使用当前登录用户稳定 ID。
3. 再收口 Reservation 写操作：草稿、确认、人工复核、OPERA 模拟。
4. 迁移业务审计 actor 到当前登录用户。
5. 最后处理 Debug、Demo、Replay、AgentBus Probe 等系统调试入口。

每一步都应保持第三方机器接口不被误拦截，SuperAgent / MCP / AgentBus 继续使用机器鉴权。
