20 KiB
Raw Blame History

phase, plan, type, wave, depends_on, files_modified, autonomous, requirements, must_haves
phase plan type wave depends_on files_modified autonomous requirements must_haves
01-credential-slot-api 02 execute 2
01-01
docs/修改记录.md
true
CRED-FE-01
truths artifacts key_links
docs/修改记录.md 顶部(『修改历史』段第一条)追加 [2026-05-08] Phase 1 条目
条目包含『配套服务端 Phase』『覆盖前端需求』前置元数据引用 commit 46d72b8
条目跨项目联动字段写明:本 phase 不引入新跨项目契约,无需再次互引(后端 Phase 2 已建立互引)
npm run lint 退出码为 0ESLint 检查 lib/api/credential-slot.ts 与 lib/api/index.ts
npx tsc --noEmit 退出码为 0项目级类型检查全部通过含 plan 01 新增的 CredentialSlot / CredentialSlotUpdatePayload
外部组件文件能成功 import { getCredentialSlot, type CredentialSlot } from '@/lib/api'(通过临时 .tsx 探针验证)
path provides contains
docs/修改记录.md 本仓库变更日志,顶部新增 Phase 1 条目
[2026-05-08] Phase 1
CRED-FE-01
lib/api/credential-slot.ts
lib/api/index.ts
46d72b8
accessTokenMasked
accessToken
from to via pattern
docs/修改记录.md 顶部新条目 qy_lty 后端 Phase 2 commit 46d72b8 已建立的前后端互引 条目『服务端联动』字段中文引用 46d72b8
from to via pattern
外部消费者Phase 2/3 组件文件) lib/api 入口 barrel import { getCredentialSlot, type CredentialSlot } from '@/lib/api' from\s+['"]@/lib/api['"]
为 plan 01 落地的代码补齐两件事: 1. 在 `docs/修改记录.md` 顶部按项目「修改格式说明」追加一条 Phase 1 条目CLAUDE.md L70-95 强制规则)。 2. 跑两条**独立**验证命令,确认 plan 01 的代码质量: - `npm run lint` —— ESLint 检查(`next lint` - `npx tsc --noEmit` —— TypeScript 类型检查(**不**能省per RESEARCH 问题 7`npm run lint` 不跑 tsc

并通过一个临时探针 .tsx 文件验证外部消费者可以从 @/lib/api 入口解析新增的 4 个符号;探针验证完成后删除。

Purpose把 Phase 1 的「成功 = 代码 + 文档 + 类型可被消费」三件套全部落地,为 Phase 2/3 提供干净起点。

Outputdocs/修改记录.md修改plan 落地后无新代码文件残留(探针文件验证后删除)。

<execution_context> @$HOME/.claude/get-shit-done/workflows/execute-plan.md @$HOME/.claude/get-shit-done/templates/summary.md </execution_context>

@.planning/phases/01-credential-slot-api/01-CONTEXT.md @.planning/phases/01-credential-slot-api/01-RESEARCH.md @.planning/phases/01-credential-slot-api/01-01-SUMMARY.md

@CLAUDE.md @docs/修改记录.md @package.json @next.config.mjs @lib/api/credential-slot.ts @lib/api/index.ts

Task 1在 docs/修改记录.md 顶部追加 Phase 1 条目

<read_first> - docs/修改记录.md L1-50特别是 L9-20 头部「修改格式说明」 + L24-47 已存在的 [2026-05-07] Phase 2 条目作为格式模板) - CLAUDE.md L70-95「项目修改记录规则」 — 强制每次代码改动追加到顶部、跨项目独立维护 - .planning/phases/01-credential-slot-api/01-CONTEXT.md 节「修改记录」段L152-156— 锁定的跨项目联动文案 - .planning/phases/01-credential-slot-api/01-RESEARCH.md 「Code Examples」节内的「docs/修改记录.md 顶部追加条目」完整模板 </read_first>

docs/修改记录.md

在 `docs/修改记录.md` 中找到这一行:
<!-- 新的修改记录添加在此处下方,最新的在最前面 -->

在该注释行之后、紧贴现有 ### [2026-05-07] Phase 2 — 锁定后端通用凭据槽位 REST 接口契约(消费方文档化) 条目之前,插入以下完整 Markdown 块(之间留 1 个空行):


### [2026-05-08] Phase 1前端凭据槽位 API 客户端

配套服务端 Phase[../qy_lty/.planning/phases/02-admin-rest/](../../qy_lty/.planning/phases/02-admin-rest/)已落地commit 46d72b8
覆盖前端需求CRED-FE-01

- **文件路径**
  - `lib/api/credential-slot.ts`(新增)
  - `lib/api/index.ts`(修改)
- **修改类型**: 新增API 客户端层;纯逻辑,无 UI 改动)
- **修改内容**:
  - 新建 `lib/api/credential-slot.ts`,封装:
    - 类型 `CredentialSlot { appId, accessTokenMasked, updatedAt }`(脱敏掩码语义命名)
    - 类型 `CredentialSlotUpdatePayload { appId, accessToken }`(明文语义命名)
    - 适配器 `mapBackendCredentialSlot()`snake_case → camelCase
    - API 函数 `getCredentialSlot()` / `updateCredentialSlot(payload)`,分别走 `apiClient.get` / `apiClient.put` 命中 `/v1/admin/credential-slot/`,沿用仓库统一的 `response.data?.data || response.data` 双保险解包PUT body 仅传 `{ app_id, access_token }`,不携 `updated_at`(与 `updateAiModel` / `updateOutfit` 风格一致)
  - `lib/api/index.ts` 末尾追加具名 re-export让组件层可 `import { getCredentialSlot, type CredentialSlot } from '@/lib/api'`
