From 15e725a32f371b99ce31f0696b1db66cc9d7be04 Mon Sep 17 00:00:00 2001 From: pmc <740076875@qq.com> Date: Fri, 8 May 2026 11:47:59 +0800 Subject: [PATCH] =?UTF-8?q?docs(02-01):=20=E5=AE=8C=E6=88=90=20Phase=202?= =?UTF-8?q?=20Plan=2002-01=EF=BC=88RBAC=20=E6=89=A9=E5=B1=95=20+=20/ai-mod?= =?UTF-8?q?el=20=E5=87=AD=E6=8D=AE=E6=A7=BD=E4=BD=8D=E5=85=A5=E5=8F=A3?= =?UTF-8?q?=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增 .planning/phases/02-rbac-ai/02-01-SUMMARY.md(含 frontmatter / 任务详情 / 验证结果 / Self-Check PASSED) - STATE.md:进度 50% → 75%,已完成 plan 2 → 3,Phase 2 状态切到 In progress(1/2 plan) - ROADMAP.md:Phase 2 Plans Complete 0/2 → 1/2,状态 Not started → In progress;Plan 02-01 勾选完成 - REQUIREMENTS.md:CRED-FE-02 + CRED-FE-03 状态切到 ✅ Done,Active 段两条 unchecked → checked --- qy-lty-admin/.planning/REQUIREMENTS.md | 9 +- qy-lty-admin/.planning/ROADMAP.md | 4 +- qy-lty-admin/.planning/STATE.md | 41 +++--- .../phases/02-rbac-ai/02-01-SUMMARY.md | 139 ++++++++++++++++++ 4 files changed, 168 insertions(+), 25 deletions(-) create mode 100644 qy-lty-admin/.planning/phases/02-rbac-ai/02-01-SUMMARY.md diff --git a/qy-lty-admin/.planning/REQUIREMENTS.md b/qy-lty-admin/.planning/REQUIREMENTS.md index 0829393..9f4dcef 100644 --- a/qy-lty-admin/.planning/REQUIREMENTS.md +++ b/qy-lty-admin/.planning/REQUIREMENTS.md @@ -88,8 +88,8 @@ ### 通用凭据槽位前端集成(CRED-FE) - [x] **CRED-FE-01** API 客户端 `lib/api/credential-slot.ts`:导出 `getCredentialSlot()`、`updateCredentialSlot({ app_id, access_token })`;含响应适配器 `mapBackendCredentialSlot()`(snake_case → camelCase);共享类型 `CredentialSlot { appId, accessTokenMasked, updatedAt }`;从 `lib/api/index.ts` 导出 -- [ ] **CRED-FE-02** RBAC 模块声明:`lib/permissions.ts` 加入 `credential-slot` 模块 key(`PermissionModule` 类型扩充);`PERMISSION_MATRIX` 把该模块分配给"超级管理员"和"AI模型管理员"两个角色;`getModuleFromPath()` 不需要新映射(凭据槽位是内嵌于 `/ai-model` 的子能力,不占独立路由) -- [ ] **CRED-FE-03** `/ai-model` 页面入口:在合适位置(如页头工具栏 / Header 右侧)渲染"凭据槽位"按钮或卡片;仅当 `hasPermission('credential-slot')` 为 true 时可见;点击触发对话框打开 +- [x] **CRED-FE-02** RBAC 模块声明:`lib/permissions.ts` 加入 `credential-slot` 模块 key(`PermissionModule` 类型扩充);`PERMISSION_MATRIX` 把该模块分配给"超级管理员"和"AI模型管理员"两个角色;`getModuleFromPath()` 不需要新映射(凭据槽位是内嵌于 `/ai-model` 的子能力,不占独立路由) +- [x] **CRED-FE-03** `/ai-model` 页面入口:在合适位置(如页头工具栏 / Header 右侧)渲染"凭据槽位"按钮或卡片;仅当 `hasPermission('credential-slot')` 为 true 时可见;点击触发对话框打开 - [ ] **CRED-FE-04** 编辑对话框组件 `components/ai-model/CredentialSlotDialog.tsx`:基于 `components/ui/dialog.tsx`;表单 React Hook Form + Zod 校验;预填态显示后端返回的 `app_id` 明文 + `access_token` 末 4 位掩码 + 不可改的 `updated_at`;表单语义为"留空保留旧值,重新输入才覆写"(避免把脱敏掩码当真值回写);提交触发 `updateCredentialSlot()`,仅提交用户实际输入的字段 - [ ] **CRED-FE-05** 提交反馈:成功调用 `useToast()` 弹 Sonner 成功 toast 并自动关闭对话框、重新触发 GET 刷新预填;失败走 `lib/api/error-handler.ts` 统一映射后端错误并 toast 提示 @@ -134,8 +134,8 @@ | Requirement | Phase | UI hint | Status | |-------------|-------|---------|--------| | CRED-FE-01 API 客户端 `lib/api/credential-slot.ts`(类型 + 适配器 + GET/PUT) | Phase 1 凭据槽位 API 客户端 | — | ✅ Done (Plan 01-01 commits a0d0b9c + c072bbe;Plan 01-02 commit c1743a3 修改记录追加 + 双重验证;Phase 1 已封盘 2026-05-08) | -| CRED-FE-02 RBAC 模块声明(`lib/permissions.ts` 加 `credential-slot` key + 矩阵分配) | Phase 2 RBAC 收敛 + AI 模型页入口 | yes | Pending | -| CRED-FE-03 `/ai-model` 页面入口(受 `hasPermission('credential-slot')` 收敛) | Phase 2 RBAC 收敛 + AI 模型页入口 | yes | Pending | +| CRED-FE-02 RBAC 模块声明(`lib/permissions.ts` 加 `credential-slot` key + 矩阵分配) | Phase 2 RBAC 收敛 + AI 模型页入口 | yes | ✅ Done (Plan 02-01 commit d60dd89, 2026-05-08) | +| CRED-FE-03 `/ai-model` 页面入口(受 `hasPermission('credential-slot')` 收敛) | Phase 2 RBAC 收敛 + AI 模型页入口 | yes | ✅ Done (Plan 02-01 commit 0bcaa39, 2026-05-08) | | CRED-FE-04 编辑对话框 `CredentialSlotDialog.tsx`(RHF + Zod,留空保留旧值语义) | Phase 3 编辑对话框 + 提交反馈 | yes | Pending | | CRED-FE-05 提交反馈(Sonner toast 成功 + `error-handler.ts` 失败映射) | Phase 3 编辑对话框 + 提交反馈 | yes | Pending | @@ -148,3 +148,4 @@ *Last updated: 2026-05-07 — Milestone v1.0「通用凭据槽位前端集成」ROADMAP 生成,Traceability 回填 5/5* *2026-05-08 更新:Plan 01-01 落地,CRED-FE-01 状态切到 ✅ Done(Active 段已自动勾选 [x])* *2026-05-08 更新:Plan 01-02 落地(修改记录追加 + 双重验证 commit c1743a3),Phase 1 全部交付(2/2 plan),等待 /gsd-plan-phase 2 启动 Phase 2* +*2026-05-08 更新:Plan 02-01 落地(commits d60dd89 + 0bcaa39),CRED-FE-02 + CRED-FE-03 状态切到 ✅ Done;Phase 2 进度 1/2,等待 Plan 02-02 收尾* diff --git a/qy-lty-admin/.planning/ROADMAP.md b/qy-lty-admin/.planning/ROADMAP.md index ee98cfd..2cce635 100644 --- a/qy-lty-admin/.planning/ROADMAP.md +++ b/qy-lty-admin/.planning/ROADMAP.md @@ -47,7 +47,7 @@ 3. 以"AI模型管理员"角色登录访问 `/ai-model`,页面工具栏 / Header 区域可见明确的"凭据槽位"入口控件(按钮或卡片,文案明确);以"内容管理员"或"查看者"角色登录访问同一页面,入口控件不渲染(DOM 中不存在,而非仅隐藏) 4. 入口控件的可见性判断走 `hasPermission('credential-slot')`,不直接读 `localStorage.user_role` 字符串比较;点击入口控件触发对话框打开行为(Phase 3 落地后端到端可用,本 phase 至少打开一个空对话框占位以验证联动点存在) **Plans**: 2 plans - - [ ] 02-01-PLAN.md — 扩展 lib/permissions.ts RBAC(PermissionModule union +1 / 矩阵 +2 角色)+ app/ai-model/page.tsx 加 "use client"、入口 Button、占位 Dialog + - [x] 02-01-PLAN.md — 扩展 lib/permissions.ts RBAC(PermissionModule union +1 / 矩阵 +2 角色)+ app/ai-model/page.tsx 加 "use client"、入口 Button、占位 Dialog ✅ 2026-05-08(commits d60dd89 + 0bcaa39) - [ ] 02-02-PLAN.md — docs/修改记录.md 顶部追加 Phase 2 条目 + plan 级双重验证(npx tsc --noEmit 反向断言 + grep 11 条 specifics + 不引入新依赖) **UI hint**: yes @@ -72,7 +72,7 @@ Phase 按数值顺序执行:1 → 2 → 3(如出现紧急插入,记为 1.1 | Phase | Plans Complete | Status | Completed | |-------|----------------|--------|-----------| | 1. 凭据槽位 API 客户端 | 2/2 | ✅ Complete | 2026-05-08 | -| 2. RBAC 收敛 + AI 模型页入口 | 0/2 | Not started | - | +| 2. RBAC 收敛 + AI 模型页入口 | 1/2 | 🚧 In progress | - | | 3. 编辑对话框 + 提交反馈 | 0/TBD | Not started | - | --- diff --git a/qy-lty-admin/.planning/STATE.md b/qy-lty-admin/.planning/STATE.md index c7f6ebf..588b6bd 100644 --- a/qy-lty-admin/.planning/STATE.md +++ b/qy-lty-admin/.planning/STATE.md @@ -2,20 +2,20 @@ gsd_state_version: 1.0 milestone: v1.0 milestone_name: 通用凭据槽位前端集成 -status: completed -last_updated: "2026-05-08T03:41:45.303Z" +status: in_progress +last_updated: "2026-05-08T08:00:00.000Z" last_activity: 2026-05-08 progress: total_phases: 3 completed_phases: 1 total_plans: 4 - completed_plans: 2 - percent: 50 + completed_plans: 3 + percent: 75 --- # Project State — 洛天依应用管理后台(qy-lty-admin) -**最后更新**: 2026-05-08(Phase 1 全部交付:plan 01 代码 + plan 02 修改记录追加 + 双重验证;CRED-FE-01 已交付,等待 /gsd-plan-phase 2 启动 Phase 2) +**最后更新**: 2026-05-08(Phase 2 Plan 02-01 完成:RBAC +credential-slot 模块 + /ai-model 页面入口 Button + 占位 Dialog;CRED-FE-02 + CRED-FE-03 已交付;等待 Plan 02-02 收尾修改记录) ## 项目引用 @@ -29,21 +29,21 @@ progress: ``` Milestone: v1.0 通用凭据槽位前端集成 -Phase: Phase 1「凭据槽位 API 客户端」✅ 已交付 -Plan: 01-01 完成 ✅ / 01-02 完成 ✅ -Status: Phase 1 complete (2/2 plans done);等待 Phase 2 启动 -Progress: [██████████] 100%(Phase 1 内部 2/2 plan 完成) +Phase: Phase 2「RBAC 收敛 + AI 模型页入口」🚧 进行中 +Plan: 02-01 完成 ✅ / 02-02 待启动 +Status: Phase 2 in progress (1/2 plans done) +Progress: [█████░░░░░] 50%(Phase 2 内部 1/2 plan 完成) Last activity: 2026-05-08 ``` -**下一步行动**:运行 `/gsd-plan-phase 2` 启动 Phase 2「RBAC 收敛 + AI 模型页入口」(CRED-FE-02 + CRED-FE-03)。 +**下一步行动**:运行 `/gsd-execute-phase 2`(或对 02-02-PLAN.md 单独 execute)落地 Plan 02-02:docs/修改记录.md 顶部追加 Phase 2 条目 + plan 级双重验证。 ## Phase 概览 | Phase | 标题 | 需求 | UI hint | 状态 | |-------|------|------|---------|------| | 1 | 凭据槽位 API 客户端 | CRED-FE-01 ✅ | — | ✅ 已交付(2/2 plan,2026-05-08)| -| 2 | RBAC 收敛 + AI 模型页入口 | CRED-FE-02, CRED-FE-03 | yes | 未开始(待 /gsd-plan-phase 2)| +| 2 | RBAC 收敛 + AI 模型页入口 | CRED-FE-02 ✅, CRED-FE-03 ✅ | yes | 🚧 进行中(1/2 plan:02-01 完成 / 02-02 待启动)| | 3 | 编辑对话框 + 提交反馈 | CRED-FE-04, CRED-FE-05 | yes | 未开始 | ## 联动 milestone @@ -58,10 +58,10 @@ Last activity: 2026-05-08 | 指标 | 数值 | |------|------| | 已完成 phase | 1 / 3 | -| 已完成 plan | 2 / 2(Phase 1 全部交付)| -| Milestone 进度 | ~33%(1/3 phase 完成)| +| 已完成 plan | 3 / 5(Phase 1 全部交付 + Phase 2 Plan 02-01 完成)| +| Milestone 进度 | ~50%(1/3 phase 完成 + 1 phase 进行中)| | 启动日期 | 2026-05-07 | -| 最近活动 | 2026-05-08 Plan 01-02 落地(commit c1743a3)| +| 最近活动 | 2026-05-08 Plan 02-01 落地(commits d60dd89 + 0bcaa39)| ### Plan 执行记录 @@ -69,6 +69,7 @@ Last activity: 2026-05-08 |------------|-------|---------|------|----------| | 01-01 | 2 | 2 | ~76s | 2026-05-08 | | 01-02 | 2 | 1 | ~360s | 2026-05-08 | +| 02-01 | 2 | 2 | ~6min | 2026-05-08 | ## 累积上下文 @@ -79,6 +80,7 @@ Last activity: 2026-05-08 - **2026-05-07 表单"留空保留旧值"语义**:后端 GET 返回的是末 4 位脱敏掩码,前端**绝不**能把掩码当真值再 PUT 回去;Phase 3 success criteria #2 显式约束。 - **2026-05-08 Plan 01-01 落地**:1:1 复刻 ai-models.ts 风格的 credential-slot.ts(adapter + GET/PUT),index.ts 末尾具名 re-export 4 个公共符号;类型层 `accessTokenMasked` vs `accessToken` 编译期屏障已建立,Phase 3 表单编写时 TS 会拦截"把脱敏字符串赋给 accessToken 字段"这条 bug 路径。 - **2026-05-08 Plan 01-02 落地**:docs/修改记录.md 顶部追加 [2026-05-08] Phase 1 条目(含「跨项目联动」+「服务端联动」字段引用后端 commit 46d72b8);`npx tsc --noEmit` 在新增/修改文件零类型错误(67 条存量错误与本 phase 无关);临时探针验证 barrel 入口可解析后已删除。`npm run lint` 因项目未 bootstrap ESLint(无 .eslintrc* / eslint-config-next)进入交互式 prompt → 按 PLAN 自动 verify 规则判定通过(不指向新增/修改文件),ESLint 基础设施补齐留给 PERM-06 候选 #3。 +- **2026-05-08 Plan 02-01 落地**:lib/permissions.ts PermissionModule union +1('credential-slot' 第 14 项)+ 「超级管理员」/「AI模型管理员」两角色数组末尾追加 + 顶部注释表新增「凭据槽位」行(commit d60dd89);app/ai-model/page.tsx 转 Client Component(line 1 加 'use client')+ 加 useState/useEffect mounted 守卫(复用 sidebar.tsx 同模式)+ DashboardHeader 内追加凭据槽位 Button(variant=outline / KeyRound 图标 / 受 mounted && hasPermission('credential-slot') 收敛)+ 后插入 controlled mode 占位 Dialog(DialogTitle「通用凭据槽位」+ DialogDescription「对话框真实内容由 Phase 3 落地」)(commit 0bcaa39);`npx tsc --noEmit` 不引入指向 lib/permissions.ts / app/ai-model/page.tsx 的新错误(67 条存量错误与本 phase 无关);不引入新依赖(4 个 lockfile 全部未动)。CRED-FE-02 + CRED-FE-03 已交付,等待 Plan 02-02 收尾修改记录追加。 ### 待办事项 @@ -99,16 +101,16 @@ Last activity: 2026-05-08 |------|------| | 代码库映射 | ✅ `.planning/codebase/` 7 文档(commit `a85b6a7`) | | PROJECT.md | ✅ 已加入 Milestone v1.0 段 + Active 5 项 | -| REQUIREMENTS.md | ✅ Active 段已落地,Traceability 已回填 5/5;CRED-FE-01 已勾选完成 | -| 路线图 | ✅ ROADMAP.md 落地(3 phase,coarse),Phase 1 已完成 | -| 当前 phase | Phase 1 ✅ 已交付,Phase 2 待启动 | +| REQUIREMENTS.md | ✅ Active 段已落地,Traceability 已回填 5/5;CRED-FE-01 + CRED-FE-02 + CRED-FE-03 已勾选完成 | +| 路线图 | ✅ ROADMAP.md 落地(3 phase,coarse),Phase 1 已完成、Phase 2 进行中 | +| 当前 phase | Phase 2 🚧 进行中(02-01 完成 / 02-02 待启动)| | 当前 milestone | v1.0 通用凭据槽位前端集成 | ## 会话连续性 **最近会话**:2026-05-08 -**最近动作**:执行 Plan 01-02(docs/修改记录.md 顶部追加 Phase 1 条目;commit c1743a3)+ 双重验证(tsc 0 个新文件错误 / next lint 因 ESLint 未 bootstrap 进 prompt 但不指向新文件)+ 临时探针验证 barrel 入口后删除;Phase 1 全部交付 -**下一会话起点**:运行 `/gsd-plan-phase 2` 启动 Phase 2「RBAC 收敛 + AI 模型页入口」(CRED-FE-02 + CRED-FE-03) +**最近动作**:执行 Plan 02-01(lib/permissions.ts 扩展 RBAC + app/ai-model/page.tsx 加凭据槽位 Button + 占位 Dialog;commits d60dd89 + 0bcaa39)+ tsc 0 个新文件错误 + 不引入新依赖;CRED-FE-02 + CRED-FE-03 已交付 +**下一会话起点**:执行 Plan 02-02(docs/修改记录.md 顶部追加 [2026-05-08] Phase 2 条目 + plan 级双重验证) ## 工作流配置 @@ -143,3 +145,4 @@ CLAUDE.md 中两条强制规则,做任何 phase 时必须遵守: *2026-05-07 由 gsd-roadmapper 切换到 Phase 1 待启动状态* *2026-05-08 Plan 01-01 完成(CRED-FE-01 已交付),Phase 1 进度 1/2,等待 Plan 01-02 收尾* *2026-05-08 Plan 01-02 完成(修改记录追加 + 双重验证),Phase 1 全部交付(2/2 plan);等待 /gsd-plan-phase 2 启动 Phase 2* +*2026-05-08 Plan 02-01 完成(RBAC 扩展 + /ai-model 页面入口 Button + 占位 Dialog),CRED-FE-02 + CRED-FE-03 已交付;Phase 2 进度 1/2,等待 Plan 02-02 收尾* diff --git a/qy-lty-admin/.planning/phases/02-rbac-ai/02-01-SUMMARY.md b/qy-lty-admin/.planning/phases/02-rbac-ai/02-01-SUMMARY.md new file mode 100644 index 0000000..a8181ca --- /dev/null +++ b/qy-lty-admin/.planning/phases/02-rbac-ai/02-01-SUMMARY.md @@ -0,0 +1,139 @@ +--- +phase: 02-rbac-ai +plan: 01 +subsystem: rbac + ai-model-page +tags: [rbac, permissions, ai-model, dialog, client-component] +requires: + - lib/api/credential-slot.ts:CredentialSlot(Phase 1 已交付,本 plan 暂未直接消费,留给 Phase 3) + - components/ui/dialog.tsx:Dialog/DialogContent/DialogHeader/DialogTitle/DialogDescription + - components/ui/button.tsx:Button(variant="outline") + - components/dashboard-header.tsx:DashboardHeader(children 单 slot) + - components/sidebar.tsx:mounted 守卫模式(line 83-104) + - lucide-react:KeyRound +provides: + - PermissionModule literal "credential-slot"(lib/permissions.ts) + - PERMISSION_MATRIX 中超级管理员/AI模型管理员可访问 credential-slot + - /ai-model 页面入口 Button(受 hasPermission 收敛) + - 占位 Dialog 挂载点(Phase 3 落实表单内容) +affects: + - lib/permissions.ts + - app/ai-model/page.tsx +tech-stack: + added: [] + patterns: + - mounted 守卫(避免 SSR 水合警告,复用 components/sidebar.tsx 同模式) + - hasPermission(...) && JSX 收敛(DOM 中完全不存在,非仅 hidden) + - Dialog controlled mode(open + onOpenChange + useState 配对) +key-files: + created: [] + modified: + - lib/permissions.ts + - app/ai-model/page.tsx +decisions: + - 凭据槽位入口 Button 与原「添加新模型」Button 用 div.flex.items-center.gap-2 包裹后作为 DashboardHeader children 单节点传入(DashboardHeader 本身只渲染单 children slot,无 gap) + - 入口 Button variant="outline"(与现有页面其他次要按钮如「查看详情」「试听示例」视觉一致) + - 图标用 KeyRound(lucide-react 0.454.0 锁定版本支持,凭据语义最贴切) + - 占位 Dialog 内联在 page.tsx,不抽离单独组件(Phase 3 才抽到 components/ai-model/CredentialSlotDialog.tsx) + - mounted 守卫复用 components/sidebar.tsx:83-104 的 useState(false) + useEffect(setMounted(true)) 模式 +metrics: + duration: ~6min + completed: 2026-05-08 + tasks: 2 + files_changed: 2 + lines_added: 53 + lines_removed: 6 +--- + +# Phase 2 Plan 01:扩展 RBAC 矩阵 + /ai-model 页面凭据槽位入口 Summary + +## 一句话 + +把 `'credential-slot'` 模块加入 PermissionModule union 与「超级管理员/AI模型管理员」角色矩阵,同时把 `/ai-model` 页面转为 Client Component 并加上受 `mounted && hasPermission('credential-slot')` 收敛的「凭据槽位」入口 Button + 占位 Dialog(DialogTitle「通用凭据槽位」+ DialogDescription「对话框真实内容由 Phase 3 落地」)。 + +## 完成的需求 + +- ✅ **CRED-FE-02** RBAC 模块声明:PermissionModule 14 项 union + 6 角色矩阵(其中超级管理员、AI模型管理员含 credential-slot);其他 4 角色逐字未动 +- ✅ **CRED-FE-03** /ai-model 页面入口:Button + 占位 Dialog 已落地,未授权角色 DOM 中完全不存在;点击触发占位 Dialog 打开 + +## 执行的任务 + +### Task 1:扩展 lib/permissions.ts RBAC(commit `d60dd89`) + +**改动 4 处(与 PLAN 一致):** + +1. PermissionModule union 末尾追加 `| "credential-slot";`(第 14 项) +2. 「超级管理员」数组末尾追加 `"credential-slot"` +3. 「AI模型管理员」数组末尾追加 `"credential-slot"` +4. 文件顶部权限矩阵注释表新增「凭据槽位」行(与代码同步) + +**未动:** +- 内容管理员 / 卡牌管理员 / 查看者 / 管理员 4 个角色数组逐字不变 +- `getModuleFromPath` 函数体(pathMap 不含 `credential-slot`) +- `getUserRole` / `getAllowedModules` / `hasPermission` / `hasPathPermission` 函数体 + +**验证:** +- `grep -nE "['\"]credential-slot['\"]" lib/permissions.ts` 命中 3 行(union literal + 2 角色数组) +- `grep -n "credential-slot" lib/permissions.ts` 命中 4 行(含注释) +- `npx tsc --noEmit` 整体 67 条存量错误,无新错误指向 lib/permissions.ts + +### Task 2:app/ai-model/page.tsx 加入口 Button + 占位 Dialog(commit `0bcaa39`) + +**改动 5 处(与 PLAN 一致):** + +1. line 1 加 `"use client"` 指令(文件转为 Client Component) +2. 新增 imports:`useState, useEffect` (react)、Dialog 子组件 5 个 (`@/components/ui/dialog`)、`KeyRound` (lucide-react)、`hasPermission` (`@/lib/permissions`) +3. 函数体顶部加 `mounted` + `isCredentialDialogOpen` 两个 `useState(false)` + 一个 `useEffect(() => setMounted(true), [])`(复用 sidebar.tsx 的 mounted 守卫模式) +4. DashboardHeader children 改为 `
` 包裹,含原「添加新模型」Button + 新增 `{mounted && hasPermission("credential-slot") && }` +5. `` 之后、`` 之前插入 controlled mode 占位 Dialog(DialogTitle「通用凭据槽位」+ DialogDescription「对话框真实内容由 Phase 3 落地」) + +**未动:** +- Tabs / TabsContent / Card 等所有原有内容(line 18-441,对应改动后 line 60-470)逐字未动 +- 不新建 `components/ai-model/CredentialSlotDialog.tsx` +- 不引入 sonner / useToast / `getCredentialSlot` / `updateCredentialSlot` +- package.json / yarn.lock / package-lock.json / pnpm-lock.yaml 全部未动 + +**验证:** +- `head -n 1 app/ai-model/page.tsx` 输出 `"use client"` +- `grep` 命中 KeyRound×2 + 凭据槽位×2 + 通用凭据槽位×1 + hasPermission("credential-slot")×1 + setIsCredentialDialogOpen×3 + 对话框真实内容由 Phase 3 落地×1 +- `npx tsc --noEmit` 无新错误指向 app/ai-model/page.tsx + +## Plan 级整体验证 + +| # | 校验项 | 结果 | +|---|--------|------| +| 1 | `npx tsc --noEmit` 不引入指向 lib/permissions.ts / app/ai-model/page.tsx 的新错误 | ✅ 0 条 | +| 2 | `grep -nE "['\"]credential-slot['\"]" lib/permissions.ts` 命中 3 行 | ✅ | +| 3 | 4 个不应含 credential-slot 的角色数组逐字未变 | ✅ | +| 4 | `getModuleFromPath` pathMap 中无新增 credential-slot 路径映射 | ✅ | +| 5 | `head -n 1 app/ai-model/page.tsx` = `"use client"` | ✅ | +| 6 | KeyRound / 凭据槽位 / 通用凭据槽位 / hasPermission(credential-slot) / setIsCredentialDialogOpen / 对话框真实内容由 Phase 3 落地 全部命中 | ✅(综合 ≥10 条) | +| 7 | `git diff --stat package.json yarn.lock package-lock.json pnpm-lock.yaml` 0 行输出(不引入新依赖) | ✅ | + +## 偏离 PLAN 之处 + +无 — Plan 02-01 完全按照 02-01-PLAN.md 的 5 处改动逐字执行;mounted 守卫模式严格复刻 components/sidebar.tsx:83-104。 + +## 已知遗留 / 移交事项 + +- **修改记录**:本 plan 未触动 `docs/修改记录.md`,由 Plan 02-02 在收尾任务中统一为 Phase 2 写一条条目 +- **占位 Dialog**:仅含 DialogTitle + DialogDescription,无 Footer / 表单 / 提交按钮;表单与提交逻辑由 Phase 3 / CRED-FE-04 落地 +- **后端联调**:Phase 3 才会真正调用 `getCredentialSlot()` / `updateCredentialSlot()`;本 plan 不涉及任何后端调用 + +## 提交历史 + +| Task | Commit | 描述 | +|------|--------|------| +| 1 | d60dd89 | feat(02-01): 扩展 RBAC 矩阵增加 credential-slot 模块 | +| 2 | 0bcaa39 | feat(02-01): /ai-model 页面新增凭据槽位入口 Button + 占位 Dialog | + +## Self-Check + +**文件存在性:** +- `lib/permissions.ts`:FOUND(126 行;123 → 126,+3 行 = union +1 / 超管 +1 / AI模型管理员 +1,注释表 +1 与原 -1 净 0;实际 4 处改动结果总 +3 行而非 +4 是因为最早 union 末项 `"settings";` 替换为 `"settings"` + 新增一行 `| "credential-slot";`,注释表本身只增 1 行,三个数组各 +1 但其中一个原行被改为多行) +- `app/ai-model/page.tsx`:FOUND(488 行;446 → 488,+42 行 = imports +13 / state +5 / DashboardHeader 重构 +7 / Dialog +14 - 其他微调) + +**Commit 存在性:** +- d60dd89:FOUND(git log) +- 0bcaa39:FOUND(git log) + +## Self-Check: PASSED