Wave 1 Day 4 admin-web 后端 API PRD 批 1 撰写。 00-overview.md (338 行): - 151 端点 / 34 标签全清单(实际 vs P1-7 估算 80,多 71 个) - 5 批 PRD 拆分映射 - OpenAPI 与代码不同步告警(本批缺 10+ 端点,Wave 5 修复抓取脚本) batch1-runtime-context-and-ai.md (924 行): - 23 端点 PRD: admin-ai 17 + runtime-context 5 + triggers 1 - 41 评估发现: P0x8 / P1x20 / P2x13 - 每端点带 file:line 引用 + 调用方定位 工作量修正: P1-7 估算 60-65h -> 实际 100-130h (按 5 批分散到 Wave 1-5)。 参考: docs/audit/changes/2026-05-04__wave1_t7_admin_api_prd_batch1.md
45 KiB
admin-web API PRD — 批 1: Runtime Context + AI 管理 + Triggers
日期:2026-05-04 / Wave 1 W1-T7 / 范围:admin-ai (17) + admin-runtime-context (4) + admin-triggers (1) 整体 5 批计划见
docs/_overview/04b-feedback/P1-7-admin-api-prd-evaluation.mdOpenAPI 与代码同步差异警示:本批审视发现
docs/contracts/openapi/backend-api.json(2026-05-04 抓取)只暴露 13 个 admin-ai 端点,而当前代码apps/backend/app/routers/admin_ai.py实际已扩到 17 个(多出/run/{app_type}/triggersGET/PATCH/prewarm/progress/trigger-event),且完全缺失admin-runtime-context5 个端点与admin-triggers/unified端点。这是一个 P1 级评估发现,记入第五章。
一、批 1 端点清单(22 个)
| 序 | Method | Path | tag | 用途简述 | 路由代码 |
|---|---|---|---|---|---|
| 1 | GET | /api/admin/ai/dashboard |
admin-ai | AI 监控总览 | admin_ai.py:117 |
| 2 | GET | /api/admin/ai/trigger-jobs |
admin-ai | 调度任务分页列表 | admin_ai.py:138 |
| 3 | GET | /api/admin/ai/trigger-jobs/{job_id} |
admin-ai | 调度任务详情 | admin_ai.py:166 |
| 4 | POST | /api/admin/ai/trigger-jobs/{job_id}/retry |
admin-ai | 手动重跑触发任务 | admin_ai.py:178 |
| 5 | GET | /api/admin/ai/run-logs |
admin-ai | AI 调用日志列表 | admin_ai.py:194 |
| 6 | GET | /api/admin/ai/run-logs/{log_id} |
admin-ai | AI 调用日志详情 | admin_ai.py:225 |
| 7 | POST | /api/admin/ai/cache/invalidate |
admin-ai | 批量缓存失效 | admin_ai.py:240 |
| 8 | GET | /api/admin/ai/budget |
admin-ai | Token 预算用量 | admin_ai.py:257 |
| 9 | POST | /api/admin/ai/batch-run |
admin-ai | 创建批量执行(预估) | admin_ai.py:269 |
| 10 | POST | /api/admin/ai/batch-run/confirm |
admin-ai | 确认批量执行 | admin_ai.py:283 |
| 11 | GET | /api/admin/ai/alerts |
admin-ai | 告警列表 | admin_ai.py:299 |
| 12 | POST | /api/admin/ai/alerts/{log_id}/ack |
admin-ai | 确认告警 | admin_ai.py:317 |
| 13 | POST | /api/admin/ai/alerts/{log_id}/ignore |
admin-ai | 忽略告警 | admin_ai.py:327 |
| 14 | POST | /api/admin/ai/run/{app_type} |
admin-ai(代码) / 缺 OpenAPI | 按需执行单个 App | admin_ai.py:352 |
| 15 | GET | /api/admin/ai/triggers |
admin-ai(代码) / 缺 OpenAPI | AI 触发器配置列表 | admin_ai.py:400 |
| 16 | PATCH | /api/admin/ai/triggers/{trigger_id} |
admin-ai(代码) / 缺 OpenAPI | 更新 AI 触发器 | admin_ai.py:409 |
| 17 | GET | /api/admin/ai/prewarm/progress |
admin-ai(代码) / 缺 OpenAPI | 72 组合预热进度 | admin_ai.py:431 |
| 18 | POST | /api/admin/ai/trigger-event |
admin-ai(代码) / 缺 OpenAPI | 手动触发 AI 事件 | admin_ai.py:444 |
| 19 | GET | /api/config/runtime-context |
业务配置 / 缺 OpenAPI | 当前用户门店运行上下文 | admin_runtime_context.py:46 |
| 20 | GET | /api/admin/runtime-context |
业务运行上下文 / 缺 OpenAPI | 按门店查上下文 | admin_runtime_context.py:54 |
| 21 | GET | /api/admin/runtime-context/sites |
业务运行上下文 / 缺 OpenAPI | 列出所有门店上下文 | admin_runtime_context.py:64 |
| 22 | PATCH | /api/admin/runtime-context |
业务运行上下文 / 缺 OpenAPI | 切换门店运行模式 | admin_runtime_context.py:94 |
| 23 | GET | /api/admin/triggers/unified |
系统管理 / 缺 OpenAPI | 三表聚合触发器视图 | admin_triggers.py:145 |
实际为 23 个端点(章节标题写 22 因 1 个为 admin-runtime-context 与 1 个 config-runtime-context 合并归类)。下方按 三大功能区分章撰写。
二、Runtime Context 端点详细 PRD(5 个)
业务运行上下文(Runtime Context)用于多门店"沙箱/正式"模式切换,核心实体 biz.site_runtime_context(每个 site_id 一行)。沙箱模式下数据库写入会附加 sandbox_instance_id 隔离,可独立"穿越到任意业务日期"做演练。
GET /api/config/runtime-context
用途:小程序/admin-web 通用 — 返回当前登录用户门店的业务运行上下文。
权限:任意登录用户(Depends(get_current_user)),不限角色。
调用方:admin-web 当前未直接调用此路径(走 /admin/runtime-context?site_id=...);小程序侧使用,但本批不展开。
Request Schema:无 query / body 参数;site_id 取自 JWT。
Response Schema (RuntimeContextResponse):
| 字段 | 类型 | 说明 |
|---|---|---|
| site_id | int | 门店 ID |
| mode | "live" | "sandbox" | 当前模式 |
| business_day_start_hour | int | 业务日切点(0-23,默认 4) |
| business_date | date | 业务日期(沙箱模式可能与真实日期不同) |
| business_now | datetime | 业务当前时刻 |
| sandbox_date | date | null | 沙箱锚定日期(仅 sandbox 模式) |
| sandbox_instance_id | str | null | 沙箱实例 UUID(用于数据隔离) |
| ai_mode | "live" | AI 模式(暂只支持 live) |
| status | str | 上下文状态(active 等) |
| is_sandbox | bool | 是否沙箱(冗余便利字段) |
业务语义:
- 任何业务接口(报表/财务/AI 触发)在沙箱模式下应使用
business_date而非系统today(),以保证"穿越体验"一致。 sandbox_instance_id用于在dws.*等表新增数据时附 UUID 标记,切换沙箱实例时旧数据自然失效。
评估问题:
- P2 — RESTful 命名不一致:同一资源同时暴露在
/api/config/runtime-context(小程序友好)和/api/admin/runtime-context(管理端)。两个 path 返回的是同一个 Pydantic 模型,可考虑统一为/api/runtime-context,前端按 query 决定 site 来源。
关联:
- 路由代码:
apps/backend/app/routers/admin_runtime_context.py:46 - Schema:
apps/backend/app/schemas/runtime_context.py:16 - 服务实现:
apps/backend/app/services/runtime_context.py:88(get_runtime_context()) - 前端调用:无(批 1 范围)
GET /api/admin/runtime-context
用途:系统管理端按 site_id 查询任意门店的业务运行上下文。
权限:super_admin 强制(_require_super_admin,行内函数 admin_runtime_context.py:34)。
调用方:apps/admin-web/src/api/runtimeContext.ts:63 fetchRuntimeContext(siteId),被沙箱配置页面/Runtime Context 总览页面消费。
Request Schema:
| 参数 | 位置 | 类型 | 必填 | 说明 |
|---|---|---|---|---|
| site_id | query | int (≥1) | 是 | 门店 ID |
Response Schema:同 /api/config/runtime-context(RuntimeContextResponse)。
业务语义:
- super_admin 跨门店查看,与登录用户的
site_id解耦。 - 与
/api/admin/runtime-context/sites的差异:本端点返回单门店完整上下文(含 business_date/business_now 计算结果),而 sites 列表只返回静态字段,不计算业务日期。
评估问题:
- P1 — 权限粒度过粗:仅 super_admin 才能查任意门店。
tenant_admin应当能查自己 tenant 下所有门店,但当前一刀切。建议按tenant_id ↔ site_id关系判断(auth.tenant_admins.tenant_id对应biz.sites.tenant_id)。
关联:
- 路由代码:
apps/backend/app/routers/admin_runtime_context.py:54 - 前端调用:
apps/admin-web/src/api/runtimeContext.ts:63
GET /api/admin/runtime-context/sites
用途:列出所有可配置门店及其当前运行上下文(用于沙箱配置主表)。
权限:super_admin 强制。
调用方:apps/admin-web/src/api/runtimeContext.ts:58 fetchRuntimeSites(),Runtime Context 主页表格 / 沙箱配置入口。
Request Schema:无参数。
Response Schema:list[RuntimeSiteItem]:
| 字段 | 类型 | 说明 |
|---|---|---|
| site_id | int | 门店 ID |
| site_name | str | null | 门店名 |
| site_code | str | null | 门店编码 |
| is_active | bool | 门店启用 |
| mode | "live"|"sandbox"|null | 当前模式(无配置时 null) |
| sandbox_date | date | null | 沙箱锚定日期 |
| sandbox_instance_id | str | null | 沙箱实例 UUID |
| ai_mode | "live" | null | AI 模式 |
| status | str | null | 状态 |
| updated_at | datetime | null | 最后更新时间 |
业务语义:
- 直接 SQL
LEFT JOIN,门店未配置 runtime_context 时仅返回 site 基础列。 - 排序:
is_active DESC, site_id(启用门店在前)。
评估问题:
- P1 — 缺少分页/数量限制:当门店数 > 200 时单次响应可能超 300KB(每行 ~150B + JSON 包装)。当前查询无 LIMIT,不阻塞表 scan。建议 query 加
page/page_size,默认 200。 - P2 — Response Model 缺失:
response_model未声明,实际返回list[dict],OpenAPI 看不到字段约束;前端 TS 类型靠runtimeContext.ts:24-35手写,易漂移。
关联:
- 路由代码:
apps/backend/app/routers/admin_runtime_context.py:64 - 前端调用:
apps/admin-web/src/api/runtimeContext.ts:58
PATCH /api/admin/runtime-context
用途:切换某门店的业务运行上下文(live ↔ sandbox)。这是整个沙箱体系最核心的写操作。
权限:super_admin 强制。
调用方:apps/admin-web/src/api/runtimeContext.ts:73 switchRuntimeContext(payload),Runtime Context 详情页 / 沙箱配置 Modal。
Request Schema (RuntimeSwitchRequest,schemas/runtime_context.py:37):
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| site_id | int (≥1) | 是 | 门店 ID |
| mode | "live"|"sandbox" | 是 | 目标模式 |
| sandbox_date | date | null | 条件必填 | sandbox 模式必填,且 ≤ 真实今天 |
| reset_sandbox | bool | 否(默认 true) | 是否重新生成 sandbox_instance_id |
| reason | str (≤500 字符) | null | 否 | 切换原因(审计) |
Response Schema (RuntimeSwitchResponse):
| 字段 | 类型 | 说明 |
|---|---|---|
| context | RuntimeContextResponse | 切换后的最新上下文 |
| steps | list[RuntimeTransitionStep] | 切换过程的步骤列表(对前端进度展示) |
RuntimeTransitionStep 结构(schemas/runtime_context.py:29):
| 字段 | 类型 | 说明 |
|---|---|---|
| key | str | 步骤键(如 cancel_etl_processes) |
| title | str | 步骤标题 |
| status | "success"|"skipped"|"warning"|"failed" | 步骤结果 |
| detail | str | 详细描述 |
| count | int | 受影响数量(如取消的 ETL 数) |
业务语义:
- 切换前会自动停服当前门店的所有运行中活动:
- 终止内存内 ETL 执行(
task_executor.cancel),admin_runtime_context.py:191-214 - 取消
task_queue中 pending/running 的记录,admin_runtime_context.py:217-249 - 取消内存内 AI Dispatcher 调用链,admin_runtime_context.py:253-271
- 把
biz.ai_trigger_jobs中 pending/running 的记录置为 cancelled,admin_runtime_context.py:273-306
- 终止内存内 ETL 执行(
biz.trigger_jobs(全局触发器)不被暂停,因为它是全局调度表,无site_id列。mode=sandbox且reset_sandbox=true或旧上下文无 sandbox_instance_id 时,生成新 UUID;否则复用旧 UUID(沙箱"继续模式")。
典型调用流程:
- 用户在 admin-web 沙箱配置 Modal 选择 mode=sandbox + sandbox_date=2026-04-15 + reason="演练春节歇业"
- 前端 PATCH 该端点
- 后端依次:停 ETL → 停队列 → 停 AI → INSERT/ON CONFLICT 写
biz.site_runtime_context→ 返回 steps + 新 context - 前端展示 5 个 step 的进度面板,引导用户确认进入沙箱
评估问题:
- P0 — 长事务 + 多重资源操作风险:整个切换过程涉及 4 个资源(进程内 task_executor / DB task_queue / 进程内 dispatcher / DB ai_trigger_jobs),没有事务包裹,任何一步异常后,部分已停部分未停,系统进入半状态。建议引入幂等键(如
transition_id)+ 失败时允许重试同 transition_id 不重复执行。 - P1 — 没有 audit 表写入:切换历史(谁/何时/原因/旧 mode → 新 mode)只
UPDATE当前行,旧值丢失,违反"沙箱必可追溯"原则。建议新增biz.site_runtime_context_history表,每次切换 INSERT 一行(reason 在 P1 schema 中已支持,但只存最后一次)。 - P2 —
_stop_runtime_activity内有多次 connect/close:每个清理步骤新开连接(admin_runtime_context.py:217 / 273),应共用一个连接,减少 4-5 倍连接开销。
关联:
- 路由代码:
apps/backend/app/routers/admin_runtime_context.py:94 - 前端调用:
apps/admin-web/src/api/runtimeContext.ts:73 - DB 表:
db/schemas/biz/site_runtime_context.sql(权威 DDL) - PRD 文档:
docs/prd/specs/P20-runtime-context-sandbox.md(本会话新建)
三、AI 管理(admin-ai)端点详细 PRD(17 个)
通用前提:全部需要 JWT 认证 + admin 角色之一(
site_admin/tenant_admin/super_admin),由_require_admin()在 admin_ai.py:70 注入(单独自动校验auth.admin_users.is_active)。所有写操作均会落ai_run_logs/ai_trigger_jobs等表。
GET /api/admin/ai/dashboard
用途:AI 监控总览(今日调用数、成功率、token、延迟、7 天趋势、各 App 分布、最近告警、健康状态)。
权限:任意 admin 角色。
调用方:apps/admin-web/src/api/adminAI.ts:238 getDashboard(query?),被 AI 仪表盘页面 (AIDashboard.tsx 系列) 消费。
Request Schema(全部 query):
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| site_id | int | 否 | 门店筛选(空=全门店) |
| range_days | int (1-365) | 否 | 回溯天数(1=今日 / 3 / 7 / 10) |
| date_from | str (YYYY-MM-DD) | 否 | 起始日期(与 date_to 成对) |
| date_to | str (YYYY-MM-DD) | 否 | 结束日期 |
Response Schema (DashboardResponse,schemas/admin_ai.py:59):
| 字段 | 类型 | 说明 |
|---|---|---|
| today_calls | int | 当日调用总次数 |
| today_success_rate | float | 当日成功率(0-1) |
| today_tokens | int | 当日总 token 消耗 |
| today_avg_latency_ms | float | 当日平均延迟 ms |
| trend_7d | list[DailyTrend] | 7 天每日 calls + success_rate |
| app_distribution | list[AppDistItem] | 各 app_type 调用占比 |
| budget | BudgetInfo | 日/月预算用量 |
| recent_alerts | list[AlertItem] | 最近 10 条告警 |
| app_health | list[AppHealthItem] | 各 App 最近一次调用状态 |
业务语义:
- 命名"today"但实际语义是"按 query 时间窗"(若传 range_days=7,today_calls 实际是 7 天累计)— 命名误导,P1。
- 7 天 trend 始终基于自然 7 天,不受 query 影响,与上方"按窗口聚合"的字段语义不一致。
评估问题:
- P1 — 字段命名误导:
today_calls等字段在range_days>1时含义变成"窗口累计",前端容易误展示。建议改名为period_calls或新增period字段标明聚合范围。 - P1 — 4 个 query 互斥关系未约束:
range_days与date_from/date_to同时传时,后端实现按谁优先未在 schema 体现,只在 service 推断(admin_service.py:69+)。OpenAPI 看不出来,前端易传错。建议加 model_validator 强制互斥。 - P2 — 9 个子查询并发执行:dashboard 一次响应内并行/串行执行 5+ 个 SQL,端到端可能 800ms+;建议引入 5-30s 缓存。
关联:
- 路由代码:
apps/backend/app/routers/admin_ai.py:117 - 服务:
apps/backend/app/services/ai/admin_service.py:40 - 前端调用:
apps/admin-web/src/api/adminAI.ts:238
GET /api/admin/ai/trigger-jobs
用途:AI 调度任务(biz.ai_trigger_jobs)分页列表 — 这是 AI 触发链的"运行实例历史"。
权限:任意 admin 角色。
调用方:apps/admin-web/src/api/adminAI.ts:246 getTriggerJobs(params),AI 触发任务历史页面消费。
Request Schema(全部 query):
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| event_type | str | 否 | consumption / dws_completed / note_created / task_assigned |
| status | str (alias status_filter) |
否 | pending / running / success / failed / cancelled |
| site_id | int | 否 | 门店 |
| date_from / date_to | YYYY-MM-DD | 否 | 创建时间范围 |
| page | int (≥1) | 否 | 默认 1 |
| page_size | int (1-100) | 否 | 默认 20 |
Response Schema (TriggerJobListResponse):
| 字段 | 类型 | 说明 |
|---|---|---|
| items | list[TriggerJobItem] | id/event_type/member_id/status/app_chain/is_forced/site_id/started_at/finished_at/created_at |
| total | int | 总条数 |
| page | int | 当前页 |
| page_size | int | 页大小 |
| today_skipped_duplicates | int | 今日去重跳过数(全局,不受 filter 影响) |
业务语义:
- "调度任务"实际是 AI 链的事件入口实例。
app_chain是文本 "app2_finance,app3_clue,app7_customer" 列出实际跑的 App 链。 today_skipped_duplicates是诊断字段,告诉用户去重去掉了多少潜在请求。
评估问题:
- P1 —
today_skipped_duplicates不应放列表 API 里:它与分页参数无关,会随每次翻页重复计算,浪费 SQL。建议挪到 dashboard 或独立 stats 端点。 - P2 — 命名歧义"trigger-jobs":与
biz.trigger_jobs(全局触发器配置表)名字相同但语义完全不同(后者是配置,前者是运行实例)。本端点返回的是biz.ai_trigger_jobs(实例),建议改名/api/admin/ai/jobs或/runs。
关联:
- 路由代码:
apps/backend/app/routers/admin_ai.py:138 - 前端调用:
apps/admin-web/src/api/adminAI.ts:246
GET /api/admin/ai/trigger-jobs/{job_id}
用途:单个调度任务详情(含 payload + error_message + connector_type)。
权限:任意 admin 角色。
调用方:apps/admin-web/src/api/adminAI.ts:251 getTriggerJobDetail(id),AI 触发任务详情 Drawer。
Request Schema:path 参数 job_id: int。
Response Schema (TriggerJobDetailResponse,继承 TriggerJobItem):
- TriggerJobItem 全部字段
- payload: dict | null — 触发原始 payload
- error_message: str | null — 失败原因
- connector_type: str — 触发来源(feiqiu / dws_completion 等)
业务语义:用于排查失败原因,通常配合 retry 端点使用。
评估问题:
- P2 — 404 文案"调度任务不存在":与 list API 命名不一致(那边是"调度任务",但实际数据源是
ai_trigger_jobs)。建议统一文案 "AI 触发任务不存在"。
关联:
- 路由代码:
apps/backend/app/routers/admin_ai.py:166 - 前端调用:
apps/admin-web/src/api/adminAI.ts:251
POST /api/admin/ai/trigger-jobs/{job_id}/retry
用途:手动重跑某调度任务(创建新 ai_trigger_jobs,is_forced=true,异步执行)。
权限:任意 admin 角色。
调用方:apps/admin-web/src/api/adminAI.ts:256 retryTriggerJob(id),详情 Drawer 的"重跑"按钮。
Request Schema:path 参数 job_id: int,无 body。
Response Schema (RetryResponse):
| 字段 | 类型 | 说明 |
|---|---|---|
| trigger_job_id | int | 新建的任务 ID |
| status | str | "pending" |
业务语义:
- 创建一个新的 ai_trigger_jobs 记录(继承原 payload + event_type),
is_forced=true跳过去重校验。 - 失败抛 ValueError → 404(由 service 抛)。
评估问题:
- P1 — 缺幂等键:用户连点 N 次按钮会创建 N 条 retry job。POST 应支持 idempotency-key header 或前端主动节流。
- P2 — 重跑后无前端轮询提示:返回的 trigger_job_id 是新 ID,但前端目前不轮询其完成状态(需要重刷列表才能看到结果)。
关联:
- 路由代码:
apps/backend/app/routers/admin_ai.py:178 - 前端调用:
apps/admin-web/src/api/adminAI.ts:256
GET /api/admin/ai/run-logs
用途:AI 调用日志(biz.ai_run_logs)分页列表(每个 App 调用一次写一行)。
权限:任意 admin 角色。
调用方:apps/admin-web/src/api/adminAI.ts:262 getRunLogs(params),AI 调用日志页面。
Request Schema(query):
| 参数 | 类型 | 说明 |
|---|---|---|
| app_type | str | app2_finance / app3_clue / ... |
| status (alias) | str | success / failed / timeout / circuit_open |
| trigger_type | str | event / cron / manual / batch |
| site_id | int | 门店 |
| date_from / date_to | YYYY-MM-DD | 时间范围 |
| page / page_size | int | 同 trigger-jobs |
Response Schema (RunLogListResponse):
- items: list[RunLogItem] (id / app_type / trigger_type / member_id / tokens_used / latency_ms / status / site_id / created_at)
- total / page / page_size
业务语义:列表只展示元信息,不含 prompt / response 大字段(由详情 API 返回)。
评估问题:
- P0 — 大表性能:
ai_run_logs是高频写入表,生产数据量预计每月 100w+,目前 ORDER BY created_at DESC 若 created_at 无索引会慢。需要确认 DDL 是否建索引(db/schemas/biz/ai_run_logs.sql)。 - P1 — 缺 status="cancelled" 文档:实际数据源里因为 runtime-context 切换会产生 cancelled 状态(见上方第二章 PATCH 流程),但本 API filter 文档未列出。
关联:
- 路由代码:
apps/backend/app/routers/admin_ai.py:194 - 前端调用:
apps/admin-web/src/api/adminAI.ts:262
GET /api/admin/ai/run-logs/{log_id}
用途:单条调用日志详情(含完整 prompt / response,不脱敏)。
权限:任意 admin 角色。
调用方:apps/admin-web/src/api/adminAI.ts:267 getRunLogDetail(id),详情 Drawer。
Request Schema:path log_id: int。
Response Schema (RunLogDetailResponse,继承 RunLogItem):
- request_prompt: str | null
- response_text: str | null
- error_message: str | null
- session_id: str | null
- finished_at: str | null
业务语义:用于排查 AI 应用的 prompt 工程问题,故意不脱敏。
评估问题:
- P0 — PII 泄露面:prompt 通常包含会员姓名/手机号/消费明细,
tenant_admin跨 tenant 也能查,违反多租户隔离原则。建议:除 super_admin 外,其他 admin 仅能查本 site_id 下的 log;或对 prompt/response 做按角色脱敏。 - P1 — 大字段无大小限制:某次失败的 response_text 可能 50KB+,会拖慢 JSON 序列化。建议加
?include_raw=falsequery 默认只返回截断。
关联:
- 路由代码:
apps/backend/app/routers/admin_ai.py:225 - 前端调用:
apps/admin-web/src/api/adminAI.ts:267
POST /api/admin/ai/cache/invalidate
用途:批量缓存失效(ai_cache.status='invalidated')。
权限:任意 admin 角色。
调用方:apps/admin-web/src/api/adminAI.ts:273 invalidateCache(body),缓存管理页 / Dashboard 操作按钮。
Request Schema (CacheInvalidateRequest):
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| site_id | int | 是 | 门店,强制 |
| app_type | str | null | 否 | 不传=该门店全部 App |
| member_id | int | null | 否 | 不传=该门店全部成员 |
Response Schema:{ affected_count: int }。
业务语义:
site_id必填是为了防止误清全平台缓存(P1-5 文档曾讨论)。- 实际不删除行,只置 status,仍保留历史。
评估问题:
- P1 — site_id 必填但 super_admin 也无法跨站清理:某些场景下 super_admin 想"全平台失效",目前只能 N 次调用。建议 super_admin 角色允许
site_id=null。 - P2 — 没有审计字段:谁清的、为什么清,没记录,出问题难追溯。建议加
reason字段并写 audit_log 表。
关联:
- 路由代码:
apps/backend/app/routers/admin_ai.py:240 - 前端调用:
apps/admin-web/src/api/adminAI.ts:273
GET /api/admin/ai/budget
用途:Token 预算用量(日/月已用/上限/百分比)。
权限:任意 admin 角色。
调用方:apps/admin-web/src/api/adminAI.ts:279 getBudget(),Dashboard 顶部 + 预算管理页。
Request Schema:无参数。
Response Schema (BudgetResponse):
| 字段 | 类型 | 说明 |
|---|---|---|
| daily_used / daily_limit / daily_pct | int / int / float | 当日 |
| monthly_used / monthly_limit / monthly_pct | int / int / float | 当月 |
业务语义:limit 来自配置(env / settings),used 来自 ai_run_logs 当日累加。
评估问题:
- P1 — 全局预算无 site 维度:多门店时一个超额会影响全平台。生产实际中应支持按 site 配额(
tenant_admin视角看自己 tenant 配额)。当前是全局口径。 - P2 — 与 dashboard.budget 字段重复:
DashboardResponse.budget与本端点字段一致,可合并(批 1 评估第五章重复 API)。
关联:
- 路由代码:
apps/backend/app/routers/admin_ai.py:257 - 前端调用:
apps/admin-web/src/api/adminAI.ts:279
POST /api/admin/ai/batch-run
用途:创建批量执行请求,返回预估(token / 调用次数)— 不立即执行。
权限:任意 admin 角色。
调用方:apps/admin-web/src/api/adminAI.ts:285 createBatchRun(body),批量执行 Modal 第一步。
Request Schema (BatchRunRequest):
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| app_types | list[str] | 是 | 要执行的 app_type 列表 |
| member_ids | list[int] | 是 | 目标成员 ID 列表 |
| site_id | int | 是 | 门店 |
Response Schema (BatchRunEstimate):
| 字段 | 类型 | 说明 |
|---|---|---|
| batch_id | str | 用于后续 confirm 的批次 ID |
| estimated_calls | int | 预估调用次数 |
| estimated_tokens | int | 预估 token 消耗 |
业务语义:两阶段提交模式,先预估再确认,避免误操作直接耗 token。
评估问题:
- P0 — batch_id 生命周期未声明:Schema 没说 batch_id 多久过期,如果不调用 confirm 是否清理。建议声明 30 分钟过期。
- P1 — member_ids 列表无上限:传入 10000 个 member_id 时 estimate SQL 会全表扫,建议加
len(member_ids) <= 500校验。 - P2 — 不支持"按全门店所有 member"模式:必须显式列 ID,不便用作"批量为所有会员预热"。
关联:
- 路由代码:
apps/backend/app/routers/admin_ai.py:269 - 前端调用:
apps/admin-web/src/api/adminAI.ts:285
POST /api/admin/ai/batch-run/confirm
用途:确认批量执行,后台异步执行(不等待返回)。
权限:任意 admin 角色。
调用方:apps/admin-web/src/api/adminAI.ts:290 confirmBatchRun(batchId),Modal 第二步确认。
Request Schema (BatchRunConfirm):{ batch_id: str }
Response Schema (BatchRunConfirmResponse):{ status: "started" }
业务语义:从内存/缓存中按 batch_id 取出预估时记录的 app_types/member_ids,投递到 dispatcher。
评估问题:
- P0 — 状态查询缺失:用户 confirm 后无法查询批次进度(已完成 X / 总 Y),只能去 run-logs 列表里逐条筛选。建议新增
GET /api/admin/ai/batch-run/{batch_id}/status。 - P1 — batch_id 失效错误码不明:抛 400 但只带文案"...",前端难精准提示。建议规范错误码
batch_not_found/batch_expired。
关联:
- 路由代码:
apps/backend/app/routers/admin_ai.py:283 - 前端调用:
apps/admin-web/src/api/adminAI.ts:290
GET /api/admin/ai/alerts
用途:告警列表(从 ai_run_logs WHERE status IN ('failed','timeout','circuit_open') 派生)。
权限:任意 admin 角色。
调用方:apps/admin-web/src/api/adminAI.ts:298 getAlerts(params),告警中心页。
Request Schema:
| 参数 | 类型 | 说明 |
|---|---|---|
| alert_status | str | pending / acknowledged / ignored |
| site_id | int | 门店 |
| page / page_size | int | 默认 1 / 20 |
Response Schema (AlertListResponse):items + total + page + page_size,item 字段同 AlertItem。
业务语义:不是独立 alerts 表,是 run-logs 失败行的视图(alert_status 列存在 run-logs 上)。
评估问题:
- P1 — 与 run-logs 严重重复:本 API 实际是
run-logs?status=in(failed,timeout,circuit_open)的语法糖。建议合并到 run-logs(扩 status 多选),减少端点数。 - P2 — 告警去重缺失:同一类型连续失败 100 次会出 100 条 alert,无聚合。建议引入 fingerprint 字段(app_type + error_message hash)做合并。
关联:
- 路由代码:
apps/backend/app/routers/admin_ai.py:299 - 前端调用:
apps/admin-web/src/api/adminAI.ts:298
POST /api/admin/ai/alerts/{log_id}/ack
用途:确认告警(alert_status → acknowledged)。
权限:任意 admin 角色。
调用方:apps/admin-web/src/api/adminAI.ts:303 ackAlert(id),告警中心 / 详情。
Request Schema:path log_id: int,无 body。
Response Schema (AlertActionResponse):{ id: int, alert_status: "acknowledged" }
业务语义:UPDATE ai_run_logs.alert_status,无业务副作用。
评估问题:
- P1 — 不记录 ack_by / ack_at:谁在何时确认无审计。建议 schema 加 ack_by_user_id / ack_at 字段,DB 也补列。
- P2 — RESTful 语义模糊:POST 改状态偏向 PATCH,建议
PATCH /alerts/{id}body{ alert_status: "acknowledged" },与 ignore 端点合并。
关联:
- 路由代码:
apps/backend/app/routers/admin_ai.py:317 - 前端调用:
apps/admin-web/src/api/adminAI.ts:303
POST /api/admin/ai/alerts/{log_id}/ignore
用途:忽略告警(alert_status → ignored)。
权限:任意 admin 角色。
调用方:apps/admin-web/src/api/adminAI.ts:308 ignoreAlert(id)。
Request / Response Schema:同 ack,只是 alert_status 变为 "ignored"。
业务语义:同 ack,业务上区分"已修"vs"忽略"。
评估问题:
- P1 — 与 ack 几乎相同:两个端点只是 status 值不同,结构 100% 重复。建议合并为
PATCH /alerts/{id}body 带 status。
关联:
- 路由代码:
apps/backend/app/routers/admin_ai.py:327 - 前端调用:
apps/admin-web/src/api/adminAI.ts:308
POST /api/admin/ai/run/{app_type} (代码已扩,OpenAPI 缺失)
用途:按需执行单个 App,跳过链路编排(直接走 dispatcher.run_single_app)。
权限:任意 admin 角色。triggered_by 字段记 admin:{user_id}。
调用方:apps/admin-web/src/api/adminAI.ts:332 runApp(appType, body),缓存详情页/告警页/AI 预热页"重新生成"按钮。
Request Schema(path + body):
- path:
app_type: str∈_SUPPORTED_APP_TYPES(8 个) - body (
RunAppRequest,schemas/admin_ai.py:202):- site_id: int (必填)
- member_id / assistant_id / time_dimension / area / note_content / noted_by_name / noted_by_created_at:可选,各 App 不同要求
Response Schema (RunAppResponse):
| 字段 | 类型 | 说明 |
|---|---|---|
| app_type | str | 实际执行的 App |
| success | bool | 失败时为 false |
| result | dict | null | 千问返回 JSON |
| error | str | null | 失败描述 |
业务语义:
- 直接调用
dispatcher.run_single_app,熔断/限流/预算检查由 _run_step 自动执行。 - 失败不抛 HTTPException 而是 success=false,便于前端在批量预热场景下统一处理。
评估问题:
- P1 — RunAppRequest 字段全部可选,实际各 App 必填字段不同:schema 不强制(app2_finance 不填 member_id 也通过校验,到 dispatcher 才报错)。建议拆 8 个 sub-schema 用 discriminated union 或在 router 层显式校验。
- P2 — 422 路径错误信息只有"不支持的 app_type":失败时不告诉前端
_SUPPORTED_APP_TYPES是哪 8 个完整列表(实际 detail 已列,前端可消费)。
关联:
- 路由代码:
apps/backend/app/routers/admin_ai.py:352 - 前端调用:
apps/admin-web/src/api/adminAI.ts:332 - 测试:
apps/admin-web/src/__tests__/adminAiAppTypes.test.ts(回归对齐 8 个 app_type)
GET /api/admin/ai/triggers (代码已扩,OpenAPI 缺失)
用途:列出所有 AI 相关触发器(biz.trigger_jobs WHERE job_type LIKE 'ai_%' OR job_name='task_generator')。
权限:任意 admin 角色。
调用方:apps/admin-web/src/api/adminAI.ts:358 listTriggers(),AI 触发器配置页 (AITriggers.tsx)。
Request Schema:无参数。
Response Schema:list[TriggerItem](schemas/admin_ai.py:250),字段:id/job_name/job_type/trigger_condition/trigger_config(dict)/status/description/last_run_at/next_run_at/last_error。
业务语义:展示 6 个 AI 相关触发器(task_generator + 5 个 ai_*),用于启停/改 cron。
评估问题:
- P0 — 与
/api/trigger-jobs严重重复:已在docs/_overview/04b-feedback/P1-6-trigger-api-merge.md详细分析。GET 字段 95% 重合,仅缺created_at;PATCH 字段互补(本端点支持 status/description,trigger-jobs 支持 interval)。直接引用 P1-6,本批不重复分析,Wave 2 按方案 A 合并。
关联:
- 路由代码:
apps/backend/app/routers/admin_ai.py:400 - 前端调用:
apps/admin-web/src/api/adminAI.ts:358 - P1-6 合并方案:
docs/_overview/04b-feedback/P1-6-trigger-api-merge.md
PATCH /api/admin/ai/triggers/{trigger_id} (代码已扩,OpenAPI 缺失)
用途:更新 AI 触发器(启停 / cron / description)。
权限:任意 admin 角色。
调用方:apps/admin-web/src/api/adminAI.ts:363 updateTrigger(id, body)。
Request Schema (TriggerUpdateRequest):3 字段全可选,至少一个。
- status: enabled / disabled
- cron_expression: 标准 5 段 cron
- description: 文本
Response Schema:TriggerItem 完整对象。
业务语义:对 biz.trigger_jobs 的 UPDATE,但 cron 实际写入 trigger_config jsonb 字段(jsonb_set)。
评估问题:
- P0 — 同上,与
/api/trigger-jobs/:id/configPATCH 互补,需合并(P1-6 方案 A)。
关联:
- 路由代码:
apps/backend/app/routers/admin_ai.py:409 - 前端调用:
apps/admin-web/src/api/adminAI.ts:363
GET /api/admin/ai/prewarm/progress (代码已扩,OpenAPI 缺失)
用途:查询 app2_finance 72 组合(8 area × 9 time_dimension)的预热进度。
权限:任意 admin 角色。
调用方:apps/admin-web/src/api/adminAI.ts:383 getPrewarmProgress(siteId),AI 预热页 (AIPrewarm.tsx)。
Request Schema:query site_id: int 必填。
Response Schema (PrewarmProgressResponse):
| 字段 | 类型 | 说明 |
|---|---|---|
| total | int | 固定 72 |
| done | int | 已生成数 |
| missing | list[PrewarmMissingItem] | 缺失列表(target_id / time_dimension / area) |
| last_updated | str | null | 最后更新 |
业务语义:配合 AIPrewarm.tsx 的"一键补跑"按钮,前端逐条 POST /api/admin/ai/run/app2_finance。
评估问题:
- P1 — total 硬编码 72:如果 area 或 time_dimension 维度发生变化(如 2026-04-23 新增 app2a 区域),硬编码会偏离实际。建议从
meta.app2_combinations这种配置表读取。 - P2 — 仅支持 app2_finance:命名
prewarm/progress但只服务一个 App;若未来 app2a/app7 也要预热,需扩展或新建端点。
关联:
- 路由代码:
apps/backend/app/routers/admin_ai.py:431 - 前端调用:
apps/admin-web/src/api/adminAI.ts:383 - 前端使用:
apps/admin-web/src/pages/AIPrewarm.tsx
POST /api/admin/ai/trigger-event (代码已扩,OpenAPI 缺失)
用途:手动触发 AI 事件链,默认 is_forced=true 跳过去重 — 这是沙箱演练 / 故障重放最关键端点。
权限:任意 admin 角色。日志会记 user_id(admin_ai.py:478)。
调用方:apps/admin-web/src/api/adminAI.ts:406 triggerEvent(body),AI 调试 / 沙箱演练 / 预热全量。
Request Schema (ManualTriggerRequest):
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| event_type | str | 是 | consumption / dws_completed / note_created / task_assigned |
| site_id | int | 是 | 门店 |
| member_id | int | null | 否 | 部分事件需要 |
| assistant_id | int | null | 否 | app4/app5 需要 |
| payload | dict | null | 否 | 事件原始 payload |
| is_forced | bool | 否(默认 true) | 是否跳过去重 |
Response Schema (ManualTriggerResponse):{ trigger_job_id: int, status: "pending" }
业务语义:
- 直接构造
TriggerEvent对象投递给dispatcher.handle_trigger。 is_forced=true会绕过biz.ai_trigger_jobs的去重(同 site_id+event_type+payload 24 小时内只跑一次)。
评估问题:
- P0 — 沙箱模式下未校验 runtime_context:当门店处于 sandbox 模式时,理论上 AI 调用应附 sandbox_instance_id 隔离;当前端点对此无显式校验,可能污染生产数据。建议在 dispatcher 入口强制校验 site_runtime_context 并附标。
- P1 — payload 无 schema 约束:任意 dict 都能传,容易传错(如 consumption 事件需要 settle_at,缺失时 dispatcher 才报错)。建议按 event_type 拆 4 个 sub-schema。
关联:
- 路由代码:
apps/backend/app/routers/admin_ai.py:444 - 前端调用:
apps/admin-web/src/api/adminAI.ts:406 - 前端使用:
apps/admin-web/src/pages/AIPrewarm.tsx
四、Triggers 端点详细 PRD(P1-6 预备合并范围)
GET /api/admin/triggers/unified
用途:聚合三张表的触发器数据,提供"全景视图"(只读)。
权限:任意登录用户(Depends(get_current_user)),未限 admin 角色 — 这是 P1 评估发现。
调用方:apps/admin-web/src/api/triggers.ts:21 fetchUnifiedTriggers(),TriggerManager.tsx 主 Tab all。
Request Schema:无参数。
Response Schema:list[UnifiedTriggerItem](schemas/admin_triggers.py:14):
| 字段 | 类型 | 说明 |
|---|---|---|
| id | int | 统一 ID(etl 来源使用 ROW_NUMBER+100000 偏移避免冲突) |
| name | str | 名称 |
| source | "biz" | "ai" | "etl" | 来源 |
| trigger_condition | str | event / cron / interval / unknown |
| status | str | enabled / disabled / idle / failed 等 |
| last_run_at / next_run_at | str | null | ISO 时间 |
| last_error | str | null | 错误 |
业务语义:
- 数据源 1:
biz.trigger_jobs(全量 9 行) → source="biz" - 数据源 2:
biz.ai_trigger_jobs(最近 100 条事件实例) → source="ai" - 数据源 3:
public.scheduled_tasks(ETL 调度) → source="etl" - 任一数据源失败,记 warning 日志后跳过,返回其他源数据 — 容错设计良好。
典型调用流程:
TriggerManager.tsx切到allTab- 前端 GET 该端点拿到 9 + 100 + N 条混合记录
- 前端按 source 字段分组渲染
评估问题:
- P0 — 权限过松:仅
get_current_user,任何登录用户(含小程序用户!)都能查,泄露其他门店触发器配置信息。必须收紧到 admin 角色。 - P1 — 三个数据源混装,id 冲突靠 +100000 偏移:
scheduled_tasks.id是 UUID,本端点用ROW_NUMBER() + 100000强转 int(admin_triggers.py:115),不稳定 —ORDER BY created_at一变,id 就变,前端无法长期跟踪。建议用(source, original_id)复合 ID。 - P1 — 数据源 2 (ai_trigger_jobs) 语义错位:这是事件实例不是触发器配置,与 source="biz" 的"触发器"不对等。聚合页面把它们混在一起会让用户混淆 — 已在 P1-6 文档第二章指出。
- P2 —
LIMIT 100写死:ai 数据源固定取最近 100,不可调,大批量场景信息缺失。
关联:
- 路由代码:
apps/backend/app/routers/admin_triggers.py:145 - Schema:
apps/backend/app/schemas/admin_triggers.py:14 - 前端调用:
apps/admin-web/src/api/triggers.ts:21 - 前端使用:
apps/admin-web/src/pages/TriggerManager.tsx(主 Tab) - P1-6 合并方案:
docs/_overview/04b-feedback/P1-6-trigger-api-merge.md
五、批 1 评估总结
5.1 P0/P1/P2 问题清单(28 个)
| 等级 | 端点 | 问题 |
|---|---|---|
| P0 | PATCH /admin/runtime-context | 长事务无幂等,4 个资源操作部分失败导致半状态 |
| P0 | GET /admin/ai/run-logs | ai_run_logs 大表查询性能依赖索引,需确认 DDL |
| P0 | GET /admin/ai/run-logs/{id} | prompt 完整返回造成 PII 跨 tenant 泄露 |
| P0 | POST /admin/ai/batch-run | batch_id 生命周期未声明 |
| P0 | POST /admin/ai/batch-run/confirm | 无批次进度查询端点 |
| P0 | GET /admin/ai/triggers + PATCH | 与 /api/trigger-jobs 重复(P1-6) |
| P0 | POST /admin/ai/trigger-event | 沙箱模式下未校验 runtime_context |
| P0 | GET /admin/triggers/unified | 权限仅 get_current_user,任意登录可查 |
| P1 | GET /admin/runtime-context | tenant_admin 应能查本 tenant 门店,当前一刀切 super_admin |
| P1 | GET /admin/runtime-context/sites | 缺分页 + response_model 缺失 |
| P1 | PATCH /admin/runtime-context | 切换历史无 audit 表 |
| P1 | GET /admin/ai/dashboard | today_* 字段在 range_days>1 时命名误导 |
| P1 | GET /admin/ai/dashboard | range_days vs date_from/to 互斥未约束 |
| P1 | GET /admin/ai/trigger-jobs | today_skipped_duplicates 不应放列表 API |
| P1 | POST /admin/ai/trigger-jobs/{id}/retry | 无幂等键,连点产生多重 retry |
| P1 | GET /admin/ai/run-logs | filter 文档缺 cancelled 状态 |
| P1 | GET /admin/ai/run-logs/{id} | 大字段无 size 上限 |
| P1 | POST /admin/ai/cache/invalidate | super_admin 无法跨站清理 |
| P1 | GET /admin/ai/budget | 无 site 维度 |
| P1 | POST /admin/ai/batch-run | member_ids 无上限 |
| P1 | POST /admin/ai/batch-run/confirm | 错误码不规范(batch_not_found / batch_expired 缺失) |
| P1 | GET /admin/ai/alerts | 与 run-logs 严重重复 |
| P1 | POST /admin/ai/alerts/{id}/ack | 无 ack_by / ack_at 审计 |
| P1 | POST /admin/ai/alerts/{id}/ignore | 与 ack 99% 重复 |
| P1 | POST /admin/ai/run/{app_type} | RunAppRequest 各 App 必填差异未拆 |
| P1 | GET /admin/ai/prewarm/progress | total=72 硬编码 |
| P1 | POST /admin/ai/trigger-event | payload 无 schema 约束 |
| P1 | GET /admin/triggers/unified | id 用 ROW_NUMBER+100000 不稳定;混装语义错位 |
| P2 | GET /config/runtime-context | 与 /admin/runtime-context 命名不一致 |
| P2 | PATCH /admin/runtime-context | 多次 connect/close,可共用连接 |
| P2 | GET /admin/ai/dashboard | 9 子查询无缓存 |
| P2 | GET /admin/ai/trigger-jobs | "trigger-jobs" 命名歧义 |
| P2 | GET /admin/ai/trigger-jobs/{id} | 404 文案不一致 |
| P2 | POST /admin/ai/trigger-jobs/{id}/retry | 无前端轮询提示 |
| P2 | POST /admin/ai/cache/invalidate | 无审计字段 |
| P2 | GET /admin/ai/budget | 与 dashboard.budget 重复 |
| P2 | POST /admin/ai/batch-run | 不支持"全门店所有 member" |
| P2 | GET /admin/ai/alerts | 告警去重缺失 |
| P2 | POST /admin/ai/alerts/{id}/ack | RESTful 语义模糊(POST 应改 PATCH) |
| P2 | POST /admin/ai/run/{app_type} | 422 错误信息可优化 |
| P2 | GET /admin/ai/prewarm/progress | 仅服务 app2_finance,命名过窄 |
| P2 | GET /admin/triggers/unified | LIMIT 100 写死 |
汇总:P0 = 8 / P1 = 20 / P2 = 13 / 合计 41 个发现(超过 P1-7 评估单 API 1-3 个的预期上限,说明本批是"高度集中的 AI 治理域,问题密集")。
5.2 关键发现
关键发现 1 — OpenAPI 与代码严重不同步:docs/contracts/openapi/backend-api.json 缺失 10 个本批端点(/admin/runtime-context 全 4 个 + /admin/triggers/unified + /admin/ai/run/{app_type} + /admin/ai/triggers 2 个 + /admin/ai/prewarm/progress + /admin/ai/trigger-event)。/api/config/runtime-context 也缺失。建议 Wave 1 W1-T8 检查 OpenAPI 抓取脚本(很可能是 router include 顺序或某个 condition 排除了)。
关键发现 2 — 触发器域有"3 套 + 2 套互补字段集 + 1 套聚合视图"的混乱:本批暴露 3 个触发器相关端点,加上批外 /api/trigger-jobs 一组,共 4 个名字相似但语义不同的端点。前端 TriggerManager.tsx / AITriggers.tsx / TriggerJobs.tsx 三页面消费方式还各异。P1-6 文档已给出方案 A(完全合并)/ B(底层 service 合并)/ C(只补文档),Wave 2 应优先决策。
5.3 与其他批的关联
- 批 2 ETL 任务管理:涉及
/api/scheduled-tasks/api/trigger-jobs,P1-6 合并方案落地需在批 2 同步动手(改apps/backend/app/routers/trigger_jobs.py与前端triggerJobs.ts) - 批 3 任务执行/调度:run-logs / batch-run 的 dispatcher 实际属于跨批共享基础设施
- 批 4 租户管理:本批 P1 发现"tenant_admin 权限粒度"应在批 4 一并梳理多租户隔离方案
- 批 5 系统设置/日志:audit log 表(本批多次提到的"切换审计/清理审计/ack 审计")应统一在批 5 设计
5.4 Wave 2-5 工单建议(本批衍生)
| 优先级 | 工单 | Wave | 范围 |
|---|---|---|---|
| P0 | 修复 /admin/triggers/unified 权限 |
Wave 2 | 加 _require_admin |
| P0 | OpenAPI 同步修复 + CI 校验 | Wave 1 末 | 抓取脚本 + 守护测试 |
| P0 | 实施 P1-6 方案 A 合并双 PATCH | Wave 2 | 后端 router + 前端 API client |
| P0 | run-logs PII 脱敏分级 | Wave 2 | 按角色返回 prompt 字段 |
| P0 | runtime-context 切换幂等键 + audit 表 | Wave 2 | DB 迁移 + 路由改造 |
| P1 | batch-run 进度查询端点 | Wave 2 | 新增 GET /batch-run/{id}/status |
| P1 | dashboard 字段命名规范 | Wave 3 | 改 today_* → period_* |
| P1 | alerts 与 run-logs 合并 | Wave 3 | 路由 + 前端 |
| P1 | tenant_admin 权限分级 | Wave 4 | 路由 + tenant_id 关联 |
| P2 | 触发器 ID 稳定方案 | Wave 5 | 复合 ID 替代 ROW_NUMBER |
六、关联
- OpenAPI 源:
docs/contracts/openapi/backend-api.json(本会话快照,2026-05-04;本批发现存在 10+ 端点缺失,需修复) - 全局总表:
docs/_overview/admin-api-prd/00-overview.md(已索引 5 批拆分) - P1-6 三 API 合并:
docs/_overview/04b-feedback/P1-6-trigger-api-merge.md(方案 A/B/C 详) - P1-7 评估元文档:
docs/_overview/04b-feedback/P1-7-admin-api-prd-evaluation.md(总工作量 100-130h) - Runtime Context PRD:
docs/prd/specs/P20-runtime-context-sandbox.md(本会话同步新增,产品规格) - Backend CLAUDE.md:
apps/backend/CLAUDE.md(JWT 双认证 / 全局响应包装 / FDW 访问)