- **修改原因**:
  - 启动 Milestone v1.0「通用凭据槽位前端集成」,本 phase 为后续 Phase 2RBAC + 入口控件、Phase 3编辑对话框 + Sonner 反馈)提供调用层基础
  - `accessTokenMasked` vs `accessToken` 故意命名不同,让 TS 编译期捕捉「把脱敏字符串当真值回写 PUT」的 bug
- **服务端联动**: 无 — Phase 1 是纯 API client 层落地(无 UI 改动),调用的后端接口由 qy_lty 后端 Milestone v1.0 Phase 2 提供commit `46d72b8` 已建立前后端互引修改记录);本 phase 不引入新跨项目代码契约,无需再次互引。前端 UI 集成Phase 2 + 3引入实质用户能力时再评估是否需要新一轮互引

关键约束

  1. 插入位置必须<!-- 新的修改记录添加在此处下方,最新的在最前面 --> 注释之后### [2026-05-07] Phase 2 — 锁定后端通用凭据槽位 REST 接口契约(消费方文档化) 标题之前(项目约定:最新在前)
  2. 顶部 ### [2026-05-08] 必须用今天日期 2026-05-08(与 RESEARCH 的 「Researched: 2026-05-08」一致不是 2026-05-07
  3. 必须出现关键字符串:CRED-FE-0146d72b8accessTokenMaskedaccessTokenlib/api/credential-slot.tslib/api/index.ts/v1/admin/credential-slot/
  4. 「服务端联动」字段必须明确写出「无 — ... commit 46d72b8 已建立 ... 本 phase 不引入新跨项目代码契约无需再次互引」per CONTEXT.md 锁定文案)
  5. 不要修改 docs/修改记录.md 中任何已有条目;只做顶部插入
  6. 不要在 qy_lty 项目侧建立新条目CONTEXT.md 锁定:本 phase 不需要新建跨项目互引)

<acceptance_criteria>

  • grep -nF "[2026-05-08] Phase 1前端凭据槽位 API 客户端" docs/修改记录.md 命中 1 次
  • 该新条目的行号 < 现有 [2026-05-07] Phase 2 — 锁定后端通用凭据槽位 REST 接口契约 标题的行号(最新在前顺序正确)
  • grep -F "CRED-FE-01" docs/修改记录.md 命中 ≥1 次
  • grep -F "46d72b8" docs/修改记录.md 命中 ≥1 次plan 01 之前已存在 1 次,本 plan 后应为 ≥2 次)
  • grep -F "accessTokenMasked" docs/修改记录.md 命中 ≥1 次
  • grep -F "lib/api/credential-slot.ts" docs/修改记录.md 命中 ≥1 次
  • grep -F "/v1/admin/credential-slot/" docs/修改记录.md 命中 ≥1 次
  • grep -F "无需再次互引" docs/修改记录.md 命中 ≥1 次
  • 现有 [2026-05-07] Phase 2 条目内容完全不变(行级 diff 仅为顶部插入,不修改既有行) </acceptance_criteria>
