From ce0df098be9337ab50cffbec7e3fe9e87ad7d597 Mon Sep 17 00:00:00 2001 From: pmc <740076875@qq.com> Date: Fri, 8 May 2026 11:06:42 +0800 Subject: [PATCH] =?UTF-8?q?docs(01-01):=20=E5=AE=8C=E6=88=90=20Phase=201?= =?UTF-8?q?=20Plan=2001-01=E3=80=8C=E5=87=AD=E6=8D=AE=E6=A7=BD=E4=BD=8D=20?= =?UTF-8?q?API=20=E5=AE=A2=E6=88=B7=E7=AB=AF=E3=80=8D=E6=94=B6=E5=B0=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增 01-01-SUMMARY.md:记录 Task 1/2 commits、关键串命中、字节产物对比、Self-Check PASSED - STATE.md:当前位置切到 'Plan 01-01 完成 / 01-02 待执行',进度 50%(Phase 1 内部 1/2 plan),新增 Plan 执行记录表 + 2026-05-08 关键决策 - ROADMAP.md:Phase 1 进度 0/2 → 1/2,状态 Not started → In Progress - REQUIREMENTS.md:CRED-FE-01 Active 段已勾选 [x];Traceability 状态切到 ✅ Done(commits a0d0b9c + c072bbe) Plan 01-01 父仓库 commits:a0d0b9c (lib/api/credential-slot.ts) + c072bbe (lib/api/index.ts) --- qy-lty-admin/.planning/REQUIREMENTS.md | 5 +- qy-lty-admin/.planning/ROADMAP.md | 4 +- qy-lty-admin/.planning/STATE.md | 38 +++-- .../01-credential-slot-api/01-01-SUMMARY.md | 158 ++++++++++++++++++ 4 files changed, 186 insertions(+), 19 deletions(-) create mode 100644 qy-lty-admin/.planning/phases/01-credential-slot-api/01-01-SUMMARY.md diff --git a/qy-lty-admin/.planning/REQUIREMENTS.md b/qy-lty-admin/.planning/REQUIREMENTS.md index ed4ae75..14d340a 100644 --- a/qy-lty-admin/.planning/REQUIREMENTS.md +++ b/qy-lty-admin/.planning/REQUIREMENTS.md @@ -87,7 +87,7 @@ ### 通用凭据槽位前端集成(CRED-FE) -- [ ] **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` 导出 +- [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 时可见;点击触发对话框打开 - [ ] **CRED-FE-04** 编辑对话框组件 `components/ai-model/CredentialSlotDialog.tsx`:基于 `components/ui/dialog.tsx`;表单 React Hook Form + Zod 校验;预填态显示后端返回的 `app_id` 明文 + `access_token` 末 4 位掩码 + 不可改的 `updated_at`;表单语义为"留空保留旧值,重新输入才覆写"(避免把脱敏掩码当真值回写);提交触发 `updateCredentialSlot()`,仅提交用户实际输入的字段 @@ -133,7 +133,7 @@ | Requirement | Phase | UI hint | Status | |-------------|-------|---------|--------| -| CRED-FE-01 API 客户端 `lib/api/credential-slot.ts`(类型 + 适配器 + GET/PUT) | Phase 1 凭据槽位 API 客户端 | — | Pending | +| CRED-FE-01 API 客户端 `lib/api/credential-slot.ts`(类型 + 适配器 + GET/PUT) | Phase 1 凭据槽位 API 客户端 | — | ✅ Done (Plan 01-01, 2026-05-08, commits a0d0b9c + c072bbe) | | 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-04 编辑对话框 `CredentialSlotDialog.tsx`(RHF + Zod,留空保留旧值语义) | Phase 3 编辑对话框 + 提交反馈 | yes | Pending | @@ -146,3 +146,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])* diff --git a/qy-lty-admin/.planning/ROADMAP.md b/qy-lty-admin/.planning/ROADMAP.md index 3784b9c..0e0907c 100644 --- a/qy-lty-admin/.planning/ROADMAP.md +++ b/qy-lty-admin/.planning/ROADMAP.md @@ -34,7 +34,7 @@ 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**: 2 plans - - [ ] 01-01-PLAN.md — 新建 lib/api/credential-slot.ts(类型 + adapter + GET/PUT)+ lib/api/index.ts 末尾追加具名 re-export + - [x] 01-01-PLAN.md — 新建 lib/api/credential-slot.ts(类型 + adapter + GET/PUT)+ lib/api/index.ts 末尾追加具名 re-export - [ ] 01-02-PLAN.md — docs/修改记录.md 顶部追加 Phase 1 条目 + 跑双重验证(npm run lint + npx tsc --noEmit)+ 探针验证 barrel 入口 ### Phase 2: RBAC 收敛 + AI 模型页入口 @@ -69,7 +69,7 @@ Phase 按数值顺序执行:1 → 2 → 3(如出现紧急插入,记为 1.1 | Phase | Plans Complete | Status | Completed | |-------|----------------|--------|-----------| -| 1. 凭据槽位 API 客户端 | 0/2 | Not started | - | +| 1. 凭据槽位 API 客户端 | 1/2 | In Progress | - | | 2. RBAC 收敛 + AI 模型页入口 | 0/TBD | Not started | - | | 3. 编辑对话框 + 提交反馈 | 0/TBD | Not started | - | diff --git a/qy-lty-admin/.planning/STATE.md b/qy-lty-admin/.planning/STATE.md index 8eabd8e..8f16aa1 100644 --- a/qy-lty-admin/.planning/STATE.md +++ b/qy-lty-admin/.planning/STATE.md @@ -3,19 +3,19 @@ gsd_state_version: 1.0 milestone: v1.0 milestone_name: 通用凭据槽位前端集成 status: executing -last_updated: "2026-05-08T03:00:37.786Z" +last_updated: "2026-05-08T03:04:39.737Z" last_activity: 2026-05-08 progress: total_phases: 3 completed_phases: 0 total_plans: 2 - completed_plans: 0 - percent: 0 + completed_plans: 1 + percent: 50 --- # Project State — 洛天依应用管理后台(qy-lty-admin) -**最后更新**: 2026-05-07(Milestone v1.0 通用凭据槽位前端集成 ROADMAP 落地,Phase 1 待启动) +**最后更新**: 2026-05-08(Phase 1 Plan 01-01 已落地:lib/api/credential-slot.ts + index.ts re-export;CRED-FE-01 已交付) ## 项目引用 @@ -30,19 +30,19 @@ progress: ``` Milestone: v1.0 通用凭据槽位前端集成 Phase: Phase 1「凭据槽位 API 客户端」 -Plan: —(待 /gsd-plan-phase 1 生成) -Status: Ready to execute -Progress: [░░░░░░░░░░] 0%(0/3 phase 完成) +Plan: 01-01 完成 ✅ / 01-02 待执行 +Status: Phase 1 in progress (1/2 plans done) +Progress: [█████░░░░░] 50%(Phase 1 内部 1/2 plan 完成) Last activity: 2026-05-08 ``` -**下一步行动**:运行 `/gsd-plan-phase 1` 把 Phase 1 拆解为可执行的 plan 节点。 +**下一步行动**:执行 Plan 01-02(`docs/修改记录.md` 顶部追加 Phase 1 条目 + `npm run lint` + `npx tsc --noEmit` 双重验证 + barrel 入口探针)。 ## Phase 概览 | Phase | 标题 | 需求 | UI hint | 状态 | |-------|------|------|---------|------| -| 1 | 凭据槽位 API 客户端 | CRED-FE-01 | — | 待启动 | +| 1 | 凭据槽位 API 客户端 | CRED-FE-01 ✅ | — | 进行中(1/2 plan)| | 2 | RBAC 收敛 + AI 模型页入口 | CRED-FE-02, CRED-FE-03 | yes | 未开始 | | 3 | 编辑对话框 + 提交反馈 | CRED-FE-04, CRED-FE-05 | yes | 未开始 | @@ -58,10 +58,16 @@ Last activity: 2026-05-08 | 指标 | 数值 | |------|------| | 已完成 phase | 0 / 3 | -| 已完成 plan | 0 / TBD | -| Milestone 进度 | 0% | +| 已完成 plan | 1 / 2(Phase 1 内部)| +| Milestone 进度 | ~17%(1/6 plan 估算) | | 启动日期 | 2026-05-07 | -| 最近活动 | 2026-05-07 ROADMAP.md 落地 | +| 最近活动 | 2026-05-08 Plan 01-01 落地(commits a0d0b9c + c072bbe)| + +### Plan 执行记录 + +| Phase-Plan | 任务数 | 文件改动 | 耗时 | 完成日期 | +|------------|-------|---------|------|----------| +| 01-01 | 2 | 2 | ~76s | 2026-05-08 | ## 累积上下文 @@ -70,6 +76,7 @@ Last activity: 2026-05-08 - **2026-05-07 phase 拆分(Option B / 3 phase)**:API 客户端独立成 Phase 1(无 UI),权限矩阵 + 入口控件合并为 Phase 2(UI),编辑对话框 + 反馈合并为 Phase 3(UI)。理由:Phase 1 是纯逻辑、可在后端联调前独立打磨;Phase 2 一旦完成,未授权角色即彻底看不到入口(安全前置);Phase 3 集中处理"留空保留旧值"语义这条最容易翻车的业务规则。 - **2026-05-07 跨项目依赖明确**:前端 phase 不阻塞代码编写,但端到端验收依赖 qy_lty 后端 Phase 2(管理端读写接口)落地;本仓库 Phase 3 收尾节奏与后端 Phase 2 完工对齐。 - **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 路径。 ### 待办事项 @@ -97,9 +104,9 @@ Last activity: 2026-05-08 ## 会话连续性 -**最近会话**:2026-05-07 -**最近动作**:roadmapper 生成 ROADMAP.md(3 个 phase,Option B 拆分)+ 回填 REQUIREMENTS.md Traceability(5/5)+ 切换 STATE.md 到 Phase 1 待启动 -**下一会话起点**:`/gsd-plan-phase 1` 启动 Phase 1 规划 +**最近会话**:2026-05-08 +**最近动作**:执行 Plan 01-01(lib/api/credential-slot.ts 新建 + lib/api/index.ts 末尾 re-export),父仓库 commits a0d0b9c + c072bbe;CRED-FE-01 在 REQUIREMENTS.md 已勾选完成 +**下一会话起点**:执行 Plan 01-02(docs/修改记录.md 追加 Phase 1 条目 + `npm run lint` + `npx tsc --noEmit` 双重验证 + barrel 入口 import 探针) ## 工作流配置 @@ -132,3 +139,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 收尾* diff --git a/qy-lty-admin/.planning/phases/01-credential-slot-api/01-01-SUMMARY.md b/qy-lty-admin/.planning/phases/01-credential-slot-api/01-01-SUMMARY.md new file mode 100644 index 0000000..c518f39 --- /dev/null +++ b/qy-lty-admin/.planning/phases/01-credential-slot-api/01-01-SUMMARY.md @@ -0,0 +1,158 @@ +--- +phase: 01-credential-slot-api +plan: 01 +subsystem: api-client +tags: [api-client, credential-slot, milestone-v1.0, brownfield] +requires: [] +provides: + - artifact: lib/api/credential-slot.ts + description: 凭据槽位 API 客户端模块(类型 + adapter + GET/PUT 函数) + - export: getCredentialSlot + from: lib/api/credential-slot.ts + via: lib/api/index.ts (具名 re-export) + - export: updateCredentialSlot + from: lib/api/credential-slot.ts + via: lib/api/index.ts (具名 re-export) + - type: CredentialSlot + from: lib/api/credential-slot.ts + via: lib/api/index.ts (具名 re-export) + - type: CredentialSlotUpdatePayload + from: lib/api/credential-slot.ts + via: lib/api/index.ts (具名 re-export) +affects: + - lib/api/index.ts +tech_stack: + added: [] + patterns: + - "1:1 复刻 lib/api/ai-models.ts 风格(mapBackend* + 双保险解包 + export const fn = async)" + - "类型命名屏障:accessTokenMasked vs accessToken 在 TS 编译期切断脱敏字符串回写 bug" + - "barrel re-export:lib/api/index.ts 末尾具名 re-export,与现有 export * 风格混用合法" +key_files: + created: + - lib/api/credential-slot.ts + modified: + - lib/api/index.ts +decisions: + - 采用「具名 re-export」而非 `export *`:符合 RESEARCH 问题 6 + CONTEXT.md 锁定写法,可读性最高、未来重名冲突可控 + - PUT body 不带 `updated_at`:沿用 updateAiModel / updateOutfit 约定,由后端 auto_now 维护 + - `BackendCredentialSlot` 不导出:仅 adapter 入参类型,与 `mapBackend*` 模块级私有约定一致 + - 路径写 `/v1/admin/credential-slot/`(不带 `/api` 前缀):API_BASE_URL 已含 `/api` +metrics: + duration_seconds: 76 + completed_date: 2026-05-08 + tasks_completed: 2 + files_changed: 2 +requirements: + - CRED-FE-01 +--- + +# Phase 1 Plan 01-01:凭据槽位 API 客户端 Summary + +**One-liner**:1:1 复刻 ai-models.ts 风格落地 `lib/api/credential-slot.ts`,封装 GET/PUT + camelCase 类型 + adapter,并在 `lib/api/index.ts` 末尾具名 re-export 4 个公共符号。 + +## 背景 + +Milestone v1.0「通用凭据槽位前端集成」启动 plan,纯逻辑层(无 UI),为 Phase 2(RBAC + AI 模型页入口)/ Phase 3(编辑对话框 + Sonner 反馈)提供调用层基础。本 plan 同时建立类型层屏障:`CredentialSlot.accessTokenMasked`(脱敏)vs `CredentialSlotUpdatePayload.accessToken`(明文)字段名故意不同,让 TS 编译期切断「把脱敏掩码当真值回写 PUT」这条 bug 路径。 + +## Tasks Executed + +### Task 1:新建 lib/api/credential-slot.ts(类型 + adapter + GET/PUT) +- **状态**: ✅ 完成 +- **Commit**: `a0d0b9c`(父级 Lila-Server 仓库) +- **文件**: `lib/api/credential-slot.ts`(新增,64 行 / 2620 字节) +- **产物**: + - `interface BackendCredentialSlot`(snake_case,模块级私有不导出) + - `export interface CredentialSlot { appId, accessTokenMasked, updatedAt }`(公共响应类型) + - `export interface CredentialSlotUpdatePayload { appId, accessToken }`(公共提交载荷类型) + - `function mapBackendCredentialSlot(raw)`(模块级私有 adapter,snake → camel) + - `export const getCredentialSlot = async (): Promise` — 走 `apiClient.get('/v1/admin/credential-slot/')` + - `export const updateCredentialSlot = async (payload): Promise` — 走 `apiClient.put('/v1/admin/credential-slot/', { app_id, access_token })` +- **关键串命中**: + - `response.data?.data || response.data` 双保险解包:**2 次**(GET / PUT 各一) + - `apiClient.get('/v1/admin/credential-slot/')`:1 次 + - `apiClient.put('/v1/admin/credential-slot/'`:1 次 + - `/api/v1/admin/credential-slot`(重复 /api 前缀):**0 次** ✓(路径正确) + - PUT body 字面量不含 `updated_at` 键 ✓(仅注释行提及) +- **自动验证**: `node -e ...` 9 个 regex 检查 + 0 路径前缀检查 + 双保险解包计数 = 2 → 退出码 0,打印 `OK` + +### Task 2:lib/api/index.ts 末尾追加具名 re-export +- **状态**: ✅ 完成 +- **Commit**: `c072bbe`(父级 Lila-Server 仓库) +- **文件**: `lib/api/index.ts`(修改,197 → 204 行,+7 行内容;diff 显示 8 insertions 含末尾 newline 重排) +- **追加位置**: `handleApiError` 函数定义(L191-196)之后(L197 空行 + L198-204 新增块) +- **追加内容**(7 行): + ```typescript + + // 凭据槽位(Milestone v1.0 通用凭据槽位前端集成 — Phase 1 / CRED-FE-01) + export { + getCredentialSlot, + updateCredentialSlot, + type CredentialSlot, + type CredentialSlotUpdatePayload, + } from './credential-slot' + ``` +- **关键串命中**: + - `from './credential-slot'`:1 次 + - `getCredentialSlot,`:1 次 + - `updateCredentialSlot,`:1 次 + - `type CredentialSlot,`:1 次 + - `type CredentialSlotUpdatePayload,`:1 次 + - `export * from './credential-slot'`(错误的 barrel 风格):**0 次** ✓ +- **现有内容保留**: `import * as client from "./client"`、`export * from "./card"/"./upload"/"./food"`、`usersApi`、`rolesApi`、`handleApiError` 全部不变 +- **自动验证**: `node -e ...` 5 个 regex 计数检查 + barrel 风格反向检查 + card 导出保留检查 + handleApiError 保留检查 → 退出码 0,打印 `OK` + +## 累计 Commit 列表 + +| # | Hash | Message | Files | +|---|------|---------|-------| +| 1 | `a0d0b9c` | feat(01-01): 新建 lib/api/credential-slot.ts 凭据槽位 API 客户端 | qy-lty-admin/lib/api/credential-slot.ts | +| 2 | `c072bbe` | feat(01-01): lib/api/index.ts 末尾追加凭据槽位具名 re-export | qy-lty-admin/lib/api/index.ts | + +(最终 SUMMARY + STATE 提交另行追加,见底部) + +## Success Criteria 自检 + +- [x] `lib/api/credential-slot.ts` 文件存在 +- [x] 文件导出 `CredentialSlot` 类型 + `CredentialSlotUpdatePayload` 类型 + `getCredentialSlot` 函数 + `updateCredentialSlot` 函数共 4 个公共符号 +- [x] `mapBackendCredentialSlot` 函数已定义(私有,未导出) +- [x] GET / PUT 路径**精确**为 `/v1/admin/credential-slot/`(不含重复 `/api`) +- [x] GET 与 PUT 函数体内各含 1 次 `response.data?.data || response.data` 双保险解包(共 2 次) +- [x] PUT body 字面量**不含** `updated_at` +- [x] `lib/api/index.ts` 末尾通过具名 re-export 暴露 4 个符号,路径 `./credential-slot` +- [x] `lib/api/index.ts` 中现有 `export * from "./card"/"./upload"/"./food"` 与 `usersApi` / `rolesApi` / `handleApiError` 完全不变 +- [x] 两个文件均为合法 UTF-8(无 BOM 干扰、无残缺字符) + +## Deviations from Plan + +**无** — plan 执行 0 偏差。所有锁定写法(路径、解包行、PUT body 不含 updated_at、私有 adapter、具名 re-export 风格、追加位置)均严格按 PLAN action 落地。 + +## 与后续 plan 的衔接 + +- **Plan 01-02**(同一 phase)将处理:`docs/修改记录.md` 顶部追加 Phase 1 条目 + 跑双重验证(`npm run lint` + `npx tsc --noEmit`)+ 探针验证 barrel 入口 +- **Phase 2** 起可用 `import { getCredentialSlot, updateCredentialSlot, type CredentialSlot, type CredentialSlotUpdatePayload } from '@/lib/api'` 直接消费本 plan 产物 +- **本 plan 不写 `docs/修改记录.md`** — 集中由 Plan 01-02 落地,避免 Phase 1 内部多次写入 + +## Known Stubs + +无 — 本 plan 是纯 API 客户端层,所有产物(类型、adapter、API 函数)都已完整实现并可直接消费。无任何占位或 TODO。 + +## 字节级关键产物对比 + +| 文件 | 状态 | 行数(前→后) | 字节 | +|------|------|--------------|------| +| `lib/api/credential-slot.ts` | 新增 | 0 → 64 | 2620 | +| `lib/api/index.ts` | 修改 | 197 → 204 | (追加 7 行) | + +## Self-Check: PASSED + +- [x] `lib/api/credential-slot.ts` 存在 (FOUND) +- [x] `lib/api/index.ts` 末尾包含具名 re-export 块 (FOUND) +- [x] commit `a0d0b9c` 在 git log 中 (FOUND, 父级 Lila-Server 仓库) +- [x] commit `c072bbe` 在 git log 中 (FOUND, 父级 Lila-Server 仓库) +- [x] Task 1 / Task 2 verify.automated 命令均退出码 0 + 打印 `OK` + +--- + +*生成时间:2026-05-08* +*执行 Agent:gsd-executor (Opus 4.7)* +*父仓库 commit hash:a0d0b9c (Task 1) / c072bbe (Task 2)*