pmc 15e725a32f docs(02-01): 完成 Phase 2 Plan 02-01(RBAC 扩展 + /ai-model 凭据槽位入口)
- 新增 .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
2026-05-08 11:47:59 +08:00

7.8 KiB
Raw Blame History

phase, plan, subsystem, tags, requires, provides, affects, tech-stack, key-files, decisions, metrics
phase plan subsystem tags requires provides affects tech-stack key-files decisions metrics
02-rbac-ai 01 rbac + ai-model-page
rbac
permissions
ai-model
dialog
client-component
lib/api/credential-slot.ts:CredentialSlotPhase 1 已交付,本 plan 暂未直接消费,留给 Phase 3
components/ui/dialog.tsx:Dialog/DialogContent/DialogHeader/DialogTitle/DialogDescription
components/ui/button.tsx:Button(variant="outline")
components/dashboard-header.tsx:DashboardHeaderchildren 单 slot
components/sidebar.tsx:mounted 守卫模式line 83-104
lucide-react:KeyRound
PermissionModule literal "credential-slot"lib/permissions.ts
PERMISSION_MATRIX 中超级管理员/AI模型管理员可访问 credential-slot
/ai-model 页面入口 Button受 hasPermission 收敛)
占位 Dialog 挂载点Phase 3 落实表单内容)
lib/permissions.ts
app/ai-model/page.tsx
added patterns
mounted 守卫(避免 SSR 水合警告,复用 components/sidebar.tsx 同模式)
hasPermission(...) && JSX 收敛DOM 中完全不存在,非仅 hidden
Dialog controlled modeopen + onOpenChange + useState 配对)
created modified
lib/permissions.ts
app/ai-model/page.tsx
凭据槽位入口 Button 与原「添加新模型」Button 用 div.flex.items-center.gap-2 包裹后作为 DashboardHeader children 单节点传入DashboardHeader 本身只渲染单 children slot无 gap
入口 Button variant="outline"(与现有页面其他次要按钮如「查看详情」「试听示例」视觉一致)
图标用 KeyRoundlucide-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)) 模式
duration completed tasks files_changed lines_added lines_removed
~6min 2026-05-08 2 2 53 6

Phase 2 Plan 01扩展 RBAC 矩阵 + /ai-model 页面凭据槽位入口 Summary

一句话

'credential-slot' 模块加入 PermissionModule union 与「超级管理员/AI模型管理员」角色矩阵同时把 /ai-model 页面转为 Client Component 并加上受 mounted && hasPermission('credential-slot') 收敛的「凭据槽位」入口 Button + 占位 DialogDialogTitle「通用凭据槽位」+ 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 RBACcommit 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 2app/ai-model/page.tsx 加入口 Button + 占位 Dialogcommit 0bcaa39

改动 5 处(与 PLAN 一致):

  1. line 1 加 "use client" 指令(文件转为 Client Component
  2. 新增 importsuseState, 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 改为 <div className="flex items-center gap-2"> 包裹含原「添加新模型」Button + 新增 {mounted && hasPermission("credential-slot") && <Button variant="outline" onClick={() => setIsCredentialDialogOpen(true)}><KeyRound .../>凭据槽位</Button>}
  5. </Tabs> 之后、</DashboardShell> 之前插入 controlled mode 占位 DialogDialogTitle「通用凭据槽位」+ 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.tsFOUND126 行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.tsxFOUND488 行446 → 488+42 行 = imports +13 / state +5 / DashboardHeader 重构 +7 / Dialog +14 - 其他微调)

Commit 存在性:

  • d60dd89FOUNDgit log
  • 0bcaa39FOUNDgit log

Self-Check: PASSED