419 lines
25 KiB
Markdown
419 lines
25 KiB
Markdown
---
|
||
phase: 02-rbac-ai
|
||
plan: 02
|
||
type: execute
|
||
wave: 2
|
||
depends_on:
|
||
- "02-01"
|
||
files_modified:
|
||
- docs/修改记录.md
|
||
autonomous: true
|
||
requirements:
|
||
- CRED-FE-02
|
||
- CRED-FE-03
|
||
must_haves:
|
||
truths:
|
||
- "docs/修改记录.md 顶部含一条 [2026-05-08] Phase 2 条目(最新在最前,紧跟「修改历史」标记之后、Phase 1 [2026-05-08] 条目之前)"
|
||
- "Phase 2 条目含完整 5 字段:日期、文件路径、修改类型、修改内容、修改原因,外加跨项目联动 + 服务端联动两个项目惯用扩展字段"
|
||
- "Phase 2 条目「文件路径」字段列出本期实际改动的 2 个文件:lib/permissions.ts、app/ai-model/page.tsx"
|
||
- "「跨项目联动」字段写「无 — Phase 2 是纯前端 RBAC + UI 入口落地,不引入新跨项目契约;后端 commit 46d72b8 已建立的互引仍有效;Phase 3 引入实质 PUT 调用时若涉及新契约再评估」(CONTEXT.md D-XX 锁定文案)"
|
||
- "Phase 2 条目覆盖前端需求:CRED-FE-02 + CRED-FE-03(在条目元信息行明确列出)"
|
||
- "整体类型检查 npx tsc --noEmit 整体退出码可能为 2(存量错误),但 grep 过滤后 0 条指向本 phase 改动的 lib/permissions.ts 与 app/ai-model/page.tsx(Phase 1 已建立的判定模式)"
|
||
- "package.json / yarn.lock / package-lock.json / pnpm-lock.yaml 4 个 manifest/lockfile 均未改动(不引入新依赖)"
|
||
artifacts:
|
||
- path: "docs/修改记录.md"
|
||
provides: "顶部 Phase 2 修改记录条目"
|
||
contains: "[2026-05-08] Phase 2"
|
||
min_lines: 100
|
||
key_links:
|
||
- from: "docs/修改记录.md Phase 2 条目"
|
||
to: "Plan 02-01 改动的 lib/permissions.ts + app/ai-model/page.tsx"
|
||
via: "「文件路径」字段精确列出"
|
||
pattern: "lib/permissions\\.ts|app/ai-model/page\\.tsx"
|
||
- from: "docs/修改记录.md Phase 2 条目「服务端联动」字段"
|
||
to: "qy_lty/.planning/phases/02-admin-rest commit 46d72b8"
|
||
via: "文本引用 commit hash"
|
||
pattern: "46d72b8"
|
||
---
|
||
|
||
<objective>
|
||
完成 Phase 2 收尾:在 `docs/修改记录.md` 顶部追加 Phase 2 条目(CLAUDE.md 强制要求),并执行 plan 级整体验证(双重类型检查 + grep 11 条 specifics 全命中 + 不引入新依赖)。
|
||
|
||
Purpose:满足 CLAUDE.md 项目宪法「修改记录强制」规则;按 Phase 1 已建立的双重验证模式(tsc + grep)封盘 Phase 2,让 STATE.md 可推进到 Phase 3 待启动状态。
|
||
Output:`docs/修改记录.md`(修改,仅顶部追加;不动其他历史条目)。
|
||
</objective>
|
||
|
||
<execution_context>
|
||
@$HOME/.claude/get-shit-done/workflows/execute-plan.md
|
||
@$HOME/.claude/get-shit-done/templates/summary.md
|
||
</execution_context>
|
||
|
||
<context>
|
||
@.planning/PROJECT.md
|
||
@.planning/ROADMAP.md
|
||
@.planning/STATE.md
|
||
@.planning/phases/02-rbac-ai/02-CONTEXT.md
|
||
@.planning/phases/02-rbac-ai/02-RESEARCH.md
|
||
@.planning/phases/02-rbac-ai/02-01-PLAN.md
|
||
@CLAUDE.md
|
||
@docs/修改记录.md
|
||
@lib/permissions.ts
|
||
@app/ai-model/page.tsx
|
||
</context>
|
||
|
||
<interfaces>
|
||
<!-- 修改记录头部「修改格式说明」(VERIFIED docs/修改记录.md line 9-20) -->
|
||
|
||
```
|
||
### [日期] 修改简述
|
||
|
||
- **文件路径**: 相对于项目根目录的文件路径
|
||
- **修改类型**: 新增 / 修改 / 删除 / 重构 / 修复Bug
|
||
- **修改内容**: 具体修改了什么
|
||
- **修改原因**: 为什么要做这个修改
|
||
```
|
||
|
||
<!-- Phase 1 条目(VERIFIED docs/修改记录.md line 28-48)作为本期模板,关键扩展字段 -->
|
||
|
||
Phase 1 条目结构(**直接抄此 7 字段结构**):
|
||
1. **元信息行**(标题下方紧跟):「配套服务端 Phase: ...」+「覆盖前端需求: CRED-FE-XX」
|
||
2. **文件路径**:列出实际改动的所有文件相对路径
|
||
3. **修改类型**:新增 / 修改 / 删除 / 重构 / 修复Bug
|
||
4. **修改内容**:分点 bullet 描述每个文件做了什么
|
||
5. **修改原因**:解释为什么做、对后续 phase 的支撑作用
|
||
6. **跨项目联动**(项目惯用扩展字段,CONTEXT.md 已锁定本期文案)
|
||
7. **服务端联动**(项目惯用扩展字段,可与「跨项目联动」复用文案或简短交叉引用)
|
||
|
||
<!-- 顶部插入位置 -->
|
||
|
||
`docs/修改记录.md` line 26 是注释 `<!-- 新的修改记录添加在此处下方,最新的在最前面 -->`,line 28 是当前最顶 Phase 1 条目 `### [2026-05-08] Phase 1(前端)凭据槽位 API 客户端`。**新条目必须插入到 line 26 的注释**之后**、line 28 的 Phase 1 条目**之前**。
|
||
</interfaces>
|
||
|
||
<tasks>
|
||
|
||
<task type="auto" tdd="false">
|
||
<name>任务 1:docs/修改记录.md 顶部追加 Phase 2 条目</name>
|
||
<files>docs/修改记录.md</files>
|
||
|
||
<read_first>
|
||
1. **必读**:`docs/修改记录.md` 完整 line 1-50(确认头部「修改格式说明」+ line 26 锚点注释 + line 28-48 Phase 1 条目作为模板)
|
||
2. **必读**:`.planning/phases/02-rbac-ai/02-CONTEXT.md` 「修改记录」段(CONTEXT D-XX 锁定的「跨项目联动」字段精确文案)
|
||
3. **必读**:`.planning/phases/02-rbac-ai/02-01-PLAN.md`(确认 Phase 2 实际改动文件 = `lib/permissions.ts` + `app/ai-model/page.tsx`)
|
||
4. **必读**:`CLAUDE.md` 「项目修改记录规则(重要 — 自动执行)」段 + 「`qy-lty-admin` 与 `qy_lty` 是独立项目,各自维护」段
|
||
</read_first>
|
||
|
||
<action>
|
||
用 Edit 工具对 `docs/修改记录.md` 做**1 处**精确插入:在 line 26 的锚点注释 `<!-- 新的修改记录添加在此处下方,最新的在最前面 -->` 之后、line 28 的 `### [2026-05-08] Phase 1(前端)凭据槽位 API 客户端` 之前,插入完整 Phase 2 条目。
|
||
|
||
**old_string**(精确匹配 line 26-28,含中间空行):
|
||
```
|
||
<!-- 新的修改记录添加在此处下方,最新的在最前面 -->
|
||
|
||
### [2026-05-08] Phase 1(前端)凭据槽位 API 客户端
|
||
```
|
||
|
||
**new_string**(在锚点与 Phase 1 之间插入完整 Phase 2 条目;Phase 2 条目结尾 → 1 个空行 → Phase 1 条目原行):
|
||
```
|
||
<!-- 新的修改记录添加在此处下方,最新的在最前面 -->
|
||
|
||
### [2026-05-08] Phase 2(前端)RBAC 收敛 + AI 模型页凭据槽位入口
|
||
|
||
配套服务端 Phase:本 phase **不**触达服务端;与服务端 v1.0 Phase 2「管理端读写接口」commit `46d72b8` 既有契约保持兼容(不引入新契约)
|
||
覆盖前端需求:CRED-FE-02、CRED-FE-03
|
||
|
||
- **文件路径**:
|
||
- `lib/permissions.ts`(修改)
|
||
- `app/ai-model/page.tsx`(修改)
|
||
- **修改类型**: 修改(前端 RBAC 矩阵扩展 + 页面入口控件 + 占位 Dialog;纯前端,无新依赖、不动 lockfile)
|
||
- **修改内容**:
|
||
- `lib/permissions.ts`:
|
||
- `PermissionModule` union 末尾追加 `"credential-slot"`,扩为 14 项
|
||
- `PERMISSION_MATRIX["超级管理员"]` 数组末尾追加 `"credential-slot"`
|
||
- `PERMISSION_MATRIX["AI模型管理员"]` 数组末尾追加 `"credential-slot"`
|
||
- 其他 4 个角色(内容管理员 / 卡牌管理员 / 查看者 / 管理员)数组**逐字不变**
|
||
- `getModuleFromPath` 函数体完全不动(凭据槽位是 `/ai-model` 子能力,不占独立路由)
|
||
- 顶部「权限矩阵对照表」注释新增一行「凭据槽位」与代码同步
|
||
- `app/ai-model/page.tsx`:
|
||
- 文件 line 1 顶部新增 `"use client"` 指令,从 Server Component 转为 Client Component
|
||
- 新增 import:`useState` / `useEffect`(react)+ `Dialog` / `DialogContent` / `DialogDescription` / `DialogHeader` / `DialogTitle`(@/components/ui/dialog)+ `KeyRound`(lucide-react)+ `hasPermission`(@/lib/permissions)
|
||
- 函数体顶部新增 `mounted` + `isCredentialDialogOpen` 两个 `useState` + 1 个 `useEffect` 设 `mounted` 为 true(复用 `components/sidebar.tsx` mounted 守卫模式避免 SSR 水合不匹配)
|
||
- `DashboardHeader` 内部用 `<div className="flex items-center gap-2">` 包两个 Button:保留原有「添加新模型」+ 新增 `{mounted && hasPermission("credential-slot") && <Button variant="outline" onClick={() => setIsCredentialDialogOpen(true)}><KeyRound /> 凭据槽位</Button>}`
|
||
- `</Tabs>` 之后、`</DashboardShell>` 之前新增 controlled mode `<Dialog open={isCredentialDialogOpen} onOpenChange={setIsCredentialDialogOpen}>`,内含 `DialogTitle`「通用凭据槽位」+ `DialogDescription`「对话框真实内容由 Phase 3 落地」(占位,无表单)
|
||
- Tabs / TabsContent / Card / 卡片内的现有按钮等所有内容(line 18-441)逐字不变
|
||
- **修改原因**:
|
||
- 推进 Milestone v1.0「通用凭据槽位前端集成」第二步:让授权运营立即看到入口(已就位的 UX 收敛),未授权角色彻底看不到(DOM 中完全不存在的安全前置)
|
||
- 沿用 RBAC 单一来源原则(`lib/permissions.ts:hasPermission`)+ shadcn Dialog primitive,不重复造轮子
|
||
- 为 Phase 3 真实表单(CRED-FE-04 + CRED-FE-05)预留 Dialog 挂载点;Dialog 用 controlled mode 让 Phase 3 可在打开瞬间触发 `getCredentialSlot()`
|
||
- 注意:前端 RBAC 仅是 UI 礼貌,最终安全闭环依赖后端 `/v1/admin/credential-slot/` 的 admin 鉴权(PERM-06 / `qy_lty` 后端);本 phase 不消化该闭环
|
||
- **跨项目联动**: 无 — Phase 2 是纯前端 RBAC + UI 入口落地,不引入新跨项目契约;后端 commit 46d72b8 已建立的互引仍有效;Phase 3 引入实质 PUT 调用时若涉及新契约再评估
|
||
- **服务端联动**: 同上「跨项目联动」字段;后端 commit `46d72b8` 已建立互引闭环,本 phase 无需再次互引
|
||
|
||
### [2026-05-08] Phase 1(前端)凭据槽位 API 客户端
|
||
```
|
||
|
||
**明确不要做的事**:
|
||
- 不要动 line 1-26 的头部说明 / 修改格式说明 / 修改历史标记
|
||
- 不要动 line 28 之后任何已有条目(Phase 1 / 2026-05-07 的两个条目 / 2026-04-30 初始化条目)
|
||
- 不要把「跨项目联动」字段文案缩短或重写(CONTEXT.md 已逐字锁定)
|
||
- 不要漏掉 Phase 2 条目的「覆盖前端需求」元信息行(必须含 CRED-FE-02 + CRED-FE-03)
|
||
- 不要在「文件路径」中列入 docs/修改记录.md 自身(CLAUDE.md 适用范围说「单纯的 typo 修复 / 注释微调可省略」,但本条目作为 phase 收尾骨干条目,遵循 Phase 1 模板的写法 = 仅列被修改的代码文件)
|
||
</action>
|
||
|
||
<acceptance_criteria>
|
||
- `grep -n "\\[2026-05-08\\] Phase 2" docs/修改记录.md` 命中 1 行(标题行)
|
||
- `grep -n "\\[2026-05-08\\] Phase 1" docs/修改记录.md` 仍命中 1 行(Phase 1 条目未被破坏)
|
||
- `head -n 30 docs/修改记录.md` 输出含「修改格式说明」+「修改历史」+ `<!-- 新的修改记录添加在此处下方,最新的在最前面 -->` 锚点(line 1-26 完全不变)
|
||
- `awk '/### \\[2026-05-08\\]/{count++} count==1 && /Phase 2/{print "PASS"; exit} count==1 && /Phase 1/{print "FAIL: Phase 1 在最前面"; exit}' docs/修改记录.md` 输出 `PASS`(确保 Phase 2 在 Phase 1 之上)
|
||
- `grep -nE "CRED-FE-(02|03)" docs/修改记录.md | head -n 5` 命中至少 1 行包含 `CRED-FE-02` 或 `CRED-FE-03` 的元信息行(在 Phase 2 条目之内)
|
||
- `grep -n "credential-slot" docs/修改记录.md` 命中 ≥1 行(Phase 2 条目里描述 PermissionModule 字面量)
|
||
- `grep -n "46d72b8" docs/修改记录.md` 命中 ≥2 行(Phase 1 条目已有的 + Phase 2 条目新增的,证明跨项目联动文案已嵌入)
|
||
- `grep -n "凭据槽位" docs/修改记录.md` 命中 ≥1 行(Phase 2 条目内容描述)
|
||
- `grep -n "通用凭据槽位" docs/修改记录.md` 命中 ≥1 行(Phase 2 条目 DialogTitle 描述)
|
||
- `git diff --stat docs/修改记录.md` 显示仅 +N 行(无 -行;纯追加)
|
||
</acceptance_criteria>
|
||
|
||
<verify>
|
||
<automated>
|
||
cd C:\Users\admin\Desktop\Lila-Server\qy-lty-admin && grep -c "\[2026-05-08\] Phase 2" docs/修改记录.md
|
||
# 预期:1
|
||
</automated>
|
||
<automated>
|
||
cd C:\Users\admin\Desktop\Lila-Server\qy-lty-admin && grep -c "\[2026-05-08\] Phase 1" docs/修改记录.md
|
||
# 预期:1(Phase 1 条目仍存在)
|
||
</automated>
|
||
<automated>
|
||
cd C:\Users\admin\Desktop\Lila-Server\qy-lty-admin && awk '/### \[2026-05-08\] Phase 2/{p2=NR} /### \[2026-05-08\] Phase 1/{p1=NR} END{ if(p2>0 && p1>0 && p2<p1) print "PASS"; else print "FAIL p2="p2" p1="p1 }' docs/修改记录.md
|
||
# 预期:PASS
|
||
</automated>
|
||
<automated>
|
||
cd C:\Users\admin\Desktop\Lila-Server\qy-lty-admin && grep -c "CRED-FE-02" docs/修改记录.md
|
||
# 预期:≥1
|
||
</automated>
|
||
</verify>
|
||
|
||
<done>
|
||
- `docs/修改记录.md` 顶部新增 Phase 2 条目(最新在最前)
|
||
- 条目含 5 个标准字段(文件路径 / 修改类型 / 修改内容 / 修改原因)+ 2 个项目惯用扩展字段(跨项目联动 / 服务端联动)+ 元信息行(覆盖前端需求 + 配套服务端 Phase)
|
||
- 「跨项目联动」字段文案逐字与 CONTEXT.md 锁定一致
|
||
- Phase 1 条目以及更早的所有历史条目逐字不变
|
||
</done>
|
||
</task>
|
||
|
||
<task type="auto" tdd="false">
|
||
<name>任务 2:plan 级整体双重验证(tsc + grep + 不引入新依赖)</name>
|
||
<files></files>
|
||
|
||
<read_first>
|
||
1. **必读**:`.planning/phases/02-rbac-ai/02-01-PLAN.md` 的 `<verification>` 段(4 条整体校验列表)
|
||
2. **必读**:`.planning/phases/02-rbac-ai/02-CONTEXT.md` 「specifics」表(11 条验证点)
|
||
3. **必读**:`.planning/STATE.md` Phase 1 收尾段(line 80-81)确认 Phase 1 已建立的 tsc 双重验证模式(整体退出码 2 但过滤后零指向新文件)
|
||
4. **必读**:本 plan 任务 1 落地后的 `docs/修改记录.md` 顶部(确认 Phase 2 条目结构正确)
|
||
</read_first>
|
||
|
||
<action>
|
||
本任务**不修改任何代码或配置文件**,仅执行验证命令并把结果汇总写入 `02-02-SUMMARY.md`(在 Plan 02-02 收尾时由 execute-plan 流程统一写)。
|
||
|
||
按以下顺序执行**4 大类**验证命令,逐条记录退出码与命中数:
|
||
|
||
### 验证 A:TypeScript 编译(双重判定,与 Phase 1 一致)
|
||
|
||
```bash
|
||
cd C:\Users\admin\Desktop\Lila-Server\qy-lty-admin
|
||
npx tsc --noEmit > /tmp/tsc-phase2.log 2>&1
|
||
echo "tsc exit code: $?"
|
||
|
||
# 整体错误数(预期与 Phase 1 的 67 条相近 ± 微小波动;不应大幅增加)
|
||
grep -cE "error TS" /tmp/tsc-phase2.log
|
||
|
||
# 反向断言:本 phase 改动文件零类型错误
|
||
grep -E "(lib/permissions\.ts|app/ai-model/page\.tsx)" /tmp/tsc-phase2.log
|
||
# 预期:0 行输出(grep 退出码 1 也算 PASS)
|
||
```
|
||
|
||
**判定**:
|
||
- tsc 整体退出码可能为 2(存量错误),允许
|
||
- 反向 grep 必须 0 行输出(无任何错误指向 `lib/permissions.ts` 或 `app/ai-model/page.tsx`)
|
||
- 整体错误数与 Phase 1 收尾时(67 条)相比浮动 ≤ 3 条,否则人工核查是否有新引入
|
||
|
||
### 验证 B:specifics 11 条 grep 全命中(CONTEXT.md 锁定)
|
||
|
||
```bash
|
||
cd C:\Users\admin\Desktop\Lila-Server\qy-lty-admin
|
||
|
||
# specifics 1:PermissionModule union 含 credential-slot
|
||
grep -cE "['\"]credential-slot['\"]" lib/permissions.ts # 期望 ≥3
|
||
|
||
# specifics 2-3:超管 + AI模型管理员含;其他 4 角色不含
|
||
awk '/超级管理员: \[/,/\],/' lib/permissions.ts | grep -c "credential-slot" # 期望 1
|
||
awk '/AI模型管理员: \[/,/\],/' lib/permissions.ts | grep -c "credential-slot" # 期望 1
|
||
awk '/内容管理员: \[/,/\],/' lib/permissions.ts | grep -c "credential-slot" # 期望 0
|
||
awk '/卡牌管理员: \[/,/\],/' lib/permissions.ts | grep -c "credential-slot" # 期望 0
|
||
awk '/查看者: \[/,/\],/' lib/permissions.ts | grep -c "credential-slot" # 期望 0
|
||
# 「管理员」(最末位)匹配,避免被「AI模型管理员」前缀干扰:用末尾段
|
||
awk '/^ 管理员: \[/,/\],/' lib/permissions.ts | grep -c "credential-slot" # 期望 0
|
||
|
||
# specifics 4:getModuleFromPath 行为不变
|
||
grep -c '"ai-model": "ai-model"' lib/permissions.ts # 期望 1
|
||
|
||
# specifics 5:app/ai-model/page.tsx 第 1 行是 "use client"
|
||
head -n 1 app/ai-model/page.tsx | grep -c '"use client"' # 期望 1
|
||
|
||
# specifics 6:含「凭据槽位」文案
|
||
grep -c "凭据槽位" app/ai-model/page.tsx # 期望 ≥2(Button + DialogTitle)
|
||
|
||
# specifics 7:含 KeyRound
|
||
grep -c "KeyRound" app/ai-model/page.tsx # 期望 ≥2
|
||
|
||
# specifics 8:含 hasPermission("credential-slot")
|
||
grep -cE "hasPermission\\([\"']credential-slot[\"']\\)" app/ai-model/page.tsx # 期望 ≥1
|
||
|
||
# specifics 9:含 useState + onClick + Dialog 三连
|
||
grep -c "useState" app/ai-model/page.tsx # 期望 ≥3(import + 2 调用)
|
||
grep -c "setIsCredentialDialogOpen" app/ai-model/page.tsx # 期望 ≥3
|
||
|
||
# specifics 10:占位 Dialog 含「通用凭据槽位」DialogTitle
|
||
grep -c "通用凭据槽位" app/ai-model/page.tsx # 期望 1
|
||
|
||
# specifics 11:修改记录顶部含 Phase 2 条目
|
||
grep -c "\[2026-05-08\] Phase 2" docs/修改记录.md # 期望 1
|
||
```
|
||
|
||
**判定**:以上 14 条 grep 全部满足预期值 → 11 条 specifics 全命中。
|
||
|
||
### 验证 C:不引入新依赖
|
||
|
||
```bash
|
||
cd C:\Users\admin\Desktop\Lila-Server\qy-lty-admin
|
||
git diff --name-only -- package.json yarn.lock package-lock.json pnpm-lock.yaml 2>/dev/null
|
||
# 期望:0 行输出(4 个文件均未改动)
|
||
|
||
git diff --name-only HEAD~1 -- package.json yarn.lock package-lock.json pnpm-lock.yaml 2>/dev/null
|
||
# 期望:0 行输出(与上一 commit 比较仍无 manifest 改动)
|
||
```
|
||
|
||
**判定**:4 个文件均未出现在 diff → 不引入新依赖。
|
||
|
||
### 验证 D:(跳过)next lint
|
||
|
||
`npm run lint`(即 `next lint`)在 Phase 1 已确认会进入「ESLint 未 bootstrap → 交互式 prompt」状态(无 `.eslintrc*` / `eslint-config-next`),按 STATE.md line 81「ESLint 基础设施补齐留给 PERM-06 候选 #3」的判定 → **本 phase 跳过 lint**,与 Phase 1 一致。
|
||
|
||
在 SUMMARY 中显式记录:「next lint 因项目未 bootstrap ESLint 跳过;判定与 Phase 1 一致;不指向本 phase 改动文件」。
|
||
|
||
### 失败处理
|
||
|
||
任一条验证失败 → **不要继续**,立即返回 STATE 报告问题,不可静默继续 SUMMARY 写入;按以下优先级处理:
|
||
1. tsc 出现指向 `lib/permissions.ts` 或 `app/ai-model/page.tsx` 的新错误 → 回到 Plan 02-01 任务 1 或 2 修补
|
||
2. 反向 grep 在「内容管理员 / 卡牌管理员 / 查看者 / 管理员」数组中命中 `credential-slot` → 回到 Plan 02-01 任务 1 重新核对
|
||
3. specifics grep 数量不足 → 回到 Plan 02-01 任务 2 检查 import / JSX
|
||
4. package.json / lockfile 出现 diff → 回滚 lockfile(`git checkout HEAD -- package.json yarn.lock package-lock.json pnpm-lock.yaml`)
|
||
</action>
|
||
|
||
<acceptance_criteria>
|
||
- 验证 A:tsc 整体退出码 2 容许;过滤后 0 行指向 `lib/permissions.ts` / `app/ai-model/page.tsx`
|
||
- 验证 B:14 条 grep 全部满足预期值(specifics 11 条 + 反向断言 3 条)
|
||
- 验证 C:`git diff` 对 4 个 manifest/lockfile 文件输出 0 行
|
||
- 验证 D:在 SUMMARY 中显式记录「next lint 跳过原因」
|
||
</acceptance_criteria>
|
||
|
||
<verify>
|
||
<automated>
|
||
cd C:\Users\admin\Desktop\Lila-Server\qy-lty-admin && npx tsc --noEmit 2>&1 | grep -cE "(lib/permissions\.ts|app/ai-model/page\.tsx)"
|
||
# 预期:0
|
||
</automated>
|
||
<automated>
|
||
cd C:\Users\admin\Desktop\Lila-Server\qy-lty-admin && (awk '/超级管理员: \[/,/\],/' lib/permissions.ts | grep -c "credential-slot") && (awk '/AI模型管理员: \[/,/\],/' lib/permissions.ts | grep -c "credential-slot")
|
||
# 预期:两条命令各输出 1
|
||
</automated>
|
||
<automated>
|
||
cd C:\Users\admin\Desktop\Lila-Server\qy-lty-admin && for ROLE in 内容管理员 卡牌管理员 查看者; do echo "$ROLE: $(awk -v role="$ROLE" '$0 ~ role"\\: \\[" {flag=1} flag {print} /\],/ {flag=0}' lib/permissions.ts | grep -c "credential-slot")"; done
|
||
# 预期:3 行各为 X: 0
|
||
</automated>
|
||
<automated>
|
||
cd C:\Users\admin\Desktop\Lila-Server\qy-lty-admin && git diff --name-only -- package.json yarn.lock package-lock.json pnpm-lock.yaml | wc -l
|
||
# 预期:0
|
||
</automated>
|
||
<automated>
|
||
cd C:\Users\admin\Desktop\Lila-Server\qy-lty-admin && head -n 1 app/ai-model/page.tsx
|
||
# 预期:含 "use client"
|
||
</automated>
|
||
<automated>
|
||
cd C:\Users\admin\Desktop\Lila-Server\qy-lty-admin && grep -c "\[2026-05-08\] Phase 2" docs/修改记录.md
|
||
# 预期:1
|
||
</automated>
|
||
</verify>
|
||
|
||
<done>
|
||
- 4 大类验证全部通过(A / B / C / D)
|
||
- 11 条 specifics 全命中,反向断言(其他 4 角色数组不含 `credential-slot`)通过
|
||
- tsc 不引入指向本 phase 改动文件的新错误
|
||
- 不引入新依赖(4 个 manifest/lockfile 均未改动)
|
||
- SUMMARY 中明确记录 next lint 跳过原因(与 Phase 1 一致)
|
||
</done>
|
||
</task>
|
||
|
||
</tasks>
|
||
|
||
<verification>
|
||
## Plan 级整体验证(覆盖整个 Phase 2)
|
||
|
||
执行完两个任务后,确认以下**3 条**整体校验通过:
|
||
|
||
### 1. 修改记录顶部条目格式
|
||
```bash
|
||
cd C:\Users\admin\Desktop\Lila-Server\qy-lty-admin
|
||
sed -n '/<!-- 新的修改记录添加在此处下方/,/### \[2026-05-08\] Phase 1/p' docs/修改记录.md | head -n 60
|
||
```
|
||
**判定**:输出含完整 Phase 2 条目结构(标题 / 元信息行 / 文件路径 / 修改类型 / 修改内容 / 修改原因 / 跨项目联动 / 服务端联动)+ 紧跟 Phase 1 标题行作为下一条。
|
||
|
||
### 2. RBAC 矩阵 5+1 角色逐一确认
|
||
```bash
|
||
cd C:\Users\admin\Desktop\Lila-Server\qy-lty-admin
|
||
echo "应含 credential-slot 的 2 角色:"
|
||
awk '/超级管理员: \[/,/\],/' lib/permissions.ts | grep "credential-slot"
|
||
awk '/AI模型管理员: \[/,/\],/' lib/permissions.ts | grep "credential-slot"
|
||
echo "应不含 credential-slot 的 4 角色:"
|
||
for ROLE in 内容管理员 卡牌管理员 查看者; do
|
||
HIT=$(awk -v role="$ROLE" '$0 ~ role"\\: \\[" {flag=1} flag {print} /\],/ {flag=0}' lib/permissions.ts | grep -c "credential-slot")
|
||
echo "$ROLE: $HIT 次(期望 0)"
|
||
done
|
||
# 「管理员」单独取末尾段(避免「AI模型管理员」前缀污染)
|
||
awk '/^ 管理员: \[/,/\],/' lib/permissions.ts | grep -c "credential-slot"
|
||
```
|
||
**判定**:超管 + AI模型管理员各命中 1 次;其他 4 角色各 0 次。
|
||
|
||
### 3. Phase 2 入口控件 + 占位 Dialog 端到端就位
|
||
```bash
|
||
cd C:\Users\admin\Desktop\Lila-Server\qy-lty-admin
|
||
# 整段验证:1) "use client" 顶置;2) 入口 Button 受 mounted + hasPermission 守卫;3) Dialog 在 DashboardShell 末尾
|
||
echo "=== line 1 ==="
|
||
head -n 1 app/ai-model/page.tsx
|
||
echo "=== mounted 守卫 + hasPermission(credential-slot) ==="
|
||
grep -nE "mounted &&" app/ai-model/page.tsx
|
||
grep -nE "hasPermission\\([\"']credential-slot" app/ai-model/page.tsx
|
||
echo "=== Dialog 占位 ==="
|
||
grep -nE "<DialogTitle>通用凭据槽位</DialogTitle>" app/ai-model/page.tsx
|
||
grep -nE "对话框真实内容由 Phase 3 落地" app/ai-model/page.tsx
|
||
```
|
||
**判定**:所有 5 段输出非空且行号合理("use client" 在 line 1;mounted + hasPermission 守卫在 DashboardHeader 区域;Dialog 在文件末尾区域)。
|
||
|
||
**整体判定**:3 条全部通过 → Phase 2 全部交付,可推进 STATE.md → Phase 3 待启动。
|
||
</verification>
|
||
|
||
<success_criteria>
|
||
**ROADMAP.md Phase 2 Success Criteria 4 条最终确认(前 3 条由 Plan 02-01 主体落地、本 Plan 02-02 验证;第 4 条由 Plan 02-01 落地、本 Plan 02-02 验证;CLAUDE.md 修改记录强制由本 Plan 02-02 落地):**
|
||
|
||
1. ✅ 验证:`hasPermission('credential-slot')` 对超管 + AI模型管理员返回 true、其他角色返回 false(通过本 plan 验证 B 段反向断言确认)
|
||
2. ✅ 验证:`getModuleFromPath('/ai-model')` 行为不变(通过 grep `'ai-model': 'ai-model'` 仍命中 1 行确认)
|
||
3. ✅ 验证:`/ai-model` 页面 DashboardHeader 含「凭据槽位」入口控件,未授权角色 DOM 中不存在(通过 mounted + hasPermission 守卫的 grep 命中确认)
|
||
4. ✅ 验证:可见性走 `hasPermission('credential-slot')`、点击触发占位 Dialog 打开(通过 grep `setIsCredentialDialogOpen(true)` + `<Dialog open=` 命中确认)
|
||
5. ✅ CLAUDE.md 修改记录强制:`docs/修改记录.md` 顶部含 Phase 2 条目,跨项目联动字段写「无」(CONTEXT.md 锁定文案)
|
||
</success_criteria>
|
||
|
||
<output>
|
||
完成后由 execute-plan 自动创建:
|
||
- `.planning/phases/02-rbac-ai/02-01-SUMMARY.md`(Plan 02-01 收尾摘要:RBAC 矩阵 + 入口控件 + Dialog 落地)
|
||
- `.planning/phases/02-rbac-ai/02-02-SUMMARY.md`(Plan 02-02 收尾摘要:修改记录追加 + 双重验证结果,含 next lint 跳过说明)
|
||
|
||
并由后续 `/gsd-verify-phase 2`(如启用)或人工触发把 STATE.md 推进到 Phase 3 待启动状态。
|
||
</output>
|