# 迭代 I7 架构设计 — 可靠投递、运营权限、前端指令 > **仓库**:`craftlabs-authorization-sdk`(`develop`)。 > **前置**:[I6 收口](./I6_CLOSEOUT.md)、[I6 实现审核](./I6_IMPLEMENTATION_REVIEW.md) §3 跟踪项。 > **角色**:迭代功能架构说明;实现以本文件为审查基线。 --- ## 1. 目标与范围 | 主题 | I7 要达成 | 非目标(后置) | | ---------------- | -------------------------------------------------------------------------------------------------- | ----------------------- | | **Webhook → 平台** | 对比特 **2xx 后立即返回**;平台投递 **异步**、可重试、**落库可观测**(状态/次数/最后错误) | MQ、跨地域多活 | | **运营权限** | 新增 `**OPS`**;**Callback Inbox**(读/改/挂接)仅 `**OPS` + `SYS_ADMIN`**;`**DEVELOPER**` 保留其余业务与 **M6 只读** | 细粒度按钮与数据范围(I8+) | | **前端** | 路由 `meta.roles` 与菜单 `**hasAnyRole`** 一致;登录页说明 `**ops/ops**` | Playwright 流水线(I7.1 可选) | --- ## 2. Webhook 侧:平台投递出站队列 ### 2.1 行为 1. `**webhook_callback_receipt` 首次插入成功** 且配置了 `craftlabs.platform.internal.base-url` + token 时,写入 `**webhook_platform_delivery`**,`status=PENDING`。 2. **不**在 Callback HTTP 线程内同步 `RestClient` 调用平台(避免比特侧拖慢与线程占用)。 3. `**@Scheduled`** 周期拉取 `PENDING` / 可重试失败行,`POST /internal/v1/callback-events`;成功 → `SENT`;失败 → `attempts++`,指数退避 `**next_retry_at**`,超过 `**max-attempts**` → `DEAD`(人工/运维处理)。 4. **未配置 base-url** 时:不建队列行(与 I5「仅收据」行为一致)。 ### 2.2 表(Flyway `V2__webhook_platform_delivery.sql`) | 列 | 说明 | | ----------------------------------------- | ------------------------------------- | | `receipt_id` | 关联收据 | | `request_body` | 平台 API JSON 正文 | | `trace_headers_json` | `traceparent` / `X-Request-Id` 等 JSON | | `idempotency_key` | 头 `Idempotency-Key` 用值 | | `status` | `PENDING` / `SENT` / `DEAD` | | `attempts`, `last_error`, `next_retry_at` | 重试与排障 | ### 2.3 配置(示例) | Key | 说明 | | ----------------------------------------------- | ----------- | | `craftlabs.platform.delivery.scheduler-enabled` | 单测可 `false` | | `craftlabs.platform.delivery.max-attempts` | 默认 `8` | | `craftlabs.platform.delivery.batch-size` | 每.tick 处理条数 | --- ## 3. 平台 API:角色与方法安全 ### 3.1 角色 | 角色 | 用途 | | ----------- | ----------------------------------------------------------- | | `SYS_ADMIN` | 全量(含 Callback) | | `OPS` | **仅** Callback Inbox + 与运营配套能力;**不**开放合同/交付等业务写路径(由路由与菜单裁剪) | | `DEVELOPER` | 业务+M6 只读;**不**含 Inbox | ### 3.2 安全模型 - `**@EnableMethodSecurity`** + `**@PreAuthorize**` 扛后端契约。 - `**CallbackInboxController**`:`hasAnyRole('OPS','SYS_ADMIN')`。 - `**IntegrationCatalogController**`:`hasAnyRole('OPS','SYS_ADMIN','DEVELOPER')`。 - JWT 仍由 `[JwtAuthenticationFilter](../../../services/delivery-platform-api/src/main/java/cn/craftlabs/platform/api/security/JwtAuthenticationFilter.java)` 注入 `ROLE_*`。 ### 3.3 演示账号 | 用户 | 密码 | 角色 | | ------- | ------- | ----------- | | `admin` | `admin` | `SYS_ADMIN` | | `dev` | `dev` | `DEVELOPER` | | `ops` | `ops` | `OPS` | --- ## 4. 前端(`delivery-platform-ui`) ### 4.1 路由 `meta.roles` | 区域 | `meta.roles` | | ------------------------------ | ------------------------------- | | 首页及以下业务(客户/项目/合同/交付/SN) | `SYS_ADMIN`, `DEVELOPER` | | `/callbacks`, `/callbacks/:id` | `SYS_ADMIN`, `OPS` | | `/integration/*` | `SYS_ADMIN`, `DEVELOPER`, `OPS` | ### 4.2 菜单与首页 - **Pinia** `hasAnyRole(roles)`,**MainLayout** / **HomeView** 按角色显示入口,避免 OPS 误以为可点业务页。 --- ## 5. 测试与 DoD | 项 | 标准 | | ------- | ----------------------------------------------------------------------------------- | | 平台 | `CallbackInboxControllerTest`:`DEVELOPER` 访问 Inbox → **403**;`SYS_ADMIN`/`OPS` 仍可走通 | | Webhook | 配置 base-url 时 **enqueue** 产生 `PENDING` 行;单测关闭 scheduler 避免后台线程 | | 前端 | `npm run build` 通过 | --- ## 6. 修订记录 | 日期 | 说明 | | ---------- | ---------------------------- | | 2026-04-06 | I7 初版:异步投递表 + OPS + 前端路由/菜单。 | | 2026-04-06 | 闭环:实现与 [I7_IMPLEMENTATION_REVIEW.md](./I7_IMPLEMENTATION_REVIEW.md) 复盘。 |