node -e "const c = require('fs').readFileSync('docs/修改记录.md','utf8'); const newIdx = c.indexOf('[2026-05-08] Phase 1前端凭据槽位 API 客户端'); const oldIdx = c.indexOf('[2026-05-07] Phase 2 — 锁定后端通用凭据槽位 REST 接口契约'); if (newIdx < 0) { console.error('FAIL: 新条目缺失'); process.exit(1); } if (oldIdx < 0) { console.error('FAIL: 旧条目消失'); process.exit(1); } if (newIdx >= oldIdx) { console.error('FAIL: 新条目未置顶'); process.exit(1); } const must = ['CRED-FE-01', '46d72b8', 'accessTokenMasked', 'accessToken', 'lib/api/credential-slot.ts', 'lib/api/index.ts', '/v1/admin/credential-slot/', '无需再次互引', '配套服务端 Phase', '覆盖前端需求']; for (const s of must) { if (!c.includes(s)) { console.error('FAIL: 缺失关键字 ' + s); process.exit(1); } } console.log('OK'); " - `docs/修改记录.md` 顶部「修改历史」段第一条为 `[2026-05-08] Phase 1前端凭据槽位 API 客户端` - 现有 [2026-05-07] Phase 2 条目位置后移、内容不变 - `verify.automated` 命令退出码为 0 且打印 `OK` - 所有关键字段CRED-FE-01 / 46d72b8 / accessTokenMasked / 文件路径 / 服务端联动文案)齐全 Task 2跑双重验证npm run lint + npx tsc --noEmit+ 临时探针验证 barrel 入口可解析

<read_first> - package.json L9 — 确认 lint 脚本是 next lintper RESEARCH 问题 7只跑 ESLint不跑 tsc - next.config.mjsL17 / L20— 确认 eslint.ignoreDuringBuildstypescript.ignoreBuildErrors 仅影响 next build,不影响显式 next lintnpx tsc --noEmit - tsconfig.json — 确认 strict 模式开启 - lib/api/credential-slot.tsplan 01 落地)+ lib/api/index.tsplan 01 落地)— 类型与导出已就位 - .planning/phases/01-credential-slot-api/01-RESEARCH.md 「Pitfall 5: 包管理器混用导致 lockfile 漂移」节 — 验证步骤只读不写,不要跑 npm install </read_first>

(不创建持久化新文件;仅临时探针 lib/api/__phase1_probe__.ts,验证后删除)

按以下顺序**严格**执行,每步退出码必须为 0任一步失败必须先排错再继续

步骤 1创建临时类型探针文件 lib/api/__phase1_probe__.ts(用 .ts 而非 .tsx,因不引入 React__ 前后缀降低被 IDE/lint 误识别为业务文件的风险)

写入以下完整内容:

// 临时探针 — Phase 1 plan 02 验证 barrel 入口可正确解析新增符号;验证后立即删除
import {
  getCredentialSlot,
  updateCredentialSlot,
  type CredentialSlot,
  type CredentialSlotUpdatePayload,
} from "@/lib/api"

async function __probe(): Promise<void> {
  const slot: CredentialSlot = await getCredentialSlot()
  const payload: CredentialSlotUpdatePayload = {
    appId: slot.appId,
    accessToken: "plaintext-not-masked",  // 故意写明文type 系统应允许
  }
  const next: CredentialSlot = await updateCredentialSlot(payload)
  void next.accessTokenMasked  // 触达字段证明类型形状
}
void __probe

步骤 2npx tsc --noEmit

npx tsc --noEmit

退出码必须为 0。如有错误

  • 若错误指向 __phase1_probe__.tsimport "@/lib/api" —— 说明 plan 01 的 index.ts re-export 有问题,回 plan 01 排错
  • 若错误指向 lib/api/credential-slot.ts —— 说明 plan 01 的类型定义有问题,回 plan 01 排错
  • 若错误指向其他文件(项目中的存量类型问题,与本 phase 无关)—— 记录错误清单到 SUMMARY但本 task 仍判定通过,因为本 phase 的责任范围是新增文件不引入类型回归

