收口预约只读接口权限与酒店隔离
This commit is contained in:
@@ -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 来源邮件会话字段说明
|
||||
|
||||
|
||||
Reference in New Issue
Block a user