3 个串行 phase(粒度 coarse,Option B 拆分): 1. 凭据槽位 API 客户端(CRED-FE-01)— 纯逻辑层,无 UI hint 2. RBAC 收敛 + AI 模型页入口(CRED-FE-02, CRED-FE-03)— UI hint yes 3. 编辑对话框 + 提交反馈(CRED-FE-04, CRED-FE-05)— UI hint yes REQUIREMENTS.md Traceability 段回填 5/5 映射;STATE.md 切到 Phase 1 待启动。 跨项目依赖:本仓库 Phase 3 端到端验收依赖 qy_lty 后端 v1.0 Phase 2 落地(commit 4637998)。
77 lines
7.7 KiB
Markdown
77 lines
7.7 KiB
Markdown
# Roadmap:洛天依应用管理后台(qy-lty-admin)
|
||
|
||
## 概览
|
||
|
||
本路线图聚焦 **Milestone v1.0「通用凭据槽位前端集成」**:在 Web 管理后台的 `/ai-model` 大模型管理页面接入后端 v1.0 暴露的 `/api/v1/admin/credential-slot/` 端点,让运营者能够录入与编辑 APP ID + Access Token,且 Access Token 仅展示末 4 位脱敏掩码、留空保留旧值。粒度为 **coarse**(目标 2-4 phase),按"API 客户端 → 权限收敛 + 页面入口 → 编辑对话框 + 反馈"自下而上分三个 phase 串行推进。
|
||
|
||
**跨项目依赖(重要)**:本前端 milestone 的代码层工作(Phase 1-3)**不阻塞** qy_lty 后端,可独立开发并以 mock / 联调环境推进;但**端到端集成测试**与上线验收**强依赖** qy_lty 后端 Milestone v1.0 的 **Phase 2「管理端读写接口」**(GET/PUT `/api/v1/admin/credential-slot/`)落地后才能跑通。规划时序上,建议本仓库 Phase 1 与后端 Phase 1-2 并行,本仓库 Phase 3 与后端 Phase 2 收尾对齐,以便 milestone 完成时双方在 `docs/修改记录.md` 互相引用条目。
|
||
|
||
## Milestones
|
||
|
||
- 🚧 **v1.0 通用凭据槽位前端集成** — Phase 1-3(启动 2026-05-07,与 qy_lty 后端 v1.0 并行)
|
||
|
||
## Phases
|
||
|
||
**Phase 编号说明:**
|
||
- 整数 phase(1、2、3):当期 milestone 计划工作
|
||
- 小数 phase(2.1、2.2):紧急插入工作(标记 INSERTED)
|
||
|
||
小数 phase 在数值序内夹在前后整数之间执行。
|
||
|
||
- [ ] **Phase 1: 凭据槽位 API 客户端** — 落地 `lib/api/credential-slot.ts`:类型定义、`mapBackendCredentialSlot` 适配器、`getCredentialSlot()` / `updateCredentialSlot()` 两个调用,并从 `lib/api/index.ts` 导出
|
||
- [ ] **Phase 2: RBAC 收敛 + AI 模型页入口** — 在 `lib/permissions.ts` 新增 `credential-slot` 模块 key,分配给"超级管理员"与"AI模型管理员";在 `/ai-model` 页面渲染受权限收敛的"凭据槽位"入口(按钮或卡片)
|
||
- [ ] **Phase 3: 编辑对话框 + 提交反馈** — 实现 `components/ai-model/CredentialSlotDialog.tsx`(React Hook Form + Zod、脱敏掩码预填、留空保留旧值语义),并通过 Sonner toast + `error-handler.ts` 完成成功/失败反馈
|
||
|
||
## Phase Details
|
||
|
||
### Phase 1: 凭据槽位 API 客户端
|
||
**Goal**: 在 `lib/api/` 层提供独立、无 UI 依赖的凭据槽位读写客户端,让后续 phase 可以直接以"调用 + 类型"方式接入,不必再次处理 axios / 适配器细节
|
||
**Depends on**: Nothing(本 milestone 首个 phase)
|
||
**Requirements**: CRED-FE-01
|
||
**Success Criteria**(必须为真):
|
||
1. `lib/api/credential-slot.ts` 导出 `getCredentialSlot()` 与 `updateCredentialSlot(payload)` 两个函数,分别走 `apiClient.get` / `apiClient.put` 命中 `/v1/admin/credential-slot/`,与现有 `lib/api/*.ts` 的拦截器、Bearer token 注入、`StandardResponseMiddleware` 解包行为完全一致
|
||
2. 模块导出共享类型 `CredentialSlot { appId: string; accessTokenMasked: string; updatedAt: string }` 与提交载荷类型,前端类型为 camelCase;后端 snake_case 字段(`app_id` / `access_token` / `updated_at`)通过 `mapBackendCredentialSlot()` 适配器统一转换,沿用 `lib/api/adapters.ts` 的 `mapBackend*` 约定
|
||
3. `lib/api/index.ts` 导出新模块,`import { getCredentialSlot, updateCredentialSlot, type CredentialSlot } from '@/lib/api'` 在任一组件文件中均能解析通过 `tsc --noEmit`
|
||
4. 在浏览器开发态以 mock 后端或后端 Phase 2 联调环境调用 `getCredentialSlot()`,控制台可以看到一条带 `Authorization: Bearer ...` 的请求,且返回值字段名是前端 camelCase(说明适配器生效,未把后端原始 snake_case 直接透传)
|
||
**Plans**: TBD
|
||
|
||
### Phase 2: RBAC 收敛 + AI 模型页入口
|
||
**Goal**: 通过 `lib/permissions.ts` 把"凭据槽位"声明为受控模块、仅向"超级管理员"与"AI模型管理员"开放;并在 `/ai-model` 页面渲染受权限校验收敛的入口控件,让授权用户能看到入口、未授权用户看不到入口
|
||
**Depends on**: Phase 1
|
||
**Requirements**: CRED-FE-02, CRED-FE-03
|
||
**Success Criteria**(必须为真):
|
||
1. `lib/permissions.ts` 的 `PermissionModule` 类型新增 `'credential-slot'` 字面量,`PERMISSION_MATRIX` 中"超级管理员"与"AI模型管理员"两个角色的模块列表均包含 `'credential-slot'`,其余角色(内容管理员、卡牌管理员、查看者)不包含;调用 `hasPermission('credential-slot')` 在两类账户下返回 `true`,其他角色返回 `false`
|
||
2. `getModuleFromPath('/ai-model')` 行为不变(凭据槽位是 `/ai-model` 内嵌子能力,不占独立路由),不引入侧边栏新菜单项
|
||
3. 以"AI模型管理员"角色登录访问 `/ai-model`,页面工具栏 / Header 区域可见明确的"凭据槽位"入口控件(按钮或卡片,文案明确);以"内容管理员"或"查看者"角色登录访问同一页面,入口控件不渲染(DOM 中不存在,而非仅隐藏)
|
||
4. 入口控件的可见性判断走 `hasPermission('credential-slot')`,不直接读 `localStorage.user_role` 字符串比较;点击入口控件触发对话框打开行为(Phase 3 落地后端到端可用,本 phase 至少打开一个空对话框占位以验证联动点存在)
|
||
**Plans**: TBD
|
||
**UI hint**: yes
|
||
|
||
### Phase 3: 编辑对话框 + 提交反馈
|
||
**Goal**: 落地 `CredentialSlotDialog` 组件让授权运营者能够查看脱敏的当前凭据、安全地提交新值,且成功 / 失败两条路径都有清晰的 toast 反馈;表单语义采用"留空保留旧值"避免回写脱敏掩码假值
|
||
**Depends on**: Phase 2
|
||
**Requirements**: CRED-FE-04, CRED-FE-05
|
||
**Success Criteria**(必须为真):
|
||
1. 打开对话框时自动调用 `getCredentialSlot()` 拉取数据:`app_id` 字段以**明文**预填、`access_token` 字段以**末 4 位掩码**显示并附"如需更新请重新输入,留空保留旧值"提示文案、`updated_at` 以只读形式呈现(运营可看到"上次更新"时间)
|
||
2. 表单使用 React Hook Form + Zod 校验:当 `app_id` 输入框被清空且与原值不同则提示"不能为空";`access_token` 字段允许留空(语义=保留旧值),但**一旦用户输入新值**则要求非空白字符;提交时**仅传递用户实际改动过的字段**给 `updateCredentialSlot()`,**绝不**把脱敏掩码当真值回写
|
||
3. 提交成功路径:`updateCredentialSlot()` 返回成功后,调用 `useToast()` 弹出 Sonner 成功 toast(中文文案,如"凭据槽位已更新"),对话框自动关闭,再次打开时数据被重新拉取并展示新的 `updated_at`
|
||
4. 提交失败路径:后端返回非成功响应或网络异常时,错误经由 `lib/api/error-handler.ts` 统一映射为可读中文消息后通过 toast 提示;对话框保持打开、表单字段保留用户输入、不丢失编辑态
|
||
5. 端到端串联(依赖 qy_lty 后端 Phase 2 落地):以"超级管理员"账户登录 → 进入 `/ai-model` → 点击凭据槽位入口 → 输入一组真实 APP ID + Access Token → 提交 → 看到成功 toast → 关闭后重新打开对话框,`access_token` 仅显示新值末 4 位、`updated_at` 已刷新
|
||
**Plans**: TBD
|
||
**UI hint**: yes
|
||
|
||
## Progress
|
||
|
||
**执行顺序:**
|
||
Phase 按数值顺序执行:1 → 2 → 3(如出现紧急插入,记为 1.1 / 2.1 等)
|
||
|
||
| Phase | Plans Complete | Status | Completed |
|
||
|-------|----------------|--------|-----------|
|
||
| 1. 凭据槽位 API 客户端 | 0/TBD | Not started | - |
|
||
| 2. RBAC 收敛 + AI 模型页入口 | 0/TBD | Not started | - |
|
||
| 3. 编辑对话框 + 提交反馈 | 0/TBD | Not started | - |
|
||
|
||
---
|
||
|
||
*生成时间:2026-05-07,Milestone v1.0「通用凭据槽位前端集成」启动;与 qy_lty 后端 v1.0 并行,端到端验收依赖后端 Phase 2 落地*
|