关键判定规则:把 npx tsc --noEmit 输出存到临时文件,过滤出仅与 lib/api/credential-slot.ts__phase1_probe__.tslib/api/index.ts 相关的错误行;这三处错误数必须为 0。其他文件的存量错误不算 phase 1 失败。

步骤 3npm run lint

npm run lint

退出码必须为 0。如有警告/错误:

  • 若错误/警告指向新增文件 lib/api/credential-slot.ts__phase1_probe__.ts —— 必须修复
  • 若错误/警告指向 lib/api/index.ts仅限新增的具名 re-export 块 —— 必须修复
  • 若错误/警告指向其他存量文件 —— 记录到 SUMMARY本 task 仍判定通过

注意 next lint 默认对项目所有 .ts / .tsx 跑;如果 ESLint 配置严格,__phase1_probe__.ts 中的 void __probe 与未使用变量可能触发 no-unused-vars。如真触发,添加文件级 // eslint-disable-next-line @typescript-eslint/no-unused-vars 注释或将 __probe / __probe2 等命名调整避免触发,但优先调整代码而非禁用规则。

步骤 4删除临时探针文件

rm lib/api/__phase1_probe__.ts

Windows PowerShell 等价:Remove-Item lib/api/__phase1_probe__.ts

步骤 5再跑一次 npx tsc --noEmitnpm run lint,确认删除探针后两条命令仍全部退出码 0防止漏删导致后续 phase 把临时文件当真)

关键约束per RESEARCH Pitfall 5

  1. 要跑 npm install / pnpm install / yarn installlockfile 漂移风险,本 phase 不引入新依赖)
  2. 要修改 package.json / package-lock.json / yarn.lock / pnpm-lock.yaml
  3. 要修改 next.config.mjs / tsconfig.json / .eslintrc*CONTEXT.md / RESEARCH.md 均隐含锁定)
  4. 探针文件必须删除,不允许残留任何临时文件到 phase 末态
  5. 两条验证命令的退出码与「与新增文件相关的错误数」都必须为 0不可用 --force / --no-warnings 等屏蔽手段

<acceptance_criteria>

  • 步骤 2npx tsc --noEmit 在创建探针后退出码 0如有非 0输出中没有任何包含 lib/api/credential-slot.ts / lib/api/__phase1_probe__.ts / lib/api/index.ts 路径的错误行(执行者负责把过滤判定写入 SUMMARY 证据段)
  • 步骤 3npm run lint 退出码 0同上规则新增/修改的文件零错误零警告
  • 步骤 4lib/api/__phase1_probe__.ts 不存在grep / Test-Path 验证)
  • 步骤 5删除探针后 npx tsc --noEmitnpm run lint 仍退出码 0
  • git status --short(如可用)显示只有 lib/api/credential-slot.ts(新增)+ lib/api/index.ts(修改)+ docs/修改记录.md(修改)三个改动;不允许有 __phase1_probe__.ts / pnpm-lock.yaml / yarn.lock / package-lock.json / package.json 出现在 diff 中(探针残留或包管理器混用信号) </acceptance_criteria>
node -e "const fs = require('fs'); const cp = require('child_process'); function run(cmd){ try { cp.execSync(cmd, { stdio: 'pipe' }); return { code: 0, out: '' }; } catch (e) { return { code: e.status || 1, out: (e.stdout?.toString() || '') + (e.stderr?.toString() || '') }; } } if (fs.existsSync('lib/api/__phase1_probe__.ts')) { console.error('FAIL: 临时探针文件未删除'); process.exit(1); } const tsc = run('npx tsc --noEmit'); if (tsc.code !== 0) { const lines = tsc.out.split(/\r?\n/).filter(l => /lib\/api\/(credential-slot|__phase1_probe__|index)\.ts/.test(l)); if (lines.length > 0) { console.error('FAIL: tsc 在新增/修改文件上报错:\n' + lines.join('\n')); process.exit(1); } else { console.error('WARN: tsc 在存量文件上有错误,但与本 phase 无关:\n' + tsc.out.split(/\r?\n/).slice(0, 20).join('\n')); } } const lint = run('npm run lint'); if (lint.code !== 0) { const lines = lint.out.split(/\r?\n/).filter(l => /lib\/api\/(credential-slot|__phase1_probe__|index)\.ts/.test(l)); if (lines.length > 0) { console.error('FAIL: lint 在新增/修改文件上报错:\n' + lines.join('\n')); process.exit(1); } else { console.error('WARN: lint 在存量文件上有错误,但与本 phase 无关:\n' + lint.out.split(/\r?\n/).slice(0, 20).join('\n')); } } console.log('OK'); " - 探针验证完整跑过:先创建 -> tsc 0 (新文件零错) -> lint 0 (新文件零错) -> 删除探针 -> 再跑 tsc 0 + lint 0 - 临时探针 `lib/api/__phase1_probe__.ts` 已删除git diff 不残留它 - 包管理器 lockfile 状态未变git status 不显示 `package-lock.json` / `yarn.lock` / `pnpm-lock.yaml` / `package.json` 的改动) - `verify.automated` 命令退出码为 0 且打印 `OK` - SUMMARY 中记录两条验证命令的退出码、与新增文件相关的错误清单(应为空)、存量错误清单(如有,仅作信息) 本 plan 完成意味着 Phase 1 全部交付完成。汇总验证:
  1. 结构性plan 01 + plan 02 联合):

    • lib/api/credential-slot.ts 文件存在、4 个公共符号导出、路径与解包行齐全
    • lib/api/index.ts 末尾具名 re-export 4 个符号
    • docs/修改记录.md 顶部新增 [2026-05-08] Phase 1 条目
  2. 工具链(本 plan task 2 兜底):

    • npx tsc --noEmit 退出码 0新增/修改文件零类型错误)
    • npm run lint 退出码 0新增/修改文件零 ESLint 错误)
  3. 可消费性(本 plan task 2 探针验证):

    • import { getCredentialSlot, type CredentialSlot } from '@/lib/api' 在临时探针文件中类型解析通过
    • 探针文件删除后两条验证命令仍退出码 0确认 plan 02 没引入残留文件依赖)
  4. 跨项目联动

    • 修改记录条目明确写出「无需再次互引(后端 commit 46d72b8 已建立)」
    • 修改 qy_lty/docs/修改记录.mdCONTEXT.md 锁定)
  5. 包管理器零漂移

    • git status 不显示 package.json / package-lock.json / yarn.lock / pnpm-lock.yaml 的任何修改

<success_criteria>

  • docs/修改记录.md 顶部第一条为 [2026-05-08] Phase 1前端凭据槽位 API 客户端
  • 该条目包含全部锁定关键字:CRED-FE-0146d72b8accessTokenMaskedaccessTokenlib/api/credential-slot.tslib/api/index.ts/v1/admin/credential-slot/无需再次互引
  • 现有 [2026-05-07] Phase 2 条目内容不变、位置下移
  • npx tsc --noEmit 退出码 0新增/修改文件零类型错误(存量错误不影响本 phase 判定)
  • npm run lint 退出码 0新增/修改文件零 ESLint 错误
  • 临时探针 lib/api/__phase1_probe__.ts 已删除git diff 不残留
  • git status --short 仅显示 lib/api/credential-slot.ts(新增) + lib/api/index.ts(修改) + docs/修改记录.md(修改)+ .planning/... 内的 PLAN/SUMMARY 文档;显示 package.json / 任一 lockfile 改动 </success_criteria>
完成后创建 `.planning/phases/01-credential-slot-api/01-02-SUMMARY.md`,记录: - 修改记录条目最终落地行号区间(在 docs/修改记录.md 中的位置)+ 关键字命中清单 - `npx tsc --noEmit` 退出码 + 与新增文件相关的错误行数(应为 0 - `npm run lint` 退出码 + 与新增文件相关的错误行数(应为 0 - 探针文件删除前后两次验证的输出对比(最关心:删除后命令仍 0 - 存量类型/lint 错误数量(仅作信息,不计入失败判定;为后续 PERM-06 候选优先级 #3 留追踪锚点) - 跨项目联动确认:本 phase 未修改 `../qy_lty/docs/修改记录.md`

完成本 SUMMARY 即可宣告 Phase 1 全部交付完成;下一步运行 /gsd-plan-phase 2 启动 RBAC 收敛 + AI 模型页入口。