From b7e4fa58858eec5577f352a980fb072ee33b8eb7 Mon Sep 17 00:00:00 2001 From: zichun Date: Thu, 28 May 2026 13:51:55 +0800 Subject: [PATCH] refactor: group skills by phase — skills/plan/ + skills/coding/ --- .claude-plugin/plugin.json | 12 +++++++++++- README.md | 26 ++++++++++++++------------ skills/coding-start/SKILL.md | 125 ----------------------------------------------------------------------------------------------------------------------------- skills/coding/coding-start/SKILL.md | 125 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ skills/db-design-gen/SKILL.md | 121 ------------------------------------------------------------------------------------------------------------------------- skills/db-design-gen/templates/docs-03-header-template.md | 24 ------------------------ skills/db-design-gen/templates/docs-03-table-template.md | 25 ------------------------- skills/db-init/SKILL.md | 141 --------------------------------------------------------------------------------------------------------------------------------------------- skills/downstream-gen/SKILL.md | 146 -------------------------------------------------------------------------------------------------------------------------------------------------- skills/downstream-gen/templates/docs-02-template.md | 26 -------------------------- skills/downstream-gen/templates/docs-05-endpoint-template.md | 12 ------------ skills/downstream-gen/templates/docs-05-header-template.md | 30 ------------------------------ skills/downstream-gen/templates/docs-06-module-pagelist-template.md | 9 --------- skills/downstream-gen/templates/docs-08-module-row-template.md | 6 ------ skills/downstream-gen/templates/docs-10-header-template.md | 16 ---------------- skills/frontend-scope-lock/SKILL.md | 130 ---------------------------------------------------------------------------------------------------------------------------------- skills/frontend-scope-lock/templates/fe-scope-template.md | 65 ----------------------------------------------------------------- skills/plan-start/SKILL.md | 145 ------------------------------------------------------------------------------------------------------------------------------------------------- skills/plan/db-design-gen/SKILL.md | 121 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ skills/plan/db-design-gen/templates/docs-03-header-template.md | 24 ++++++++++++++++++++++++ skills/plan/db-design-gen/templates/docs-03-table-template.md | 25 +++++++++++++++++++++++++ skills/plan/db-init/SKILL.md | 141 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ skills/plan/downstream-gen/SKILL.md | 146 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ skills/plan/downstream-gen/templates/docs-02-template.md | 26 ++++++++++++++++++++++++++ skills/plan/downstream-gen/templates/docs-05-endpoint-template.md | 12 ++++++++++++ skills/plan/downstream-gen/templates/docs-05-header-template.md | 30 ++++++++++++++++++++++++++++++ skills/plan/downstream-gen/templates/docs-06-module-pagelist-template.md | 9 +++++++++ skills/plan/downstream-gen/templates/docs-08-module-row-template.md | 6 ++++++ skills/plan/downstream-gen/templates/docs-10-header-template.md | 16 ++++++++++++++++ skills/plan/frontend-scope-lock/SKILL.md | 130 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ skills/plan/frontend-scope-lock/templates/fe-scope-template.md | 65 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ skills/plan/plan-start/SKILL.md | 145 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ skills/plan/project-init/SKILL.md | 110 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ skills/plan/project-init/templates/CLAUDE-template.md | 255 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ skills/plan/project-init/templates/docs-01-index-template.md | 16 ++++++++++++++++ skills/plan/project-init/templates/docs-04-stack-template.md | 32 ++++++++++++++++++++++++++++++++ skills/plan/project-init/templates/docs-08-initial-template.md | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ skills/plan/scope-lock/SKILL.md | 231 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ skills/plan/scope-lock/templates/_module-template.md | 5 +++++ skills/plan/scope-lock/templates/config-vars-template.yaml | 30 ++++++++++++++++++++++++++++++ skills/plan/scope-lock/templates/req-card-template.md | 44 ++++++++++++++++++++++++++++++++++++++++++++ skills/plan/skeleton-gen/SKILL.md | 160 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ skills/plan/skeleton-gen/templates/docs-04-skeleton-template.md | 69 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ skills/plan/skeleton-gen/templates/docs-06-static-template.md | 42 ++++++++++++++++++++++++++++++++++++++++++ skills/plan/skeleton-gen/templates/docs-07-env-template.md | 34 ++++++++++++++++++++++++++++++++++ skills/plan/skeleton-gen/templates/docs-09-structure-template.md | 45 +++++++++++++++++++++++++++++++++++++++++++++ skills/plan/skeleton-gen/templates/env-local-template | 25 +++++++++++++++++++++++++ skills/plan/skeleton-gen/templates/gitignore-append-template | 32 ++++++++++++++++++++++++++++++++ skills/plan/skeleton-gen/templates/scripts-setup-test-db-template.mjs | 126 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ skills/plan/skeleton-gen/templates/scripts-test-template.mjs | 69 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ skills/plan/skeleton-gen/templates/styles-tokens-template.css | 43 +++++++++++++++++++++++++++++++++++++++++++ skills/project-init/SKILL.md | 110 -------------------------------------------------------------------------------------------------------------- skills/project-init/templates/CLAUDE-template.md | 255 --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- skills/project-init/templates/docs-01-index-template.md | 16 ---------------- skills/project-init/templates/docs-04-stack-template.md | 32 -------------------------------- skills/project-init/templates/docs-08-initial-template.md | 76 ---------------------------------------------------------------------------- skills/scope-lock/SKILL.md | 231 --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- skills/scope-lock/templates/_module-template.md | 5 ----- skills/scope-lock/templates/config-vars-template.yaml | 30 ------------------------------ skills/scope-lock/templates/req-card-template.md | 44 -------------------------------------------- skills/skeleton-gen/SKILL.md | 160 ---------------------------------------------------------------------------------------------------------------------------------------------------------------- skills/skeleton-gen/templates/docs-04-skeleton-template.md | 69 --------------------------------------------------------------------- skills/skeleton-gen/templates/docs-06-static-template.md | 42 ------------------------------------------ skills/skeleton-gen/templates/docs-07-env-template.md | 34 ---------------------------------- skills/skeleton-gen/templates/docs-09-structure-template.md | 45 --------------------------------------------- skills/skeleton-gen/templates/env-local-template | 25 ------------------------- skills/skeleton-gen/templates/gitignore-append-template | 32 -------------------------------- skills/skeleton-gen/templates/scripts-setup-test-db-template.mjs | 126 ------------------------------------------------------------------------------------------------------------------------------ skills/skeleton-gen/templates/scripts-test-template.mjs | 69 --------------------------------------------------------------------- skills/skeleton-gen/templates/styles-tokens-template.css | 43 ------------------------------------------- 70 files changed, 2490 insertions(+), 2478 deletions(-) delete mode 100644 skills/coding-start/SKILL.md create mode 100644 skills/coding/coding-start/SKILL.md delete mode 100644 skills/db-design-gen/SKILL.md delete mode 100644 skills/db-design-gen/templates/docs-03-header-template.md delete mode 100644 skills/db-design-gen/templates/docs-03-table-template.md delete mode 100644 skills/db-init/SKILL.md delete mode 100644 skills/downstream-gen/SKILL.md delete mode 100644 skills/downstream-gen/templates/docs-02-template.md delete mode 100644 skills/downstream-gen/templates/docs-05-endpoint-template.md delete mode 100644 skills/downstream-gen/templates/docs-05-header-template.md delete mode 100644 skills/downstream-gen/templates/docs-06-module-pagelist-template.md delete mode 100644 skills/downstream-gen/templates/docs-08-module-row-template.md delete mode 100644 skills/downstream-gen/templates/docs-10-header-template.md delete mode 100644 skills/frontend-scope-lock/SKILL.md delete mode 100644 skills/frontend-scope-lock/templates/fe-scope-template.md delete mode 100644 skills/plan-start/SKILL.md create mode 100644 skills/plan/db-design-gen/SKILL.md create mode 100644 skills/plan/db-design-gen/templates/docs-03-header-template.md create mode 100644 skills/plan/db-design-gen/templates/docs-03-table-template.md create mode 100644 skills/plan/db-init/SKILL.md create mode 100644 skills/plan/downstream-gen/SKILL.md create mode 100644 skills/plan/downstream-gen/templates/docs-02-template.md create mode 100644 skills/plan/downstream-gen/templates/docs-05-endpoint-template.md create mode 100644 skills/plan/downstream-gen/templates/docs-05-header-template.md create mode 100644 skills/plan/downstream-gen/templates/docs-06-module-pagelist-template.md create mode 100644 skills/plan/downstream-gen/templates/docs-08-module-row-template.md create mode 100644 skills/plan/downstream-gen/templates/docs-10-header-template.md create mode 100644 skills/plan/frontend-scope-lock/SKILL.md create mode 100644 skills/plan/frontend-scope-lock/templates/fe-scope-template.md create mode 100644 skills/plan/plan-start/SKILL.md create mode 100644 skills/plan/project-init/SKILL.md create mode 100644 skills/plan/project-init/templates/CLAUDE-template.md create mode 100644 skills/plan/project-init/templates/docs-01-index-template.md create mode 100644 skills/plan/project-init/templates/docs-04-stack-template.md create mode 100644 skills/plan/project-init/templates/docs-08-initial-template.md create mode 100644 skills/plan/scope-lock/SKILL.md create mode 100644 skills/plan/scope-lock/templates/_module-template.md create mode 100644 skills/plan/scope-lock/templates/config-vars-template.yaml create mode 100644 skills/plan/scope-lock/templates/req-card-template.md create mode 100644 skills/plan/skeleton-gen/SKILL.md create mode 100644 skills/plan/skeleton-gen/templates/docs-04-skeleton-template.md create mode 100644 skills/plan/skeleton-gen/templates/docs-06-static-template.md create mode 100644 skills/plan/skeleton-gen/templates/docs-07-env-template.md create mode 100644 skills/plan/skeleton-gen/templates/docs-09-structure-template.md create mode 100644 skills/plan/skeleton-gen/templates/env-local-template create mode 100644 skills/plan/skeleton-gen/templates/gitignore-append-template create mode 100644 skills/plan/skeleton-gen/templates/scripts-setup-test-db-template.mjs create mode 100644 skills/plan/skeleton-gen/templates/scripts-test-template.mjs create mode 100644 skills/plan/skeleton-gen/templates/styles-tokens-template.css delete mode 100644 skills/project-init/SKILL.md delete mode 100644 skills/project-init/templates/CLAUDE-template.md delete mode 100644 skills/project-init/templates/docs-01-index-template.md delete mode 100644 skills/project-init/templates/docs-04-stack-template.md delete mode 100644 skills/project-init/templates/docs-08-initial-template.md delete mode 100644 skills/scope-lock/SKILL.md delete mode 100644 skills/scope-lock/templates/_module-template.md delete mode 100644 skills/scope-lock/templates/config-vars-template.yaml delete mode 100644 skills/scope-lock/templates/req-card-template.md delete mode 100644 skills/skeleton-gen/SKILL.md delete mode 100644 skills/skeleton-gen/templates/docs-04-skeleton-template.md delete mode 100644 skills/skeleton-gen/templates/docs-06-static-template.md delete mode 100644 skills/skeleton-gen/templates/docs-07-env-template.md delete mode 100644 skills/skeleton-gen/templates/docs-09-structure-template.md delete mode 100644 skills/skeleton-gen/templates/env-local-template delete mode 100644 skills/skeleton-gen/templates/gitignore-append-template delete mode 100644 skills/skeleton-gen/templates/scripts-setup-test-db-template.mjs delete mode 100644 skills/skeleton-gen/templates/scripts-test-template.mjs delete mode 100644 skills/skeleton-gen/templates/styles-tokens-template.css diff --git a/.claude-plugin/plugin.json b/.claude-plugin/plugin.json index ff22faa..90a639f 100644 --- a/.claude-plugin/plugin.json +++ b/.claude-plugin/plugin.json @@ -2,5 +2,15 @@ "name": "erp-workflow", "description": "ERP 项目全流程框架:阶段 A 计划(plan-start 入口 + A0~A6 共 7 个 skill + B 阶段瘦入口 coding-start = 9 个 skill;plan-start 终结闸 5 项前移硬校验) + 阶段 B 编码(单个静默 Workflow 脚本 coding.mjs,子代理自动跑后端+前端功能循环、测试闸门、本地里程碑 tag)。", "version": "0.2.0", - "skills": ["./skills"] + "skills": [ + "./skills/plan/plan-start", + "./skills/plan/project-init", + "./skills/plan/scope-lock", + "./skills/plan/skeleton-gen", + "./skills/plan/db-design-gen", + "./skills/plan/db-init", + "./skills/plan/downstream-gen", + "./skills/plan/frontend-scope-lock", + "./skills/coding/coding-start" + ] } diff --git a/README.md b/README.md index d934e9a..0c9142f 100644 --- a/README.md +++ b/README.md @@ -95,7 +95,7 @@ Claude Code 插件:ERP / 后端管理系统全流程开发框架。 ``` erp-workflow-plugin/ ├── .claude-plugin/ -│ └── plugin.json # 插件清单,声明 ./skills(9 skill) +│ └── plugin.json # 插件清单,显式列出 9 个 skill 路径 ├── README.md # 本文档 ├── workflows/ │ └── coding.mjs # 阶段 B:整个编码阶段编排为单个静默 Workflow @@ -107,23 +107,25 @@ erp-workflow-plugin/ │ └── *.test.mjs # 各助手的 node:test 单测 ├── agents/ │ └── code-reviewer.md # 统一 reviewer(coding.mjs review stage 调用,phase 选维度集) -└── skills/ # 阶段 A:9 个 skill(扁平,无中间层) - ├── plan-start/ # A 阶段入口 + Plan 终结硬闸 - ├── project-init/ # A0 - ├── scope-lock/ # A1 - ├── skeleton-gen/ # A2 - ├── db-design-gen/ # A3 - ├── db-init/ # A4 - ├── downstream-gen/ # A5 - ├── frontend-scope-lock/ # A6 - └── coding-start/ # B 阶段瘦入口(启动 coding.mjs) +└── skills/ # 按阶段分组(slug 不变,由 SKILL.md frontmatter name 决定) + ├── plan/ # 阶段 A:8 个 skill(入口 + A0~A6) + │ ├── plan-start/ # A 阶段入口 + Plan 终结硬闸 + │ ├── project-init/ # A0 + │ ├── scope-lock/ # A1 + │ ├── skeleton-gen/ # A2 + │ ├── db-design-gen/ # A3 + │ ├── db-init/ # A4 + │ ├── downstream-gen/ # A5 + │ └── frontend-scope-lock/ # A6 + └── coding/ # 阶段 B:1 个 skill(瘦入口) + └── coding-start/ # 启动 workflows/coding.mjs ``` ## Hook 清单(0 个) 本插件**不再注册任何 hook**。原"跨模块改动留痕"hook(`log-cross-module.sh`)已删除,其职责由 `workflows/coding.mjs` 的 cross-module stage 在模块循环内承担。 -## Skill 清单(9 个,扁平于 `skills/`) +## Skill 清单(9 个,按阶段分组于 `skills/{plan,coding}/`;slug 由 SKILL.md frontmatter 决定,未受目录调整影响) ### 入口(2 个) diff --git a/skills/coding-start/SKILL.md b/skills/coding-start/SKILL.md deleted file mode 100644 index 69c2b0d..0000000 --- a/skills/coding-start/SKILL.md +++ /dev/null @@ -1,125 +0,0 @@ ---- -name: coding-start -description: B 阶段(Coding)瘦入口。校验 Plan 终结闸(docs/08 §一 A0~A6 全勾、已在本地默认分支、工作树干净)后,读取 docs/08 §二/§三 概述模块/前端进度,然后调用 workflows/coding.mjs Workflow 全自动、静默地跑完整个编码阶段(后端+前端功能循环、测试闸、里程碑 tag),跑完或 halt 时返回最终状态。本入口不写任何文件、不做编码决策。 -user-invocable: true -allowed-tools: Read Glob Workflow ---- - -**所有输出必须使用中文。** - -你是 B 阶段(Coding)的**瘦入口**。你的唯一职责是:**校验 Plan 终结闸 → 概述进度 → 启动 `workflows/coding.mjs` Workflow**。 - -编码阶段是**全自动、静默的 Workflow**——其子代理物理上无法弹窗问人。因此本入口**不做任何编码决策、不写任何文件、不调用其他 skill**;全部需求/配置必须已在 Plan 期(A0~A6)锁死。真正的进度判定与 `git tag` 核对由 `coding.mjs` 的 router stage 从 `docs/08` + tag 重算——本入口的进度概述仅为给用户的信息提要。 - -> 工具约束:本 skill 只允许 `Read` / `Glob` / `Workflow`,**不允许 Bash**。门禁与进度概述全部基于 `docs/08` 文本(其 `里程碑:` 字段已记录每模块/前端阶段的 tag 名),权威的 `git tag -l 'milestone/*'` 核对交由 Workflow 内 router stage 完成。 - -## 执行步骤 - -### 步骤 0:打印 B 阶段流程概览(模型直接输出,不用 cat) - -直接向用户输出以下横幅(逐字输出文本本身,**不要**用任何命令读文件): - -``` -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - [coding-start] B 阶段(Coding)= 一个全自动静默 Workflow - - Router → 读 docs/08 + git tag,算出未完成模块 - 每个模块: - 后端功能循环 spec → plan → tdd → verify → review(≤5轮) - 后端测试闸 test-gate(RED 自动重试 1 次,仍 RED → halt) - 前端功能循环 同一流水线,phase=frontend(FE-NN,限 frontend/) - 前端测试闸 test-gate - 跨模块记录 → 模块报告 → 里程碑(merge --no-ff + milestone/ tag) - 任一模块 halt → fail-fast 停在该模块,修复后重跑本入口即可续跑 - - 全程无 Q&A:缺值表现为带诊断的 halt,不是对话框。 -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ -``` - -### 步骤 1:确认 docs/08 存在 - -用 `Glob` 检查 `docs/08-模块任务管理.md`。 -- 不存在 → 输出「⚠️ 项目尚未初始化,请先运行 `/erp-workflow:plan-start`」并**停下**,不启动 Workflow。 - -### 步骤 2:Plan 终结闸校验(HARD GATE) - -`Read` `docs/08-模块任务管理.md`,逐项校验,任一不满足即**拦截、不启动 Workflow**: - -1. **docs/08 § 一 A0~A6 全部勾选** - - 读 § 一 进度表,确认 A0/A1/A2/A3/A4/A5/A6(含各自子项)均为 `[x]`。 - - 任一未勾 → 缺口:`Plan 未完成(<未勾项>)→ 先运行 /erp-workflow:plan-start`。 - -2. **当前在本地默认分支(main / master)** - - 本入口无 Bash,无法直接查 git。改为信任用户:在放行横幅中**显式要求**用户确认当前已在默认分支。若用户已说明不在默认分支,则拦截。 - - (权威的分支/tag 状态由 `coding.mjs` 的 milestone stage 在 merge 时校验。) - -3. **工作树干净(Plan 产物已 commit)** - - 同样无法用 Bash 直接查。在放行横幅中**显式要求**用户确认工作树干净、Plan 产物已提交。 - -> 第 2/3 项受 `allowed-tools` 限制(无 Bash)无法程序化核对,故以放行横幅中的明确前置要求承担;Workflow 的 milestone stage 在本地 merge 时会再次校验分支与工作树,不干净则该 stage 失败并 halt。 - -任一缺口 → 输出拦截横幅,逐条列出缺口与回填位置,**停下**,不启动 Workflow: - -``` -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - [coding-start] ⛔ 未满足进入 B 阶段的前置条件 - - <逐条列出缺口,格式:[项] 缺口描述 → 回填/处理位置> - 例:[Plan 进度] A6 前端 scope 未勾 → 先运行 /erp-workflow:plan-start - - 处理后重新运行 /erp-workflow:coding-start。 -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ -``` - -### 步骤 3:概述进度(信息提要) - -仅当步骤 2 的 § 一 校验通过后,`Read` `docs/08 § 二`(后端模块元数据 + `里程碑:` 字段)与 `§ 三`(前端阶段 `整体里程碑:` 字段),概述: - -- 后端:每个模块的 `里程碑:` 是否已是 `milestone/`(已完成)还是 `—`(待跑)。 -- 前端:`§ 三 整体里程碑:` 是否已是 `milestone/frontend-phase`(已完成)还是 `—`(待跑)。 - -向用户简述「已完成 N 个模块 / 待跑 M 个模块;前端阶段:已完成 / 待跑」。 - -> 这是基于 docs/08 文本的提要;权威的 `git tag -l 'milestone/*'` 核对与未完成集合的最终判定由 Workflow 的 router stage 完成(router 以 docs/08 + tag 双重为准)。本入口不因提要里看似"全部完成"就跳过启动——是否有事可做由 router 决定。 - -### 步骤 4:启动 Coding Workflow - -用 `Workflow` 工具调用编码编排脚本。`projectRoot` **必须是绝对路径**(POSIX 形如 `/Users/.../my-erp`,Windows 形如 `C:\\Users\\...\\my-erp`),从你当前会话的工作目录读取——**绝不传相对路径如 `.`**。`coding.mjs` 顶部对相对路径做硬校验,传 `.` 会立即 halt(避免子代理在错误 cwd 上执行 `git -C .` 把 tag 打到错处)。 - -``` -Workflow({ - scriptPath: "${CLAUDE_PLUGIN_ROOT}/workflows/coding.mjs", - args: { projectRoot: "<当前项目根绝对路径>" } -}) -``` - -### 步骤 5:告知用户 Workflow 已启动 - -启动后向用户输出: - -``` -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - [coding-start] ✅ Coding Workflow 已启动 - - 进度概述:<步骤 3 概述,如「待跑 3 模块 + 前端阶段」> - - ⚠️ 请确认(本入口无法程序化核对): - • 当前已在本地默认分支(main / master) - • 工作树干净,Plan 产物(docs/* + skeleton + DDL)已 commit - - Workflow 将按模块顺序全自动、静默推进,跑完所有模块或在某模块 - halt(测试闸持续 RED / review 5 轮未过 / 缺值阻塞等)时返回最终状态。 - halt 后请按诊断修复,再重新运行 /erp-workflow:coding-start 续跑。 -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ -``` - -本 skill 到此结束,**不调用任何下游 skill**。 - -## 参考 - -- `docs/08-模块任务管理.md § 一`(A0~A6 Plan 进度,步骤 2 读取) -- `docs/08-模块任务管理.md § 二`(后端模块元数据 + 里程碑字段,步骤 3 读取) -- `docs/08-模块任务管理.md § 三`(前端阶段整体里程碑,步骤 3 读取) -- `workflows/coding.mjs`(B 阶段编排脚本,步骤 4 启动) -- `plan-start`(姊妹入口,A 阶段) -- `CLAUDE.md`(项目指令) diff --git a/skills/coding/coding-start/SKILL.md b/skills/coding/coding-start/SKILL.md new file mode 100644 index 0000000..69c2b0d --- /dev/null +++ b/skills/coding/coding-start/SKILL.md @@ -0,0 +1,125 @@ +--- +name: coding-start +description: B 阶段(Coding)瘦入口。校验 Plan 终结闸(docs/08 §一 A0~A6 全勾、已在本地默认分支、工作树干净)后,读取 docs/08 §二/§三 概述模块/前端进度,然后调用 workflows/coding.mjs Workflow 全自动、静默地跑完整个编码阶段(后端+前端功能循环、测试闸、里程碑 tag),跑完或 halt 时返回最终状态。本入口不写任何文件、不做编码决策。 +user-invocable: true +allowed-tools: Read Glob Workflow +--- + +**所有输出必须使用中文。** + +你是 B 阶段(Coding)的**瘦入口**。你的唯一职责是:**校验 Plan 终结闸 → 概述进度 → 启动 `workflows/coding.mjs` Workflow**。 + +编码阶段是**全自动、静默的 Workflow**——其子代理物理上无法弹窗问人。因此本入口**不做任何编码决策、不写任何文件、不调用其他 skill**;全部需求/配置必须已在 Plan 期(A0~A6)锁死。真正的进度判定与 `git tag` 核对由 `coding.mjs` 的 router stage 从 `docs/08` + tag 重算——本入口的进度概述仅为给用户的信息提要。 + +> 工具约束:本 skill 只允许 `Read` / `Glob` / `Workflow`,**不允许 Bash**。门禁与进度概述全部基于 `docs/08` 文本(其 `里程碑:` 字段已记录每模块/前端阶段的 tag 名),权威的 `git tag -l 'milestone/*'` 核对交由 Workflow 内 router stage 完成。 + +## 执行步骤 + +### 步骤 0:打印 B 阶段流程概览(模型直接输出,不用 cat) + +直接向用户输出以下横幅(逐字输出文本本身,**不要**用任何命令读文件): + +``` +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + [coding-start] B 阶段(Coding)= 一个全自动静默 Workflow + + Router → 读 docs/08 + git tag,算出未完成模块 + 每个模块: + 后端功能循环 spec → plan → tdd → verify → review(≤5轮) + 后端测试闸 test-gate(RED 自动重试 1 次,仍 RED → halt) + 前端功能循环 同一流水线,phase=frontend(FE-NN,限 frontend/) + 前端测试闸 test-gate + 跨模块记录 → 模块报告 → 里程碑(merge --no-ff + milestone/ tag) + 任一模块 halt → fail-fast 停在该模块,修复后重跑本入口即可续跑 + + 全程无 Q&A:缺值表现为带诊断的 halt,不是对话框。 +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +``` + +### 步骤 1:确认 docs/08 存在 + +用 `Glob` 检查 `docs/08-模块任务管理.md`。 +- 不存在 → 输出「⚠️ 项目尚未初始化,请先运行 `/erp-workflow:plan-start`」并**停下**,不启动 Workflow。 + +### 步骤 2:Plan 终结闸校验(HARD GATE) + +`Read` `docs/08-模块任务管理.md`,逐项校验,任一不满足即**拦截、不启动 Workflow**: + +1. **docs/08 § 一 A0~A6 全部勾选** + - 读 § 一 进度表,确认 A0/A1/A2/A3/A4/A5/A6(含各自子项)均为 `[x]`。 + - 任一未勾 → 缺口:`Plan 未完成(<未勾项>)→ 先运行 /erp-workflow:plan-start`。 + +2. **当前在本地默认分支(main / master)** + - 本入口无 Bash,无法直接查 git。改为信任用户:在放行横幅中**显式要求**用户确认当前已在默认分支。若用户已说明不在默认分支,则拦截。 + - (权威的分支/tag 状态由 `coding.mjs` 的 milestone stage 在 merge 时校验。) + +3. **工作树干净(Plan 产物已 commit)** + - 同样无法用 Bash 直接查。在放行横幅中**显式要求**用户确认工作树干净、Plan 产物已提交。 + +> 第 2/3 项受 `allowed-tools` 限制(无 Bash)无法程序化核对,故以放行横幅中的明确前置要求承担;Workflow 的 milestone stage 在本地 merge 时会再次校验分支与工作树,不干净则该 stage 失败并 halt。 + +任一缺口 → 输出拦截横幅,逐条列出缺口与回填位置,**停下**,不启动 Workflow: + +``` +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + [coding-start] ⛔ 未满足进入 B 阶段的前置条件 + + <逐条列出缺口,格式:[项] 缺口描述 → 回填/处理位置> + 例:[Plan 进度] A6 前端 scope 未勾 → 先运行 /erp-workflow:plan-start + + 处理后重新运行 /erp-workflow:coding-start。 +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +``` + +### 步骤 3:概述进度(信息提要) + +仅当步骤 2 的 § 一 校验通过后,`Read` `docs/08 § 二`(后端模块元数据 + `里程碑:` 字段)与 `§ 三`(前端阶段 `整体里程碑:` 字段),概述: + +- 后端:每个模块的 `里程碑:` 是否已是 `milestone/`(已完成)还是 `—`(待跑)。 +- 前端:`§ 三 整体里程碑:` 是否已是 `milestone/frontend-phase`(已完成)还是 `—`(待跑)。 + +向用户简述「已完成 N 个模块 / 待跑 M 个模块;前端阶段:已完成 / 待跑」。 + +> 这是基于 docs/08 文本的提要;权威的 `git tag -l 'milestone/*'` 核对与未完成集合的最终判定由 Workflow 的 router stage 完成(router 以 docs/08 + tag 双重为准)。本入口不因提要里看似"全部完成"就跳过启动——是否有事可做由 router 决定。 + +### 步骤 4:启动 Coding Workflow + +用 `Workflow` 工具调用编码编排脚本。`projectRoot` **必须是绝对路径**(POSIX 形如 `/Users/.../my-erp`,Windows 形如 `C:\\Users\\...\\my-erp`),从你当前会话的工作目录读取——**绝不传相对路径如 `.`**。`coding.mjs` 顶部对相对路径做硬校验,传 `.` 会立即 halt(避免子代理在错误 cwd 上执行 `git -C .` 把 tag 打到错处)。 + +``` +Workflow({ + scriptPath: "${CLAUDE_PLUGIN_ROOT}/workflows/coding.mjs", + args: { projectRoot: "<当前项目根绝对路径>" } +}) +``` + +### 步骤 5:告知用户 Workflow 已启动 + +启动后向用户输出: + +``` +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + [coding-start] ✅ Coding Workflow 已启动 + + 进度概述:<步骤 3 概述,如「待跑 3 模块 + 前端阶段」> + + ⚠️ 请确认(本入口无法程序化核对): + • 当前已在本地默认分支(main / master) + • 工作树干净,Plan 产物(docs/* + skeleton + DDL)已 commit + + Workflow 将按模块顺序全自动、静默推进,跑完所有模块或在某模块 + halt(测试闸持续 RED / review 5 轮未过 / 缺值阻塞等)时返回最终状态。 + halt 后请按诊断修复,再重新运行 /erp-workflow:coding-start 续跑。 +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +``` + +本 skill 到此结束,**不调用任何下游 skill**。 + +## 参考 + +- `docs/08-模块任务管理.md § 一`(A0~A6 Plan 进度,步骤 2 读取) +- `docs/08-模块任务管理.md § 二`(后端模块元数据 + 里程碑字段,步骤 3 读取) +- `docs/08-模块任务管理.md § 三`(前端阶段整体里程碑,步骤 3 读取) +- `workflows/coding.mjs`(B 阶段编排脚本,步骤 4 启动) +- `plan-start`(姊妹入口,A 阶段) +- `CLAUDE.md`(项目指令) diff --git a/skills/db-design-gen/SKILL.md b/skills/db-design-gen/SKILL.md deleted file mode 100644 index ce41b6e..0000000 --- a/skills/db-design-gen/SKILL.md +++ /dev/null @@ -1,121 +0,0 @@ ---- -name: db-design-gen -description: A3 DB 设计 + REQ 回填——基于 docs/01-需求清单//REQ-*.md 正向设计 docs/03-数据库设计文档.md(业务实体 → 表 + 字段 + 索引 + 外键 + 业务注记),并把回填值写入 REQ 卡片的「依赖表: TBD(A3 自动补)」与模块头的「涉及表: TBD(A3 自动补)」占位。生成完毕停下等人工审阅。 -user-invocable: false -allowed-tools: Read Write Edit Grep Glob AskUserQuestion ---- - -**所有输出必须使用中文。** - -# db-design-gen - -## 前置条件 - -- A1 `scope-lock` 已完成:`docs/01-需求清单//_module.md` + `docs/01-需求清单//REQ-*.md` 已生成,含 `TBD(A3 自动补)` 占位。 -- A2 `skeleton-gen` 已完成:`docs/04-技术规范.md § 一+` 命名规范已生成(本 skill 推导表/字段命名时严格遵循)。 - -## 执行步骤 - -### 步骤 A0:确认 ERP schema 约定(一次性) - -在正向设计 schema 之前,**先确认本项目的 3 项数据库约定**。默认值即现 ERP 约定,用户可逐项覆盖。结果写入 `docs/04` + `CLAUDE.md`,本 skill 后续步骤(B/C)严格引用确认后的值,不再字面写死。 - -> 先用 `Grep` 检查 `docs/04-技术规范.md` 是否已含 `## 四、数据库 schema 约定` 节。**已存在则视为本约定已确认**,跳过本步骤直接读取该节作为 `PK_CONVENTION` / `TENANT_COLS` / `COL_PREFIX_RULE` 的值,进入步骤 A。 - -用 `AskUserQuestion` 一次性提出以下 3 个问题(每题给「沿用默认」与「自定义」两类选项;选自定义时追问具体值): - -1. **主键约定(PK_CONVENTION)** - - 默认(沿用 ERP):`iIncrement` int 整数主键(自增方式由实现决定:DB `AUTO_INCREMENT` 或应用/触发器分配),另设 `sId` varchar(100) 业务 ID 对外暴露。 - - 自定义:用户给出主键列名 / 类型 / 生成策略(如复合主键 / UUID / 业务主键)。 - -2. **租户隔离列(TENANT_COLS)** - - 默认(沿用 ERP):`sBrandsId` varchar(100)(品牌 ID,多租户隔离)+ `sSubsidiaryId` varchar(100)(子公司 ID,组织层级隔离),默认值均为 `1111111111`。 - - 自定义:用户给出租户列名 / 类型 / 默认值,或声明本项目不做多租户隔离(此时 TENANT_COLS = 「无」)。 - -3. **列命名前缀规则(COL_PREFIX_RULE)** - - 默认(沿用 ERP):匈牙利前缀——`i` = int、`s` = varchar、`t` = datetime。 - - 自定义:用户给出自己的前缀/命名规则,或声明不使用前缀(此时 COL_PREFIX_RULE = 「无前缀,列名直接用业务语义」)。 - -得到三项确认值后: - -- **写入 `docs/04-技术规范.md`**:用 `Grep` 确认无 `## 四、数据库 schema 约定` 节后,用 `Edit` 在文末追加该节,列出 `PK_CONVENTION` / `TENANT_COLS` / `COL_PREFIX_RULE` 三项的确认值(每项含列名/类型/默认值/生成策略的完整描述)。 -- **写入 `CLAUDE.md`**:用 `Edit` 在「Schema 演化规约」节末尾追加一条「数据库 schema 约定(A3 确认)」小节,简述三项约定,并注明「详见 `docs/04 § 四`」。 - -后续步骤 B/C 用到 `{{PK_CONVENTION}}` / `{{TENANT_COLS}}` / `{{COL_PREFIX_RULE}}` 处,一律引用此处确认后的值。 - -### A. 读取设计输入 - -读: - -- `docs/04-技术规范.md` -- `docs/01-需求清单/index.md` 模块索引 -- `docs/01-需求清单/*/REQ-*.md` 所有 REQ 卡片 - -### B. 推导 schema - -基于步骤 A 读到的 REQ + 命名规范,**正向推导**业务实体 → 表 + 字段 + 索引 + 外键。要求: - -1. 严格套用 `docs/04` 的命名规范 + 步骤 A0 确认的 `COL_PREFIX_RULE` 列命名前缀规则 -2. **主键**:套用步骤 A0 确认的 `PK_CONVENTION`。REQ 明确要求与确认约定不同的主键(复合主键 / UUID / 业务主键)时按 REQ,并在该表业务注记里注明偏离原因 -3. **外键**:依据 REQ 中的引用关系(如「订单引用客户」),明确列出 `ON DELETE` / `ON UPDATE` 策略;不能确定时默认 `RESTRICT` -4. **索引**:根据 REQ 的查询模式推导业务索引;外键列默认建索引;步骤 A0 确认的 `TENANT_COLS` 租户隔离列(若非「无」),按业务查询模式建组合索引 -5. **业务注记**:对每张表用一两句话说明业务用途、关键约束、与其他表的关系 - -如果某 REQ 表述模糊以致无法推断关键 schema 细节(如:枚举值范围 / 字段长度上限 / 必填性),先按合理默认推导并在该字段「业务含义」列加 `【人工填写:需用户审阅】` 标注,待步骤 E 用户审阅时调整;**不打断本次推导**。 - -### C. 渲染 docs/03 - -1. 读取 `${CLAUDE_SKILL_DIR}/templates/docs-03-header-template.md`,填充 `schema_name`(从 `.env.local` 读 `DB_SCHEMA`,无则填 `【人工填写:DB_SCHEMA】`)、`er_overview`(纯文本 ER 概览),以及步骤 A0 确认的 `{{PK_CONVENTION}}` / `{{TENANT_COLS}}` / `{{COL_PREFIX_RULE}}`。 -2. 渲染「表清单」:对每张表:读取并填充 `${CLAUDE_SKILL_DIR}/templates/docs-03-table-template.md`,其中标准列区块用步骤 A0 确认的 `{{PK_CONVENTION}}` / `{{TENANT_COLS}}` 展开(`TENANT_COLS` = 「无」时不输出租户列行)。 -3. 写入 `docs/03-数据库设计文档.md`。 - -完成后,用 `Edit` 在 `docs/08-模块任务管理.md` 中勾选: -- ` - [ ] docs/03-数据库设计文档.md 已生成` - -### D. 回填模块头 + REQ 卡片的 TBD 字段 - -1. 列出 `docs/01-需求清单/*/_module.md`(模块头)和 `docs/01-需求清单/*/REQ-*.md`(REQ 卡片)。 -2. 在这些文件中搜索 `TBD(A3 自动补)` 的并回填。 不动 `TBD(A5 自动补)` -3. 打印回填统计:`A3 回填 处模块"涉及表" + 处 REQ"依赖表"`。 - -完成后,用 `Edit` 在 `docs/08-模块任务管理.md` 中勾选: -- ` - [ ] docs/01 各 REQ 卡片"依赖表" + 模块头"涉及表" 已回填` - -### E. 勾选 A3 顶层 + 停下等人工审阅 - -1. 完成后,用 `Edit` 在 `docs/08-模块任务管理.md` 中勾选 A3 顶层(A3 两个子项已在 C / D 步骤分别勾选): - - `- [ ] A3 DB 设计 + REQ 回填 — db-design-gen` - -2. 打印停下横幅并**停下**: - - ``` - ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - [db-design-gen] ✅ A3 DB 设计完成 - - 产出: - ✓ docs/03-数据库设计文档.md - ✓ docs/01-需求清单//REQ-*.md 依赖表已回填 + _module.md 涉及表已回填 - - ⏸ 现在请你审阅 docs/03。 - 重点关注: - - 业务实体覆盖是否完整 - - 字段类型 / 长度 / 是否可空 / 默认值是否合理 - - 索引是否覆盖主要查询模式 - - 外键 ON DELETE / ON UPDATE 策略是否符合业务 - - 字段「业务含义」列含 `【人工填写:需用户审阅】` 标注的位置需逐一确认 - - 审阅完成后,再运行: - /erp-workflow:plan-start - - ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - ``` - - **停止**,不调用任何下游 skill。 - -## 参考 - -- `${CLAUDE_SKILL_DIR}/templates/docs-03-header-template.md` -- `${CLAUDE_SKILL_DIR}/templates/docs-03-table-template.md` -- `docs/04-技术规范.md` § 一+(命名规范输入) -- `docs/01-需求清单//_module.md`(模块头:回填 `涉及表`) -- `docs/01-需求清单//REQ-*.md`(REQ 输入 + 回填 `依赖表`) diff --git a/skills/db-design-gen/templates/docs-03-header-template.md b/skills/db-design-gen/templates/docs-03-header-template.md deleted file mode 100644 index fa8507c..0000000 --- a/skills/db-design-gen/templates/docs-03-header-template.md +++ /dev/null @@ -1,24 +0,0 @@ -# 03-数据库设计文档 - -- **Schema**: `{{schema_name}}` -- **Migration 清单**: `sql/migrations/V*.sql`(由 Flyway 顺序 apply) -- **生成方式**: 由 A3 `db-design-gen` 基于 `docs/01-需求清单//REQ-*.md` REQ 卡片正向设计生成(schema SSoT)。 - -## 项目标准列约定 - -本项目的数据库约定(主键 / 租户隔离列 / 列命名前缀)由 A3 `db-design-gen` 在设计起始时一次性确认,确认值见 `docs/04-技术规范.md § 四、数据库 schema 约定`。下文每张业务表的字段清单都自动包含以下标准列,渲染时由 `docs-03-table-template.md` 模板按确认值展开。 - -- **列命名前缀规则**:{{COL_PREFIX_RULE}} -- **主键约定**:{{PK_CONVENTION}} -- **租户隔离列**:{{TENANT_COLS}} - -字典 / 辅助表如有豁免,在该表业务注记里注明豁免原因。 - -## ER 关系概览 - -{{er_overview}} - -## 表清单 -{{#each tables}} -- `{{table_name}}` — {{purpose}} -{{/each}} diff --git a/skills/db-design-gen/templates/docs-03-table-template.md b/skills/db-design-gen/templates/docs-03-table-template.md deleted file mode 100644 index f43e1ea..0000000 --- a/skills/db-design-gen/templates/docs-03-table-template.md +++ /dev/null @@ -1,25 +0,0 @@ -## `{{table_name}}` — {{purpose}} - -### 字段 - -| 字段 | 类型 | Nullable | 默认 | 业务含义 | -|---|---|---|---|---| -{{PK_CONVENTION}} -{{TENANT_COLS}} -| `tCreateDate` | datetime | 否 | 当前时间 | 创建时间(标准列) | -{{#each columns}} -| {{name}} | {{type}} | {{nullable}} | {{default}} | {{business_meaning}} | -{{/each}} - -### 索引 -{{#each indexes}} -- `{{name}}` ({{type}}): {{columns}} -{{/each}} - -### 外键 -{{#each foreign_keys}} -- `{{name}}`: {{from_col}} → {{to_table}}.{{to_col}} ({{on_delete}}) -{{/each}} - -### 业务注记 -{{notes}} diff --git a/skills/db-init/SKILL.md b/skills/db-init/SKILL.md deleted file mode 100644 index ea9cbbc..0000000 --- a/skills/db-init/SKILL.md +++ /dev/null @@ -1,141 +0,0 @@ ---- -name: db-init -description: A4 DB 初始化——LLM 解析 docs/03-数据库设计文档.md → 生成 sql/migrations/V1__initial_schema.sql(DDL only,Flyway 初始 migration)→ 用 lib/validate-ddl.mjs 全量校验 DDL ↔ docs/03 一致性 → 验证 MySQL 连接 → 调 scripts/setup-test-db.mjs 复用三层防护并 DROP+CREATE 空库 → 用 lib/apply-ddl.mjs apply V1。 -user-invocable: false -allowed-tools: Read Write Edit Glob Skill Bash(node *) Bash(mysql *) ---- - -**所有输出必须使用中文。** - -# db-init - -## 执行步骤 - -### A. DDL 生成(不依赖数据库连接) - -#### A.1 读 docs/03 并翻译为 DDL - -读取 `docs/03-数据库设计文档.md`,按字段 / 索引 / 外键 / 业务注记**严格翻译**为: - -- 每张表一段 `CREATE TABLE` -- 字段顺序与 docs/03 表格行序一致;`Nullable` 列直接映射 `NOT NULL` / `NULL`;`默认` 列映射 `DEFAULT `;列尾用 `COMMENT '<业务含义>'` 写注释 -- 索引 -- 外键:在所有表创建完成后**统一追加** - -要求: -- **严禁臆造** docs/03 中没有的表 / 字段 / 索引 / 外键 -- **严禁省略** docs/03 中已有的列、注释或约束 -- 字符集统一 `utf8mb4` + `utf8mb4_unicode_ci`,引擎统一 `InnoDB`,除非 docs/03 业务注记明确要求其他设置 - -#### A.2 落盘 V1 文件 - -用 `Write` 写 `sql/migrations/V1__initial_schema.sql`(`Write` 会自动创建缺失的父目录 `sql/migrations/`),内容 = 头部注释 + DDL 主体: - -1. **头部注释**(6 行 SQL 注释): - - `-- Flyway migration V1 — initial schema for `(从 `CLAUDE.md § 🎯 项目概述` 读) - - `-- Generated: `(UTC ISO 8601 时间戳) - - `-- Source: 由 A4 db-init 从 docs/03-数据库设计文档.md 翻译生成(schema SSoT 是 docs/03)` - - `-- This is the FIRST migration; subsequent schema changes must be written as new files sql/migrations/V2__.sql, V3__... etc.` - - `-- Apply: Flyway runs this automatically at Spring Boot startup.` - - `-- Do not hand-edit this file after it is committed; write a new migration instead.` - -2. **DDL 主体**:A.1 推导出的所有 `CREATE TABLE` → `CREATE INDEX` → `ALTER TABLE ... ADD CONSTRAINT ... FOREIGN KEY`,按此顺序拼接。 - -#### A.3 校验 V1 ↔ docs/03 5 维一致性 + 自主修正 - -调 `${CLAUDE_PLUGIN_ROOT}/lib/validate-ddl.mjs` 做跨平台、纯 Node 的 5 维校验(表集合 / 列名 / 列类型 / 索引 / 外键)。**注意参数顺序:docs/03 在前,V1.sql 在后。** - -```bash -node "${CLAUDE_PLUGIN_ROOT}/lib/validate-ddl.mjs" \ - docs/03-数据库设计文档.md \ - sql/migrations/V1__initial_schema.sql -``` - -退出码与处理: -- `0` → 通过,进入步骤 B -- `1` → 存在差异(5 维 diff 明细打印到 stderr)。进入**自主修正循环**(最多 3 轮,docs/03 是 SSoT 不动): - 1. 解析 stderr 差异清单,修正 V1.sql - 2. 重跑 `validate-ddl.mjs` - 3. 退出 0 → 进入 B;退出 1 且本轮 < 3 → 回步骤 1;本轮 ≥ 3 仍失败 → 停下,打印最终残留差异 + 已尝试的 3 轮修正摘要,让用户介入 -- `2` → 用法错(docs/03 / V1 路径找不到),打印路径并停下 - -完成后(V1 写入并通过 `validate-ddl.mjs` 校验),用 `Edit` 在 `docs/08-模块任务管理.md` 中勾选: -- ` - [ ] sql/migrations/V1__initial_schema.sql 已生成` -- ` - [ ] DDL 与 docs/03 全量一致` - -### B. 数据库环境检查 - -#### B.1 检查 .env.local 凭据 - -用 `Glob` 检查 `.env.local` 是否存在;不存在 → 提示用户重新运行 A2 `skeleton-gen` 重建并停下。 - -用 `Read` 读取 `.env.local`,逐行解析 `KEY=VALUE`(跳过空行 / `#` 注释,**不做** shell-source / 变量展开),校验 5 个必填字段 `DB_HOST`、`DB_PORT`、`DB_USER`、`DB_PASSWORD`、`DB_SCHEMA` 均存在且非空。 - -任一缺失 → 打印缺失字段名并停下,提示用户编辑 `.env.local` 后重跑。 - -#### B.2 验证 MySQL 连接 - -用 B.1 解析出的字段值(**不要** shell-source `.env.local`)拼出 `mysql` 客户端调用,做一次连通性自检。把 `` 等占位替换为读到的实际值: - -```bash -mysql -h -P -u -p -e "SELECT 1;" -``` - -- **成功** → 进入步骤 C -- **失败** → 打印具体错误(认证 / 主机不可达 / 端口拒接等),提示检查 `.env.local`,**停下**。 - -完成后,用 `Edit` 在 `docs/08-模块任务管理.md` 中勾选: -- ` - [ ] .env.local 凭据已验证(mysql -e "SELECT 1" OK)` - -### C. 自动导入 MySQL - -#### C.1 DROP+CREATE 空库 - -```bash -node scripts/setup-test-db.mjs -``` - -#### C.2 把 V1 灌入已清空的 schema - -调 `${CLAUDE_PLUGIN_ROOT}/lib/apply-ddl.mjs`:它用纯 JS 解析 `.env.local`(**不** shell-source,消除注入),再经 mysql2 把 DDL 灌入 schema。 - -```bash -node "${CLAUDE_PLUGIN_ROOT}/lib/apply-ddl.mjs" .env.local sql/migrations/V1__initial_schema.sql -``` - -退出码与处理: -- `0` → 成功,进入 C.3 -- `1` → 失败:若错误提示 `mysql2 not found`,先在目标项目执行 `npm i mysql2` 再重跑;其余错误打印 stderr 并停下 -- `2` → 用法错(路径找不到),打印路径并停下 - -完成后,用 `Edit` 在 `docs/08-模块任务管理.md` 中勾选: -- ` - [ ] setup-test-db.mjs 防护通过 + DROP+CREATE + apply V1 已执行` - -#### C.3 自检:docs/03 ↔ V1 表集合一致 - -再跑一次 `validate-ddl.mjs`,确认刚 apply 的 `V1__initial_schema.sql` 与 docs/03 的表/列/类型/索引/外键 5 维仍然一致(参数顺序:docs/03 在前,V1.sql 在后): - -```bash -node "${CLAUDE_PLUGIN_ROOT}/lib/validate-ddl.mjs" \ - docs/03-数据库设计文档.md \ - sql/migrations/V1__initial_schema.sql -``` - -退出码 `0` → 进入步骤 D;`1` → 打印 stderr 5 维 diff 并停下;`2` → 路径错,打印路径并停下。 - -### D. 勾选 docs/08 进度 + 进入 A5 - - -1. 完成后,用 `Edit` 在 `docs/08-模块任务管理.md` 中勾选(A4 子项 + A4 顶层): - - ` - [ ] DDL ↔ docs/03 apply 后 5 维一致(validate-ddl.mjs)` - - `- [ ] A4 DB 初始化 — db-init` - -2. 立即调用 `Skill(downstream-gen)` 进入 A5,不等用户手动输入。 - -## 参考 - -- `${CLAUDE_PLUGIN_ROOT}/lib/validate-ddl.mjs`(A.3 / C.3 docs/03 ↔ V1.sql 5 维一致性校验,跨平台纯 Node) -- `${CLAUDE_PLUGIN_ROOT}/lib/apply-ddl.mjs`(C.2 安全解析 .env.local + mysql2 灌入 DDL,不 shell-source) -- `docs/03-数据库设计文档.md`(DDL 翻译输入,SSoT) -- `.env.local`(DB 凭据) -- 产物:`sql/migrations/V1__initial_schema.sql`(由 Flyway 在 Spring Boot 启动时验证 / apply) diff --git a/skills/downstream-gen/SKILL.md b/skills/downstream-gen/SKILL.md deleted file mode 100644 index 54ad39c..0000000 --- a/skills/downstream-gen/SKILL.md +++ /dev/null @@ -1,146 +0,0 @@ ---- -name: downstream-gen -description: A5 下游文档生成——基于 docs/01 和 docs/03 推导,一次性生成 docs/02 + docs/05 + docs/06 § 三 + docs/10,回填 REQ 卡片依赖接口,把模块清单追加到 docs/08 § 二。 -user-invocable: false -allowed-tools: Read Write Edit Glob Grep Skill AskUserQuestion ---- - -**所有输出必须使用中文。** - -# downstream-gen - -## 执行步骤 - -### A. docs/02 — 开发计划(含 REQ 级开发顺序清单) - -**清单颗粒度**:一行一个 REQ,同一模块的 REQ 必须**连续排列**。 - -1. 构建**模块依赖 DAG**。 -2. 对**每个模块内部**构建 REQ 间依赖,得到模块内 REQ 顺序。 -3. 合成 `req_order[]`:按 `module_topo_order[]` 依次铺开每个模块内的 REQ 序列(**同模块 REQ 连续**)。 -4. **环依赖打破**: - - **模块级**:若模块 DAG 存在环(module_A ↔ module_B),按启发式(字母序 / 被依赖次数多者先)破环排出 `module_topo_order`,并在**参与环的模块里第一个 REQ** 的 `note` 字段填入原因(如 "A↔B 互依赖:先做 A 的骨架")。 - - **REQ 级(同模块内)**:若模块内 REQ 互依赖,同样破环,`note` 填原因。 - - 非环 REQ `note` 留 `—`。 -5. 为 `req_order[]` 每项生成字段: - - `index`:行号(从 1 开始) - - `req_id`:如 `REQ-SYS-001` - - `module_id`:该 REQ 所属模块,如 `module_sys` - - `rationale`(**选中理由**):依赖驱动的简短描述,如 `所属模块无依赖,基础模块` / `依赖 REQ-SYS-001 已在前` / `所属模块依赖 module_sys 已在前` - - `note`(**备注**):默认 `—`;仅环依赖打破场景填原因 -6. 读取并填充 `${CLAUDE_SKILL_DIR}/templates/docs-02-template.md`。 -7. 写入 `docs/02-开发计划.md`。 - -完成后,用 `Edit` 在 `docs/08-模块任务管理.md` 中勾选: -- ` - [ ] docs/02 开发计划已生成` - -### B. docs/05 — API 接口契约 - -1. 读取 `${CLAUDE_SKILL_DIR}/templates/docs-05-header-template.md`,写入 `docs/05-API接口契约.md` 头部。 -2. 对所有模块的每个 REQ:读取并推断 `${CLAUDE_SKILL_DIR}/templates/docs-05-endpoint-template.md`,追加到 docs/05。 - -完成后,用 `Edit` 在 `docs/08-模块任务管理.md` 中勾选: -- ` - [ ] docs/05 API 契约已生成` - -### B2. 回填模块头 + REQ 卡片的 TBD(A5) 字段 - -1. 在`docs/01-需求清单/*/_module.md`(模块头)和 `docs/01-需求清单/*/REQ-*.md`(REQ 卡片)中搜索并回填 `TBD(A5 自动补)` -2. 打印回填统计:`A5 回填 处模块"依赖模块" + 处 REQ"依赖接口"`。 - -完成后,用 `Edit` 在 `docs/08-模块任务管理.md` 中勾选: -- ` - [ ] REQ 卡片依赖接口已回填` - -### C. docs/06 — 页面清单 - -对每个有前端页面的模块:读取并填充 `${CLAUDE_SKILL_DIR}/templates/docs-06-module-pagelist-template.md`,追加到 `docs/06-UI交互规范.md` § 三。 - -完成后,用 `Edit` 在 `docs/08-模块任务管理.md` 中勾选: -- ` - [ ] docs/06 § 三 页面清单已填入` - -### D. docs/08 — 追加模块清单 - -读 `${CLAUDE_SKILL_DIR}/templates/docs-08-module-row-template.md`,按 `module_id` 字母序为每个模块渲染 bullet(模块元数据 + REQ 子项清单,REQ 序保持步骤 A 模块内顺序),追加到 docs/08。 - -完成后,用 `Edit` 在 `docs/08-模块任务管理.md` 中勾选: -- ` - [ ] 下方模块列表已填入` - -### E. docs/10 — 验收清单(项目级 SOP) - -用 `Read` 读取 `${CLAUDE_SKILL_DIR}/templates/docs-10-header-template.md`,用 `Write` 原样写到 `docs/10-验收检查清单.md`(跨平台,不用 `cp`)。 - -完成后,用 `Edit` 在 `docs/08-模块任务管理.md` 中勾选: -- ` - [ ] docs/10 验收清单已生成` - -### F. 验证 + 勾选 docs/08 进度 + 结束 Plan - -1. 一致性检查 + 自主修复循环(最多 3 轮,docs/01 是 REQ SSoT 不动): - - **检查项**: - - 每个 docs/01 REQ 都出现在 docs/05(作为接口,如适用) - - `docs/02 § 二` 的 `module_id` 集合 = `docs/08 § 二` 的 `module_id` 集合 - - **不一致 → 按差异类型自主修复**: - - **REQ 缺 docs/05 endpoint** → 按步骤 B 规则为该 REQ 推测,并追加到 docs/05 - - **module_id 缺 docs/08 § 二** → 按步骤 D 规则渲染该模块 bullet(含 REQ 子项),按 `module_id` 字母序插入正确位置 - - **module_id 缺 docs/02 § 二** → 重算该模块的 `req_order` 段(步骤 A 子流程),按拓扑序插入 docs/02 § 二 - - 修复后重跑检查;通过 → 进入 2;3 轮仍失败 → 停下,打印最终残留差异 + 已尝试的 3 轮修复摘要让用户介入。 - -2. **最终占位符扫描 + 结构性残留检查**(覆盖 Plan 阶段全部产出): - - a. **`TBD` → 自动补齐**:Grep 搜索 `TBD(A3 自动补)` 和 `TBD(A5 自动补)`。有命中则就地补填(A3 残留 → 查 docs/03 填 `依赖表`;A5 残留 → 查 docs/05 按 REQ-ID 填 `依赖接口`),再 Grep 确认 0 命中;仍残留报错停下。 - - b. **结构性残留检查(不只看字面占位符,校验 SSoT 完整性)**: - - - **docs/05 每个端点都有请求/响应 schema**:逐个解析 docs/05 的每个 endpoint 段(以 `### REQ-` 开头的小节)。每段必须同时含非空的 `- **请求**:` 与 `- **响应**:` 行——值不得为空、`TBD`、`—` 或 `【人工填写:…】`。缺失/留空 → 按步骤 B 规则就地为该端点推测补全请求/响应 schema,再复核;3 轮仍补不全则计入残留清单(见下方 c),交由 QA 循环让用户介入。 - - **docs/02 DAG 覆盖每个 REQ**:收集 docs/01 全部 REQ-ID 集合,与 `docs/02 § 二、开发顺序清单` 表中出现的 `req_id` 集合比对。任一 docs/01 REQ 未出现在 docs/02 顺序清单 → 按步骤 A 子流程把该 REQ 插入其所属模块段的正确拓扑位置(保持同模块 REQ 连续),再复核;3 轮仍无法补齐则计入残留清单交由 QA 循环。 - - c. **`【人工填写:...】` + 结构性残留 → QA 循环等用户补**: - - 循环执行直到(搜索不到 `【人工填写:`)**且**(步骤 b 两项结构检查均通过)且用户选「继续」: - - 0 残留 → 直接放行进入步骤 3 - - 有残留 → 打印残留清单(含字面占位符 `<文件:行号> — <内容摘要>`,以及结构性缺口 `docs/05 端点 缺请求/响应 schema` / `docs/02 顺序清单缺 REQ `),用 `AskUserQuestion` 弹「继续」/「有疑问想先沟通」二选一;用户回答后重扫 + 重跑结构检查再决定放行 / 继续循环 - - **每次弹 QA 前都重扫一次**(含两项结构检查)——保证用户看到的 N 是最新的,避免「用户以为填完但实际还有残留」直接放行。 - -3. **docs/05 + docs/02 人工评审闸(强制,未确认不得勾选 A5)**: - - 向用户摘要展示两份 SSoT 的关键内容,请其确认无误: - - **docs/05 API 契约**:列出全部端点(`METHOD PATH — REQ-ID`),并标注任何「由 A5 自动推断」的端点/字段供重点核对。 - - **docs/02 构建顺序**:展示 `req_order[]` 顺序,**特别标出所有 `note ≠ —` 的环依赖打破项**(启发式选定的顺序 + 原因),供用户判断该顺序是否可接受。 - - 用 `AskUserQuestion` 同时问两项确认(多问题表单),每项二选一: - - 「docs/05 端点/字段确认无误」:`确认` / `需要修改` - - 「docs/02 构建顺序可接受(含 cycle-breaking 选定的顺序)」:`确认` / `需要修改` - - 裁决: - - 两项均 `确认` → 进入步骤 4 勾选 A5。 - - 任一为 `需要修改` → 用 `AskUserQuestion` 收集具体修改点,就地修订对应文档(docs/05 端点/字段或 docs/02 顺序/备注),改完重新展示摘要并重跑本评审闸,直到两项均 `确认`。**未两项确认前禁止勾选 A5、禁止打印终止横幅。** - -4. 完成后,用 `Edit` 在 `docs/08-模块任务管理.md` 勾选 A5 父项: - - `- [ ] A5 下游文档生成 — downstream-gen` - -5. 打印 A5 完成横幅并**停下**(A6 仍未跑——A5 之后由 plan-start 派发 A6 frontend-scope-lock,A6 完成后再由 plan-start 跑 5 项终结闸;只有终结闸全过才会提示运行 coding-start): - - ``` - ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - [downstream-gen] ✅ A5 下游文档生成完成(A0~A5) - - docs/02 / docs/05 / docs/06 § 三 / docs/08 § 二 / docs/10 已就绪; - docs/05 + docs/02 评审闸已通过;docs/08 § 一 A0~A5 已全勾。 - - ⏭️ 下一步:运行 /erp-workflow:plan-start - plan-start 会派发到 A6 frontend-scope-lock 锁定前端 scope, - A6 完成后再由 plan-start 跑 5 项终结闸校验; - 全过才会提示运行 /erp-workflow:coding-start 进入 B 阶段。 - ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - ``` - -## 参考 - -- `${CLAUDE_SKILL_DIR}/templates/docs-02-template.md` -- `${CLAUDE_SKILL_DIR}/templates/docs-05-header-template.md` -- `${CLAUDE_SKILL_DIR}/templates/docs-05-endpoint-template.md` -- `${CLAUDE_SKILL_DIR}/templates/docs-06-module-pagelist-template.md`(追加到 docs/06 § 三) -- `${CLAUDE_SKILL_DIR}/templates/docs-08-module-row-template.md`(模块 bullet 行模板) -- `${CLAUDE_SKILL_DIR}/templates/docs-10-header-template.md` diff --git a/skills/downstream-gen/templates/docs-02-template.md b/skills/downstream-gen/templates/docs-02-template.md deleted file mode 100644 index 68d29d5..0000000 --- a/skills/downstream-gen/templates/docs-02-template.md +++ /dev/null @@ -1,26 +0,0 @@ -# 02-开发计划 - -## 一、模块依赖表 - -| 模块 ID | 模块名 | 依赖模块 | 依赖表 | -|---|---|---|---| -{{#each modules}} -| {{id}} | {{name}} | {{deps}} | {{tables}} | -{{/each}} - -## 二、开发顺序清单(CC 分发权威) - -> 本清单由 A5 `downstream-gen` 一次性生成。**每行是一个 REQ**,不是模块。Coding 阶段(`coding.mjs` 的 Router)按表格行序确定模块顺序,对每个 REQ 所属模块查 `docs/08 § 二` 的 `里程碑:` 字段 + 本地 `git tag -l 'milestone/'`:tag 存在则跳过,否则(`—` / tag 不存在)选为待跑模块;顶层循环对每个待跑后端模块依次跑功能链(spec→plan→tdd→verify→review)+ 测试闸 + 里程碑,把该模块的所有 REQ 一次做完。 -> -> **约束**:同一模块的所有 REQ 必须**连续排列**。允许打破依赖拓扑(如环依赖、业务必须先做),但必须在「备注」列写明原因。 - -| # | REQ | 所属模块 | 选中理由 | 备注 | -|---|-----|---------|---------|------| -{{#each req_order}} -| {{index}} | **{{req_id}}** | {{module_id}} | {{rationale}} | {{note}} | -{{/each}} - -> **后端模块全部打里程碑后**:`coding.mjs` 的 Router 把全部未完成前端 FE 聚合为**唯一一个** `frontend-phase` 阶段,排在所有后端模块之后由顶层循环跑(prototype/ 门禁已在 Plan 期 A6 `frontend-scope-lock` 前移完成)。前端阶段以业务功能(不是 HTML 文件数)为粒度拆分 FE(FE-NN,路径限 `frontend/`),每个 FE 跑一次功能链,整个阶段打 **1 个**里程碑 tag(分支 `frontend-phase`,`milestone/frontend-phase`,记录在 `docs/08 § 三 整体里程碑`)。 - -## 三、关键说明 -{{notes}} diff --git a/skills/downstream-gen/templates/docs-05-endpoint-template.md b/skills/downstream-gen/templates/docs-05-endpoint-template.md deleted file mode 100644 index 91a1fda..0000000 --- a/skills/downstream-gen/templates/docs-05-endpoint-template.md +++ /dev/null @@ -1,12 +0,0 @@ -### {{req_id}} {{title}} - -- **Method**: {{method}} -- **Path**: `{{path}}` -- **Auth**: {{auth}} -- **请求**: {{request_summary}} -- **响应**: {{response_summary}} - -#### 错误码 -{{#each errors}} -- `{{code}}` — {{message}} -{{/each}} diff --git a/skills/downstream-gen/templates/docs-05-header-template.md b/skills/downstream-gen/templates/docs-05-header-template.md deleted file mode 100644 index e89cc3d..0000000 --- a/skills/downstream-gen/templates/docs-05-header-template.md +++ /dev/null @@ -1,30 +0,0 @@ -# 05-API接口契约 - -BasePath: `{{base_path}}` -端口: `【人工填写:后端端口,默认 8080】` - -## 全局约定 - -### 响应格式 -```json -{"code": 200, "message": "操作成功", "data": {}, "timestamp": 1700000000000} -``` - -### 错误码 -| 范围 | 含义 | -|---|---| -| 200 | 成功 | -| 400xx | 客户端参数错误 | -| 401xx | 认证/授权错误 | -| 403xx | 权限不足 | -| 404xx | 资源不存在 | -| 500xx | 服务端内部错误 | - -### 鉴权 -{{auth_note}} - -### 分页参数 -{{pagination_note}} - -## 接口清单 -(各模块接口段落见下方,由 `downstream-gen` 按 REQ 填入) diff --git a/skills/downstream-gen/templates/docs-06-module-pagelist-template.md b/skills/downstream-gen/templates/docs-06-module-pagelist-template.md deleted file mode 100644 index 36f18a5..0000000 --- a/skills/downstream-gen/templates/docs-06-module-pagelist-template.md +++ /dev/null @@ -1,9 +0,0 @@ -### {{module_id}} {{module_name}} - -{{#each pages}} -- **{{page_name}}** (`{{route}}`) - - 类型: {{page_type}} (列表页 / 表单页 / 详情页 / 树形管理页) - - 对应 REQ: {{req_ids}} - - 入口菜单: {{menu_path}} - - 主要交互: {{interactions}} -{{/each}} diff --git a/skills/downstream-gen/templates/docs-08-module-row-template.md b/skills/downstream-gen/templates/docs-08-module-row-template.md deleted file mode 100644 index edd15f1..0000000 --- a/skills/downstream-gen/templates/docs-08-module-row-template.md +++ /dev/null @@ -1,6 +0,0 @@ -- {{module_id}} {{module_name}} - - 依赖: {{depends_on}} - - 路径: {{path_scopes}} - - 里程碑: — - - 功能: -{{req_checklist}} diff --git a/skills/downstream-gen/templates/docs-10-header-template.md b/skills/downstream-gen/templates/docs-10-header-template.md deleted file mode 100644 index 4440bff..0000000 --- a/skills/downstream-gen/templates/docs-10-header-template.md +++ /dev/null @@ -1,16 +0,0 @@ -# 10-验收检查清单 - -通用验收项(全项目适用): - -- [ ] `node scripts/test.mjs` 本地全绿 -- [ ] 所有 schema 改动都有对应 `sql/migrations/V_n__.sql` -- [ ] 所有新接口在 `docs/05` 中有契约定义 -- [ ] 所有新功能代码注释含 REQ-XXX-NNN -- [ ] 统一响应格式 `{code, message, data, timestamp}` -- [ ] 异常走全局处理器,不暴露堆栈到前端 -- [ ] 前端不存敏感信息到 localStorage - -> 本文档仅维护项目级验收 SOP。粒度更细的验收信息分散在: -> - **每 REQ 的业务验收点**:`docs/01-需求清单//.md § 验收` -> - **每模块的实测验收(数据 / UI / 自动化用例位置)**:由 B 阶段 coding.mjs 的 module-report stage 在该模块完成时填入模块完成报告 -> - **REQ 开发进度(review stage approve 状态)**:`docs/08 § 二` diff --git a/skills/frontend-scope-lock/SKILL.md b/skills/frontend-scope-lock/SKILL.md deleted file mode 100644 index 1fa8942..0000000 --- a/skills/frontend-scope-lock/SKILL.md +++ /dev/null @@ -1,130 +0,0 @@ ---- -name: frontend-scope-lock -description: A6 前端范围锁定(Plan 期)——检查项目根 prototype/*.html,从 prototype + docs/01 REQ 卡片 + docs/05/06 提炼项目级 UI 约定、Design Tokens、组件库选型,逐项 AskUserQuestion 确认后写入 docs/06(UI 交互规范)+ docs/04(前端栈),并为每个 FE-NN 锁定设计决策表。把全部前端歧义前移到 Plan 期问清,使 Coding 阶段前端循环无需再弹窗。 -user-invocable: false -allowed-tools: Read Write Edit Glob Grep Skill AskUserQuestion ---- - -**所有输出必须使用中文。** - -# frontend-scope-lock - -A6 是 **Plan 阶段最后一个前端守门 skill**,由 `plan-start` 在 A5(downstream-gen)完成后派发。 - -**定位**:把原 Coding 阶段晚到的前端闸(`frontend-start` 的 prototype 检查 + `fe-feature-brainstorm` / `fe-feature-plan` 的交互式 Q&A)整体**前移到 Plan 期**。Plan 期允许 `AskUserQuestion` 问人;问清后写入 SSoT(docs/06 + docs/04),Coding 阶段的前端循环只读不问。 - -## 阶段范围 - -锁定**项目级**前端契约:UI 约定 / Design Tokens / 组件库选型 + 每个 FE-NN 的设计决策。**不涉及** SQL / migration / controller / service / DTO(后端范畴),也**不在此实现**任何页面代码(Coding 阶段做)。 - -## 执行步骤 - -> **关于 AskUserQuestion**:下文只描述「问什么、给哪些选项、各选项导向什么后续」。`header` / 各选项的 `description` / `multiSelect` 等具体参数由你按工具 schema 自行填全合法值——不要把下文的选项文字当成完整调用照抄。 - -### 步骤 0:打印当前位置流程图 - -向用户**直接输出**(模型自己打印,不调 bash / cat)当前位置: - -``` -┌────────────────────────────────────────────────────────┐ -│ 📋 阶段 A:规划(一次性) │ -│ A0 初始化 → A1 锁范围 → A2 骨架 → A3 DB 设计 │ -│ → A4 DB 初始化 → A5 下游文档 │ -│ ▶ A6 前端范围锁定(prototype + tokens + 约定) │ -│ 规划阶段到此结束 │ -└────────────────────────────────────────────────────────┘ -``` - -### 步骤 1:检查 prototype(缺失则在此问) - -用 `Glob` 检查项目根 `prototype/**/*.html`: - -- **至少 1 个 `.html`** → 通过,记下文件清单,进入步骤 2。 -- **0 个** → 这是 Plan 期,**可以问**。用 `AskUserQuestion` 告知用户「未在 prototype/ 找到任何 .html 原型,前端范围锁定依赖原型作为页面骨架权威」,给「我已补齐原型,请重新检查」和「本项目无前端,跳过 A6」两个选项。 - - 选「已补齐」→ 重新 `Glob`:命中则进入步骤 2,仍为 0 则重复本问。 - - 选「无前端」→ 在 docs/08 § 一 把 A6 的**父项 + 全部 3 个子项**一并勾选并在父项行尾注明「(无前端,A6 跳过)」,打印步骤 6 的终止横幅(产出标注「跳过」),**停止**,不写 docs/06 / docs/04。 - > 必须同时勾子项:`plan-start` 的分发依据是「§ 一 第一个未勾 [ ] 子项」,若只勾父项会让下一次 plan-start 重复派发回本 skill,无前端项目无法满足 Plan 终结闸。具体要勾的子项: - > - ` - [x] docs/06 项目级 UI 约定 + Design Tokens + 组件库已锁定(无前端跳过)` - > - ` - [x] docs/04 § 二 前端栈已锁定(引用 docs/06)(无前端跳过)` - > - ` - [x] 各 FE-NN 设计决策表已生成(docs/06 § 三之后 / docs/08 § 三)(无前端跳过)` - -### 步骤 2:收集证据(只读,不问) - -为提炼项目级约定,`Read` 以下来源: - -- **prototype/**:所有 `*.html`,作为页面布局 / 组件 / 交互的**实测权威**(DOM 结构、表单展现、列表范式、状态色实例)。 -- **docs/01-需求清单/**:各 `_module.md` + `REQ-*.md`,提取 UI 描述、业务校验、acceptance 中与界面相关的部分。 -- **docs/05-API接口契约.md**:端点列表,确认前端要消费的接口集合(影响页面状态机 / 加载态)。 -- **docs/06-UI交互规范.md**:已有的通用交互规则(§ 一)、Design Tokens(§ 二)、页面清单(§ 三 由 A5 填)。布局以项目根 `prototype/` 为权威,docs/06 不设独立布局小节。本 skill 在此基础上**收敛 / 补全**,不推翻已确认内容。 -- **docs/04-技术规范.md § 零**:技术栈表里的前端行(如 `前端 UI 组件` = Ant Design),作为组件库选型默认值来源。 - -把证据归纳为三组**草案**:(a) 项目级 UI 约定、(b) Design Tokens(全局调色板 + 组件级状态色)、(c) 组件库选型。草案优先复用 docs/06 / docs/04 既有值(已锁定的不重问),仅对 prototype 与现文档**不一致**或**缺失**的点进入步骤 3 确认。 - -### 步骤 3:逐项 AskUserQuestion 确认 - -**一次一问**,仅对真歧义点。每问给出「从证据提炼的默认值」让用户**确认 / 覆盖**,不造无意义确认题。建议覆盖(无歧义的项直接采用默认值,不弹问): - -1. **UI 约定**:整体布局骨架、最小视口 / 响应式策略、列表页范式、表单展现阈值(Modal / Drawer / 独立页)、操作反馈范式、数据展示约定、前端权限控制方式。 -2. **Design Tokens**:全局调色板语义→变量→默认值;组件级状态色表(编辑 / 只读 / 悬浮 的 bg/fg)。prototype 中出现但未登记的色值 → 问是否新增 token。 -3. **组件库选型**:UI 组件库 + 版本(默认取 docs/04 § 零)、主题接入方式、图标库、表格 / 表单是否二次封装。 - -每个确认结果即时记入对应草案。**绝不**留 `【人工填写:】` / `{{占位}}` / `TBD` 作为最终值。 - -### 步骤 4:写入 docs/06 + docs/04 - -用 `${CLAUDE_SKILL_DIR}/templates/fe-scope-template.md` 作为填充骨架,把步骤 3 确认后的真实值填入(剥掉模板内 HTML 注释),分别落盘: - -- **docs/06-UI交互规范.md**(用 `Edit` 合并,不另起文件;小节编号以 `skeleton-gen/templates/docs-06-static-template.md` 为权威:§ 一 通用交互规则 / § 二 Design Tokens / § 三 页面清单): - - 模板 § 一 → 收敛 / 补全 docs/06 § 一(通用交互规则)的项目级约定。 - - 模板 § 二 → 写入 / 校正 docs/06 § 二(Design Tokens 全局调色板 + 组件级状态色 + Token 默认值),与 `src/styles/tokens.css` 命名规范(docs/04 § 2.5)一致。 - - 模板 § 五 → 追加到 docs/06 § 三(页面清单)之后,作为 **FE 级设计决策表**:FE 清单来自 docs/08 § 三(若 § 三 尚无 FE bullet,则在此按 prototype + docs/01 + docs/05 推导 FE 清单并**同时写入 docs/08 § 三**「功能:」项,行格式见 docs/08 模板)。一 FE 一行。 -- **docs/04-技术规范.md § 二(前端编码规范)**(用 `Edit`): - - 把组件库选型 + 模板 § 四前端栈摘要写入 / 校正 § 2.3(组件 / 页面编写规范)与 § 2.5(样式与主题)的引用说明;色值约定指向 docs/06 § 二。 - - 不重复抄 docs/06 全文,只写「前端组件库 = X、tokens 锁定于 docs/06 § 二」这类引用,保持 SSoT。 - -写入时遵循模板的字面安全约定:值含 `$` / `{` / `}` 等字符**原样写入**,不做二次解释。 - -### 步骤 5:自审(inline 修,不等用户) - -- 模板五节均已填充,**无** `{{...}}` / `【人工填写:】` / `TBD` 残留(`Grep` 校验 docs/06 + docs/04 本次写入区域)。 -- 组件库选型与 docs/04 § 零前端行一致;如确认值覆盖了 § 零默认值,回写 § 零保持一致。 -- docs/06 § 五 / docs/08 § 三 的 FE-NN 集合一致,每个 FE 行字段非空。 -- 命中残留 → 就地修正后重新校验;无法自决的歧义 → 回步骤 3 补问。 - -### 步骤 6:勾选 docs/08 + 终止横幅 - -1. 用 `Edit` 在 `docs/08-模块任务管理.md § 一` 勾选 A6 子项 + 父项: - - ` - [ ] docs/06 项目级 UI 约定 + Design Tokens + 组件库已锁定` - - ` - [ ] docs/04 § 二 前端栈已锁定(引用 docs/06)` - - ` - [ ] 各 FE-NN 设计决策表已生成(docs/06 § 三之后 / docs/08 § 三)` - - `- [ ] A6 前端范围锁定 — frontend-scope-lock` -2. 向用户**直接输出**终止横幅并**停止**(不自动进入 B 阶段,回交给 plan-start 的终结闸判定): - -``` -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - [frontend-scope-lock] ✅ A6 前端范围锁定完成 - - 产出: - ✓ docs/06 § 一 项目级 UI 约定(通用交互规则) - ✓ docs/06 § 二 Design Tokens(全局调色板 + 组件级状态色) - ✓ docs/06 § 三之后 各 FE-NN 设计决策表 - ✓ docs/04 § 二 前端栈 + 组件库选型(引用 docs/06) - - 前端契约已全部锁定,Coding 阶段前端循环将只读不问。 - - Plan 阶段(A0~A6)到此结束。请运行 /erp-workflow:plan-start - 让终结闸校验全部前移闸门是否通过,再进入 B 阶段。 -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ -``` - -## 参考 - -- `${CLAUDE_SKILL_DIR}/templates/fe-scope-template.md`(产出骨架) -- `prototype/**/*.html`(页面骨架实测权威,步骤 1 前置门由本 skill 自承) -- `docs/01-需求清单/**/*.md`(UI 描述 / 业务校验来源) -- `docs/05-API接口契约.md`(前端消费端点) -- `docs/06-UI交互规范.md`(写入目标:§ 一 通用交互约定、§ 二 Tokens、§ 三之后 FE 决策表) -- `docs/04-技术规范.md § 二 / § 零`(前端栈 + 组件库选型写入目标) -- `docs/08-模块任务管理.md § 一`(A6 进度勾选)/ `§ 三`(FE 清单) -- 上游:`plan-start`(A5 完成后派发到此) -- 下游:`plan-start` 终结闸(A6 完成后回交校验);Coding 阶段 `workflows/coding.mjs` 前端循环消费本 skill 的产出 diff --git a/skills/frontend-scope-lock/templates/fe-scope-template.md b/skills/frontend-scope-lock/templates/fe-scope-template.md deleted file mode 100644 index bb8bd6a..0000000 --- a/skills/frontend-scope-lock/templates/fe-scope-template.md +++ /dev/null @@ -1,65 +0,0 @@ - -## 一、项目级 UI 约定 - -> 来源:prototype/*.html 实测 + docs/01 REQ 卡片 UI 描述 + docs/06 已有布局。经用户确认。 - -| 约定项 | 锁定值 | 依据 | -| --- | --- | --- | -| 整体布局骨架 | {{LAYOUT_SKELETON}} | {{LAYOUT_SOURCE}} | -| 最小支持视口 / 响应式策略 | {{VIEWPORT_POLICY}} | {{VIEWPORT_SOURCE}} | -| 列表页交互范式 | {{LIST_PATTERN}} | {{LIST_SOURCE}} | -| 表单展现规则(Modal / Drawer / 独立页阈值) | {{FORM_PATTERN}} | {{FORM_SOURCE}} | -| 操作反馈范式(成功 / 失败 / 二次确认) | {{FEEDBACK_PATTERN}} | {{FEEDBACK_SOURCE}} | -| 数据展示约定(状态 / 日期 / 金额 / 空值 / 操作列) | {{DISPLAY_PATTERN}} | {{DISPLAY_SOURCE}} | -| 前端权限控制方式 | {{AUTH_PATTERN}} | {{AUTH_SOURCE}} | - -## 二、Design Tokens - -> 单元格写 token 名(`--color-xxx`),不写裸 hex;色值默认值落地于 `src/styles/tokens.css`。命名规范见 docs/04 § 2.5。 - -### 2.1 全局调色板 - -| 语义 | 变量名 | 默认值 | 用途 | -| --- | --- | --- | --- | -| {{TOKEN_SEMANTIC}} | {{TOKEN_VAR}} | {{TOKEN_VALUE}} | {{TOKEN_USAGE}} | - -### 2.2 组件级状态色 - -| 序号 | 组件 | 编辑 bg | 只读 bg | 悬浮 bg | 编辑 fg | 只读 fg | 悬浮 fg | 备注 | -| --- | --- | --- | --- | --- | --- | --- | --- | --- | -| {{COMP_NO}} | {{COMP_NAME}} | {{COMP_BG_EDIT}} | {{COMP_BG_READONLY}} | {{COMP_BG_HOVER}} | {{COMP_FG_EDIT}} | {{COMP_FG_READONLY}} | {{COMP_FG_HOVER}} | {{COMP_NOTE}} | - -## 三、组件库选型 - -| 项 | 锁定值 | 依据 / 备注 | -| --- | --- | --- | -| 前端 UI 组件库 | {{UI_LIB}} | {{UI_LIB_SOURCE}} | -| 版本 | {{UI_LIB_VERSION}} | 与 docs/04 § 零 一致 | -| 主题接入方式 | {{UI_LIB_THEME}} | 如 ConfigProvider.theme.token 引用 § 二全局调色板 | -| 图标库 | {{ICON_LIB}} | {{ICON_LIB_SOURCE}} | -| 表格 / 表单封装策略 | {{WRAP_STRATEGY}} | 是否二次封装、统一 props 约定 | - -## 四、前端栈摘要(同步 docs/04 § 二) - -| 分层 | 技术 | 版本 | 说明 | -| --- | --- | --- | --- | -| {{FE_LAYER}} | {{FE_TECH}} | {{FE_VERSION}} | {{FE_NOTE}} | - -## 五、各 FE 设计决策表 - -> 一 FE 一行,FE 清单来自 docs/08 § 三。每行锁定该 FE 的页面骨架来源、页面类型、组件库选型与状态机要点,供 Coding 阶段前端循环直接消费(不再二次问人)。 - -| FE-NN | 功能名 | 关联 REQ | 关联原型 | 页面类型 | 核心组件树要点 | 关键状态机(loading/empty/error/正常/提交中) | 引用 Design Tokens | -| --- | --- | --- | --- | --- | --- | --- | --- | -| {{FE_ID}} | {{FE_NAME}} | {{FE_REQS}} | {{FE_PROTOTYPES}} | {{FE_PAGE_TYPE}} | {{FE_COMPONENT_TREE}} | {{FE_STATE_MACHINE}} | {{FE_TOKENS}} | diff --git a/skills/plan-start/SKILL.md b/skills/plan-start/SKILL.md deleted file mode 100644 index 67bac3b..0000000 --- a/skills/plan-start/SKILL.md +++ /dev/null @@ -1,145 +0,0 @@ ---- -name: plan-start -description: A 阶段(Plan)入口与分发器。根据 docs/08 § 一 的 checkbox 状态派发到 A0~A6 对应 skill。Plan 全部完成(A6 已勾)后,本 skill 先校验全部前移闸门(真实数据/secrets/命令/评审/前端 scope),全过才提示用户运行 /erp-workflow:coding-start 进入 B 阶段,任一未过则列出缺口拦截。 -user-invocable: true -allowed-tools: Skill Read Glob Grep ---- - -**所有输出必须使用中文。** - -你是 ERP 项目**规划阶段的编排器**。你**只派发 A 阶段(A0~A6)的 skill**;docs/08 § 一 全部勾选后,你**不立即放行**——先执行 §2.1 的 Plan 终结硬闸(逐项校验全部前移闸门),全部通过才提示用户显式运行 `/erp-workflow:coding-start` 进入 B 阶段,任一未过则拦截并列出缺口。你不直接生成任何文件。 - -## 第一步:读取 docs/08 + 决定分发目标 - -docs/08 § 一 是**Plan 阶段进度追踪**(A0~A6 的 checkbox)。§ 二的模块元数据由 coding-start 读写,本 skill 不读。 - -### 分发判定 - -1. **docs/08 是否存在** - 用 `Glob` 检查 `docs/08-模块任务管理.md`。 - - 如果不存在 → 后续 = `project-init`。 - -2. **根据 § 一 找到当前进度** - - **判定算法(务必按此执行,不要凭"表里含 Axx"判断;docs/08 § 一 模板始终列出 A0~A6 全部行,"含"恒为真)**: - - 用 Read / Grep 把 `docs/08-模块任务管理.md § 一` 全文读出,按文件顺序自上而下扫描,找到**第一个 `- [ ]` 未勾子项**(仅看 § 一,§ 二 / § 三 不参与判定)。 - - 该子项归属的父项 `Axx`(A0~A6)即为当前阶段,按下表派发到对应 skill。 - - 若 § 一 所有 `[ ]` 都已变成 `[x]`(含父项与全部子项)→ 进入 §2.1 Plan 终结闸。 - -| `第一个未勾子项归属` | `后续` | `阶段` | -|---|---|---| -| 无 docs/08(文件不存在) | `project-init` | `A0` | -| A0 父项或其任一子项 | `project-init` | `A0` | -| A1 父项或其任一子项 | `scope-lock` | `A1` | -| A2 父项或其任一子项 | `skeleton-gen` | `A2` | -| A3 父项或其任一子项 | `db-design-gen` | `A3` | -| A4 父项或其任一子项 | `db-init` | `A4` | -| A5 父项或其任一子项 | `downstream-gen` | `A5` | -| A6 父项或其任一子项 | `frontend-scope-lock` | `A6` | -| § 一 全部 `[x]` | **无分发** → §2.1 Plan 终结闸 | - | - -## 第二步:分发通知 + 调用目标 skill - -### 2.1 Plan 已完成 — 终结硬闸(HARD GATE) - -A 阶段所有 checkbox 均 `[x]` 时**不代表可以进 B 阶段**。Coding 阶段为全自动静默 Workflow(子代理无法弹窗问人),因此**所有需求/配置必须在 Plan 期锁死**。本步骤是**硬闸**:先逐项校验下列全部前移闸门,**全部通过**才提示用户运行 `coding-start`;**任一未过**则**不提示进 B 阶段**,转而列出缺口并指明回填位置。 - -#### 第 1 步:逐项校验前移闸门(用 Read / Glob / Grep,禁止跳过任何一项) - -逐项检查,记录每项 `通过` / `缺口`。任一缺口即整闸 `不通过`。 - -1. **REQ 卡片真实数据**(来自 A1 scope-lock) - - `Glob` 找出全部 REQ 卡片(如 `docs/01-需求清单/**/*.md`)。 - - 对每张卡片 `Grep` 残留占位:命中任一即缺口 — - `【人工填写`、`TBD`、`待补`、`<示例`、`【示例行`(与 scope-lock E.1 同强度——`<示例` 兜底 `<示例值>`,`【示例行` 兜底未删的模板示例行 `【示例行,替换为真实字段】`;避免半填卡片绕过本闸)。 - - 缺口表述示例:`REQ-USER-001 仍含 TBD / 示例值未替换为真实约束 / 示例行未删除`。 - -2. **secrets / 项目配置全锁**(来自 A1 收集的 secret/account/package-name/namespace 清单) - - `Read` `.env.local`(真实 secret 值所在;gitignored,docs/07 只记规则不记值):校验 `config-vars.yaml` 的 `secrets_ref` 列出的每个 secret 键(如 `DB_PASSWORD` / `JWT_SECRET`)均有真实值,无 `【人工填写`/`TBD`/空值。 - - `Read` `config-vars.yaml`(非敏感项目级配置):校验包名 / namespace / 端口 / 初始账号等字段均已填,无 `【人工填写`/`TBD`。 - - 任一未填即缺口。(docs/07-环境配置.md 仅承载规则/约定,不参与值校验。) - -3. **docs/04 §零 命令齐**(来自 A1 收集的每栈构建/lint/单测/e2e 命令) - - `Read` `docs/04-技术规范.md`,定位 `§ 零` 命令区。 - - 校验:每个技术栈的 build / lint / unit / e2e 命令均显式存在且非占位。缺命令或留 `TBD` 即缺口(Coding 期 test-gate / featureLoop 依赖这些命令,缺即无法静默跑)。 - -4. **docs/05 + docs/02 已评审**(来自 A5 downstream-gen 的评审闸) - - `Read` `docs/05-API接口契约.md` 与 `docs/02-开发计划.md`。 - - 校验:(a) docs/05 每个端点都有请求/响应 schema、无 `【人工填写`/`TBD`;(b) docs/02 每个 REQ 都在构建顺序 DAG 中、cycle-breaking 顺序有 `note` 说明。缺任一即缺口。(A5 父项已勾本身即蕴含 downstream-gen 评审闸已过——downstream-gen 在用户未确认时禁止勾 A5,故无需独立的「已评审」标记。) - -5. **A6 前端 scope 已锁**(来自 A6 frontend-scope-lock) - - **无前端项目分支**:先 `Read` `docs/08-模块任务管理.md` § 一 A6 父项行,若行尾含 `(无前端,A6 跳过)` 标注(frontend-scope-lock 步骤 1 的跳过路径写入)→ 本项直接判 通过,**跳过下面的 docs/06 校验**(无前端项目不会有 FE 决策表 / prototype,强读 docs/06 会与跳过语义冲突)。 - - 否则(有前端):`Read` `docs/06-UI交互规范.md`,校验项目级 UI 约定 / Design Tokens / 组件库选型已确认;每个 FE-NN 的设计决策表非占位;prototype 闸门已过(docs/08 § 一 A6 勾选即代表此项已由 A6 skill 锁定,但仍核对 docs/06 无 `【人工填写`/`TBD` 残留)。缺任一即缺口。 - -#### 第 2 步(A):全部通过 → 放行 - -仅当第 1 步 **5 项全部 `通过`** 时,向用户输出完成横幅: - -``` -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - [plan-start] ✅ Plan 阶段全部完成,前移闸门全部通过 - - 已校验通过: - ✓ REQ 卡片均为真实数据(无占位/示例残留) - ✓ .env.local secrets + config-vars.yaml(account/package/namespace)全锁 - ✓ docs/04 §零 各栈 build/lint/unit/e2e 命令齐全 - ✓ docs/05 API 契约 + docs/02 构建顺序已评审 - ✓ A6 前端 scope(UI 约定 / tokens / 组件库)已锁 - - ⚠️ 进入 B 阶段前必须完成: - 1. 人工通读 docs/* + CLAUDE.md + sql/migrations/V1 + 各 scripts/* - - 2. 把全部 Plan 产物 commit 到本地默认分支(main / master): - git add -A && git commit -m "chore: plan phase A0~A6 done" - - 3. B 阶段全程纯本地(无需远程仓库 / push / MR): - 每个模块由 coding.mjs 的 milestone stage 本地 merge 进默认分支并打 milestone/ tag。 - 确认当前已在本地默认分支(main / master)上即可。 - - 4. 运行 /erp-workflow:coding-start 进入 B 阶段 -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ -``` - -不调任何下游 skill。 - -#### 第 2 步(B):存在缺口 → 拦截,**不提示进 B 阶段** - -只要第 1 步出现**任一缺口**,**禁止**输出上面的放行横幅、**禁止**提示运行 `coding-start`。改为输出拦截横幅,逐条列出缺口与回填位置,让用户先补齐: - -``` -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - [plan-start] ⛔ Plan 终结闸未通过 — 暂不能进入 B 阶段 - - Coding 阶段全自动静默,缺失项无法在编码期补问,必须现在锁死。 - 以下缺口需补齐后重新运行 /erp-workflow:plan-start: - - <逐条列出每个缺口,格式:[闸门] 缺口描述 → 回填位置> - 例: - [REQ 真实数据] REQ-USER-001 输入字段「示例值」列仍为模板占位 → docs/01-需求清单/... - [secrets] DB_PASSWORD 未填 → .env.local - [docs/04 §零] node 栈缺 e2e 命令 → docs/04-技术规范.md §零 - - 补齐后再次运行 /erp-workflow:plan-start 重新校验。 -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ -``` - -输出拦截横幅后**停下**,不调任何下游 skill,不提示 coding-start。 - -### 2.2 正常派发(`后续` 非空) - -打印简短分发通知: - -``` -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - [plan-start] → 派发到 <后续> - 未勾项: -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ -``` - -立即用 `Skill` 工具调用 `后续`。 - -## 参考 - -- `docs/08-模块任务管理.md`(进度追踪) -- `CLAUDE.md`(项目指令) -- 后续 skills(通过 `Skill` 工具按名称调用) diff --git a/skills/plan/db-design-gen/SKILL.md b/skills/plan/db-design-gen/SKILL.md new file mode 100644 index 0000000..ce41b6e --- /dev/null +++ b/skills/plan/db-design-gen/SKILL.md @@ -0,0 +1,121 @@ +--- +name: db-design-gen +description: A3 DB 设计 + REQ 回填——基于 docs/01-需求清单//REQ-*.md 正向设计 docs/03-数据库设计文档.md(业务实体 → 表 + 字段 + 索引 + 外键 + 业务注记),并把回填值写入 REQ 卡片的「依赖表: TBD(A3 自动补)」与模块头的「涉及表: TBD(A3 自动补)」占位。生成完毕停下等人工审阅。 +user-invocable: false +allowed-tools: Read Write Edit Grep Glob AskUserQuestion +--- + +**所有输出必须使用中文。** + +# db-design-gen + +## 前置条件 + +- A1 `scope-lock` 已完成:`docs/01-需求清单//_module.md` + `docs/01-需求清单//REQ-*.md` 已生成,含 `TBD(A3 自动补)` 占位。 +- A2 `skeleton-gen` 已完成:`docs/04-技术规范.md § 一+` 命名规范已生成(本 skill 推导表/字段命名时严格遵循)。 + +## 执行步骤 + +### 步骤 A0:确认 ERP schema 约定(一次性) + +在正向设计 schema 之前,**先确认本项目的 3 项数据库约定**。默认值即现 ERP 约定,用户可逐项覆盖。结果写入 `docs/04` + `CLAUDE.md`,本 skill 后续步骤(B/C)严格引用确认后的值,不再字面写死。 + +> 先用 `Grep` 检查 `docs/04-技术规范.md` 是否已含 `## 四、数据库 schema 约定` 节。**已存在则视为本约定已确认**,跳过本步骤直接读取该节作为 `PK_CONVENTION` / `TENANT_COLS` / `COL_PREFIX_RULE` 的值,进入步骤 A。 + +用 `AskUserQuestion` 一次性提出以下 3 个问题(每题给「沿用默认」与「自定义」两类选项;选自定义时追问具体值): + +1. **主键约定(PK_CONVENTION)** + - 默认(沿用 ERP):`iIncrement` int 整数主键(自增方式由实现决定:DB `AUTO_INCREMENT` 或应用/触发器分配),另设 `sId` varchar(100) 业务 ID 对外暴露。 + - 自定义:用户给出主键列名 / 类型 / 生成策略(如复合主键 / UUID / 业务主键)。 + +2. **租户隔离列(TENANT_COLS)** + - 默认(沿用 ERP):`sBrandsId` varchar(100)(品牌 ID,多租户隔离)+ `sSubsidiaryId` varchar(100)(子公司 ID,组织层级隔离),默认值均为 `1111111111`。 + - 自定义:用户给出租户列名 / 类型 / 默认值,或声明本项目不做多租户隔离(此时 TENANT_COLS = 「无」)。 + +3. **列命名前缀规则(COL_PREFIX_RULE)** + - 默认(沿用 ERP):匈牙利前缀——`i` = int、`s` = varchar、`t` = datetime。 + - 自定义:用户给出自己的前缀/命名规则,或声明不使用前缀(此时 COL_PREFIX_RULE = 「无前缀,列名直接用业务语义」)。 + +得到三项确认值后: + +- **写入 `docs/04-技术规范.md`**:用 `Grep` 确认无 `## 四、数据库 schema 约定` 节后,用 `Edit` 在文末追加该节,列出 `PK_CONVENTION` / `TENANT_COLS` / `COL_PREFIX_RULE` 三项的确认值(每项含列名/类型/默认值/生成策略的完整描述)。 +- **写入 `CLAUDE.md`**:用 `Edit` 在「Schema 演化规约」节末尾追加一条「数据库 schema 约定(A3 确认)」小节,简述三项约定,并注明「详见 `docs/04 § 四`」。 + +后续步骤 B/C 用到 `{{PK_CONVENTION}}` / `{{TENANT_COLS}}` / `{{COL_PREFIX_RULE}}` 处,一律引用此处确认后的值。 + +### A. 读取设计输入 + +读: + +- `docs/04-技术规范.md` +- `docs/01-需求清单/index.md` 模块索引 +- `docs/01-需求清单/*/REQ-*.md` 所有 REQ 卡片 + +### B. 推导 schema + +基于步骤 A 读到的 REQ + 命名规范,**正向推导**业务实体 → 表 + 字段 + 索引 + 外键。要求: + +1. 严格套用 `docs/04` 的命名规范 + 步骤 A0 确认的 `COL_PREFIX_RULE` 列命名前缀规则 +2. **主键**:套用步骤 A0 确认的 `PK_CONVENTION`。REQ 明确要求与确认约定不同的主键(复合主键 / UUID / 业务主键)时按 REQ,并在该表业务注记里注明偏离原因 +3. **外键**:依据 REQ 中的引用关系(如「订单引用客户」),明确列出 `ON DELETE` / `ON UPDATE` 策略;不能确定时默认 `RESTRICT` +4. **索引**:根据 REQ 的查询模式推导业务索引;外键列默认建索引;步骤 A0 确认的 `TENANT_COLS` 租户隔离列(若非「无」),按业务查询模式建组合索引 +5. **业务注记**:对每张表用一两句话说明业务用途、关键约束、与其他表的关系 + +如果某 REQ 表述模糊以致无法推断关键 schema 细节(如:枚举值范围 / 字段长度上限 / 必填性),先按合理默认推导并在该字段「业务含义」列加 `【人工填写:需用户审阅】` 标注,待步骤 E 用户审阅时调整;**不打断本次推导**。 + +### C. 渲染 docs/03 + +1. 读取 `${CLAUDE_SKILL_DIR}/templates/docs-03-header-template.md`,填充 `schema_name`(从 `.env.local` 读 `DB_SCHEMA`,无则填 `【人工填写:DB_SCHEMA】`)、`er_overview`(纯文本 ER 概览),以及步骤 A0 确认的 `{{PK_CONVENTION}}` / `{{TENANT_COLS}}` / `{{COL_PREFIX_RULE}}`。 +2. 渲染「表清单」:对每张表:读取并填充 `${CLAUDE_SKILL_DIR}/templates/docs-03-table-template.md`,其中标准列区块用步骤 A0 确认的 `{{PK_CONVENTION}}` / `{{TENANT_COLS}}` 展开(`TENANT_COLS` = 「无」时不输出租户列行)。 +3. 写入 `docs/03-数据库设计文档.md`。 + +完成后,用 `Edit` 在 `docs/08-模块任务管理.md` 中勾选: +- ` - [ ] docs/03-数据库设计文档.md 已生成` + +### D. 回填模块头 + REQ 卡片的 TBD 字段 + +1. 列出 `docs/01-需求清单/*/_module.md`(模块头)和 `docs/01-需求清单/*/REQ-*.md`(REQ 卡片)。 +2. 在这些文件中搜索 `TBD(A3 自动补)` 的并回填。 不动 `TBD(A5 自动补)` +3. 打印回填统计:`A3 回填 处模块"涉及表" + 处 REQ"依赖表"`。 + +完成后,用 `Edit` 在 `docs/08-模块任务管理.md` 中勾选: +- ` - [ ] docs/01 各 REQ 卡片"依赖表" + 模块头"涉及表" 已回填` + +### E. 勾选 A3 顶层 + 停下等人工审阅 + +1. 完成后,用 `Edit` 在 `docs/08-模块任务管理.md` 中勾选 A3 顶层(A3 两个子项已在 C / D 步骤分别勾选): + - `- [ ] A3 DB 设计 + REQ 回填 — db-design-gen` + +2. 打印停下横幅并**停下**: + + ``` + ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + [db-design-gen] ✅ A3 DB 设计完成 + + 产出: + ✓ docs/03-数据库设计文档.md + ✓ docs/01-需求清单//REQ-*.md 依赖表已回填 + _module.md 涉及表已回填 + + ⏸ 现在请你审阅 docs/03。 + 重点关注: + - 业务实体覆盖是否完整 + - 字段类型 / 长度 / 是否可空 / 默认值是否合理 + - 索引是否覆盖主要查询模式 + - 外键 ON DELETE / ON UPDATE 策略是否符合业务 + - 字段「业务含义」列含 `【人工填写:需用户审阅】` 标注的位置需逐一确认 + + 审阅完成后,再运行: + /erp-workflow:plan-start + + ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + ``` + + **停止**,不调用任何下游 skill。 + +## 参考 + +- `${CLAUDE_SKILL_DIR}/templates/docs-03-header-template.md` +- `${CLAUDE_SKILL_DIR}/templates/docs-03-table-template.md` +- `docs/04-技术规范.md` § 一+(命名规范输入) +- `docs/01-需求清单//_module.md`(模块头:回填 `涉及表`) +- `docs/01-需求清单//REQ-*.md`(REQ 输入 + 回填 `依赖表`) diff --git a/skills/plan/db-design-gen/templates/docs-03-header-template.md b/skills/plan/db-design-gen/templates/docs-03-header-template.md new file mode 100644 index 0000000..fa8507c --- /dev/null +++ b/skills/plan/db-design-gen/templates/docs-03-header-template.md @@ -0,0 +1,24 @@ +# 03-数据库设计文档 + +- **Schema**: `{{schema_name}}` +- **Migration 清单**: `sql/migrations/V*.sql`(由 Flyway 顺序 apply) +- **生成方式**: 由 A3 `db-design-gen` 基于 `docs/01-需求清单//REQ-*.md` REQ 卡片正向设计生成(schema SSoT)。 + +## 项目标准列约定 + +本项目的数据库约定(主键 / 租户隔离列 / 列命名前缀)由 A3 `db-design-gen` 在设计起始时一次性确认,确认值见 `docs/04-技术规范.md § 四、数据库 schema 约定`。下文每张业务表的字段清单都自动包含以下标准列,渲染时由 `docs-03-table-template.md` 模板按确认值展开。 + +- **列命名前缀规则**:{{COL_PREFIX_RULE}} +- **主键约定**:{{PK_CONVENTION}} +- **租户隔离列**:{{TENANT_COLS}} + +字典 / 辅助表如有豁免,在该表业务注记里注明豁免原因。 + +## ER 关系概览 + +{{er_overview}} + +## 表清单 +{{#each tables}} +- `{{table_name}}` — {{purpose}} +{{/each}} diff --git a/skills/plan/db-design-gen/templates/docs-03-table-template.md b/skills/plan/db-design-gen/templates/docs-03-table-template.md new file mode 100644 index 0000000..f43e1ea --- /dev/null +++ b/skills/plan/db-design-gen/templates/docs-03-table-template.md @@ -0,0 +1,25 @@ +## `{{table_name}}` — {{purpose}} + +### 字段 + +| 字段 | 类型 | Nullable | 默认 | 业务含义 | +|---|---|---|---|---| +{{PK_CONVENTION}} +{{TENANT_COLS}} +| `tCreateDate` | datetime | 否 | 当前时间 | 创建时间(标准列) | +{{#each columns}} +| {{name}} | {{type}} | {{nullable}} | {{default}} | {{business_meaning}} | +{{/each}} + +### 索引 +{{#each indexes}} +- `{{name}}` ({{type}}): {{columns}} +{{/each}} + +### 外键 +{{#each foreign_keys}} +- `{{name}}`: {{from_col}} → {{to_table}}.{{to_col}} ({{on_delete}}) +{{/each}} + +### 业务注记 +{{notes}} diff --git a/skills/plan/db-init/SKILL.md b/skills/plan/db-init/SKILL.md new file mode 100644 index 0000000..ea9cbbc --- /dev/null +++ b/skills/plan/db-init/SKILL.md @@ -0,0 +1,141 @@ +--- +name: db-init +description: A4 DB 初始化——LLM 解析 docs/03-数据库设计文档.md → 生成 sql/migrations/V1__initial_schema.sql(DDL only,Flyway 初始 migration)→ 用 lib/validate-ddl.mjs 全量校验 DDL ↔ docs/03 一致性 → 验证 MySQL 连接 → 调 scripts/setup-test-db.mjs 复用三层防护并 DROP+CREATE 空库 → 用 lib/apply-ddl.mjs apply V1。 +user-invocable: false +allowed-tools: Read Write Edit Glob Skill Bash(node *) Bash(mysql *) +--- + +**所有输出必须使用中文。** + +# db-init + +## 执行步骤 + +### A. DDL 生成(不依赖数据库连接) + +#### A.1 读 docs/03 并翻译为 DDL + +读取 `docs/03-数据库设计文档.md`,按字段 / 索引 / 外键 / 业务注记**严格翻译**为: + +- 每张表一段 `CREATE TABLE` +- 字段顺序与 docs/03 表格行序一致;`Nullable` 列直接映射 `NOT NULL` / `NULL`;`默认` 列映射 `DEFAULT `;列尾用 `COMMENT '<业务含义>'` 写注释 +- 索引 +- 外键:在所有表创建完成后**统一追加** + +要求: +- **严禁臆造** docs/03 中没有的表 / 字段 / 索引 / 外键 +- **严禁省略** docs/03 中已有的列、注释或约束 +- 字符集统一 `utf8mb4` + `utf8mb4_unicode_ci`,引擎统一 `InnoDB`,除非 docs/03 业务注记明确要求其他设置 + +#### A.2 落盘 V1 文件 + +用 `Write` 写 `sql/migrations/V1__initial_schema.sql`(`Write` 会自动创建缺失的父目录 `sql/migrations/`),内容 = 头部注释 + DDL 主体: + +1. **头部注释**(6 行 SQL 注释): + - `-- Flyway migration V1 — initial schema for `(从 `CLAUDE.md § 🎯 项目概述` 读) + - `-- Generated: `(UTC ISO 8601 时间戳) + - `-- Source: 由 A4 db-init 从 docs/03-数据库设计文档.md 翻译生成(schema SSoT 是 docs/03)` + - `-- This is the FIRST migration; subsequent schema changes must be written as new files sql/migrations/V2__.sql, V3__... etc.` + - `-- Apply: Flyway runs this automatically at Spring Boot startup.` + - `-- Do not hand-edit this file after it is committed; write a new migration instead.` + +2. **DDL 主体**:A.1 推导出的所有 `CREATE TABLE` → `CREATE INDEX` → `ALTER TABLE ... ADD CONSTRAINT ... FOREIGN KEY`,按此顺序拼接。 + +#### A.3 校验 V1 ↔ docs/03 5 维一致性 + 自主修正 + +调 `${CLAUDE_PLUGIN_ROOT}/lib/validate-ddl.mjs` 做跨平台、纯 Node 的 5 维校验(表集合 / 列名 / 列类型 / 索引 / 外键)。**注意参数顺序:docs/03 在前,V1.sql 在后。** + +```bash +node "${CLAUDE_PLUGIN_ROOT}/lib/validate-ddl.mjs" \ + docs/03-数据库设计文档.md \ + sql/migrations/V1__initial_schema.sql +``` + +退出码与处理: +- `0` → 通过,进入步骤 B +- `1` → 存在差异(5 维 diff 明细打印到 stderr)。进入**自主修正循环**(最多 3 轮,docs/03 是 SSoT 不动): + 1. 解析 stderr 差异清单,修正 V1.sql + 2. 重跑 `validate-ddl.mjs` + 3. 退出 0 → 进入 B;退出 1 且本轮 < 3 → 回步骤 1;本轮 ≥ 3 仍失败 → 停下,打印最终残留差异 + 已尝试的 3 轮修正摘要,让用户介入 +- `2` → 用法错(docs/03 / V1 路径找不到),打印路径并停下 + +完成后(V1 写入并通过 `validate-ddl.mjs` 校验),用 `Edit` 在 `docs/08-模块任务管理.md` 中勾选: +- ` - [ ] sql/migrations/V1__initial_schema.sql 已生成` +- ` - [ ] DDL 与 docs/03 全量一致` + +### B. 数据库环境检查 + +#### B.1 检查 .env.local 凭据 + +用 `Glob` 检查 `.env.local` 是否存在;不存在 → 提示用户重新运行 A2 `skeleton-gen` 重建并停下。 + +用 `Read` 读取 `.env.local`,逐行解析 `KEY=VALUE`(跳过空行 / `#` 注释,**不做** shell-source / 变量展开),校验 5 个必填字段 `DB_HOST`、`DB_PORT`、`DB_USER`、`DB_PASSWORD`、`DB_SCHEMA` 均存在且非空。 + +任一缺失 → 打印缺失字段名并停下,提示用户编辑 `.env.local` 后重跑。 + +#### B.2 验证 MySQL 连接 + +用 B.1 解析出的字段值(**不要** shell-source `.env.local`)拼出 `mysql` 客户端调用,做一次连通性自检。把 `` 等占位替换为读到的实际值: + +```bash +mysql -h -P -u -p -e "SELECT 1;" +``` + +- **成功** → 进入步骤 C +- **失败** → 打印具体错误(认证 / 主机不可达 / 端口拒接等),提示检查 `.env.local`,**停下**。 + +完成后,用 `Edit` 在 `docs/08-模块任务管理.md` 中勾选: +- ` - [ ] .env.local 凭据已验证(mysql -e "SELECT 1" OK)` + +### C. 自动导入 MySQL + +#### C.1 DROP+CREATE 空库 + +```bash +node scripts/setup-test-db.mjs +``` + +#### C.2 把 V1 灌入已清空的 schema + +调 `${CLAUDE_PLUGIN_ROOT}/lib/apply-ddl.mjs`:它用纯 JS 解析 `.env.local`(**不** shell-source,消除注入),再经 mysql2 把 DDL 灌入 schema。 + +```bash +node "${CLAUDE_PLUGIN_ROOT}/lib/apply-ddl.mjs" .env.local sql/migrations/V1__initial_schema.sql +``` + +退出码与处理: +- `0` → 成功,进入 C.3 +- `1` → 失败:若错误提示 `mysql2 not found`,先在目标项目执行 `npm i mysql2` 再重跑;其余错误打印 stderr 并停下 +- `2` → 用法错(路径找不到),打印路径并停下 + +完成后,用 `Edit` 在 `docs/08-模块任务管理.md` 中勾选: +- ` - [ ] setup-test-db.mjs 防护通过 + DROP+CREATE + apply V1 已执行` + +#### C.3 自检:docs/03 ↔ V1 表集合一致 + +再跑一次 `validate-ddl.mjs`,确认刚 apply 的 `V1__initial_schema.sql` 与 docs/03 的表/列/类型/索引/外键 5 维仍然一致(参数顺序:docs/03 在前,V1.sql 在后): + +```bash +node "${CLAUDE_PLUGIN_ROOT}/lib/validate-ddl.mjs" \ + docs/03-数据库设计文档.md \ + sql/migrations/V1__initial_schema.sql +``` + +退出码 `0` → 进入步骤 D;`1` → 打印 stderr 5 维 diff 并停下;`2` → 路径错,打印路径并停下。 + +### D. 勾选 docs/08 进度 + 进入 A5 + + +1. 完成后,用 `Edit` 在 `docs/08-模块任务管理.md` 中勾选(A4 子项 + A4 顶层): + - ` - [ ] DDL ↔ docs/03 apply 后 5 维一致(validate-ddl.mjs)` + - `- [ ] A4 DB 初始化 — db-init` + +2. 立即调用 `Skill(downstream-gen)` 进入 A5,不等用户手动输入。 + +## 参考 + +- `${CLAUDE_PLUGIN_ROOT}/lib/validate-ddl.mjs`(A.3 / C.3 docs/03 ↔ V1.sql 5 维一致性校验,跨平台纯 Node) +- `${CLAUDE_PLUGIN_ROOT}/lib/apply-ddl.mjs`(C.2 安全解析 .env.local + mysql2 灌入 DDL,不 shell-source) +- `docs/03-数据库设计文档.md`(DDL 翻译输入,SSoT) +- `.env.local`(DB 凭据) +- 产物:`sql/migrations/V1__initial_schema.sql`(由 Flyway 在 Spring Boot 启动时验证 / apply) diff --git a/skills/plan/downstream-gen/SKILL.md b/skills/plan/downstream-gen/SKILL.md new file mode 100644 index 0000000..54ad39c --- /dev/null +++ b/skills/plan/downstream-gen/SKILL.md @@ -0,0 +1,146 @@ +--- +name: downstream-gen +description: A5 下游文档生成——基于 docs/01 和 docs/03 推导,一次性生成 docs/02 + docs/05 + docs/06 § 三 + docs/10,回填 REQ 卡片依赖接口,把模块清单追加到 docs/08 § 二。 +user-invocable: false +allowed-tools: Read Write Edit Glob Grep Skill AskUserQuestion +--- + +**所有输出必须使用中文。** + +# downstream-gen + +## 执行步骤 + +### A. docs/02 — 开发计划(含 REQ 级开发顺序清单) + +**清单颗粒度**:一行一个 REQ,同一模块的 REQ 必须**连续排列**。 + +1. 构建**模块依赖 DAG**。 +2. 对**每个模块内部**构建 REQ 间依赖,得到模块内 REQ 顺序。 +3. 合成 `req_order[]`:按 `module_topo_order[]` 依次铺开每个模块内的 REQ 序列(**同模块 REQ 连续**)。 +4. **环依赖打破**: + - **模块级**:若模块 DAG 存在环(module_A ↔ module_B),按启发式(字母序 / 被依赖次数多者先)破环排出 `module_topo_order`,并在**参与环的模块里第一个 REQ** 的 `note` 字段填入原因(如 "A↔B 互依赖:先做 A 的骨架")。 + - **REQ 级(同模块内)**:若模块内 REQ 互依赖,同样破环,`note` 填原因。 + - 非环 REQ `note` 留 `—`。 +5. 为 `req_order[]` 每项生成字段: + - `index`:行号(从 1 开始) + - `req_id`:如 `REQ-SYS-001` + - `module_id`:该 REQ 所属模块,如 `module_sys` + - `rationale`(**选中理由**):依赖驱动的简短描述,如 `所属模块无依赖,基础模块` / `依赖 REQ-SYS-001 已在前` / `所属模块依赖 module_sys 已在前` + - `note`(**备注**):默认 `—`;仅环依赖打破场景填原因 +6. 读取并填充 `${CLAUDE_SKILL_DIR}/templates/docs-02-template.md`。 +7. 写入 `docs/02-开发计划.md`。 + +完成后,用 `Edit` 在 `docs/08-模块任务管理.md` 中勾选: +- ` - [ ] docs/02 开发计划已生成` + +### B. docs/05 — API 接口契约 + +1. 读取 `${CLAUDE_SKILL_DIR}/templates/docs-05-header-template.md`,写入 `docs/05-API接口契约.md` 头部。 +2. 对所有模块的每个 REQ:读取并推断 `${CLAUDE_SKILL_DIR}/templates/docs-05-endpoint-template.md`,追加到 docs/05。 + +完成后,用 `Edit` 在 `docs/08-模块任务管理.md` 中勾选: +- ` - [ ] docs/05 API 契约已生成` + +### B2. 回填模块头 + REQ 卡片的 TBD(A5) 字段 + +1. 在`docs/01-需求清单/*/_module.md`(模块头)和 `docs/01-需求清单/*/REQ-*.md`(REQ 卡片)中搜索并回填 `TBD(A5 自动补)` +2. 打印回填统计:`A5 回填 处模块"依赖模块" + 处 REQ"依赖接口"`。 + +完成后,用 `Edit` 在 `docs/08-模块任务管理.md` 中勾选: +- ` - [ ] REQ 卡片依赖接口已回填` + +### C. docs/06 — 页面清单 + +对每个有前端页面的模块:读取并填充 `${CLAUDE_SKILL_DIR}/templates/docs-06-module-pagelist-template.md`,追加到 `docs/06-UI交互规范.md` § 三。 + +完成后,用 `Edit` 在 `docs/08-模块任务管理.md` 中勾选: +- ` - [ ] docs/06 § 三 页面清单已填入` + +### D. docs/08 — 追加模块清单 + +读 `${CLAUDE_SKILL_DIR}/templates/docs-08-module-row-template.md`,按 `module_id` 字母序为每个模块渲染 bullet(模块元数据 + REQ 子项清单,REQ 序保持步骤 A 模块内顺序),追加到 docs/08。 + +完成后,用 `Edit` 在 `docs/08-模块任务管理.md` 中勾选: +- ` - [ ] 下方模块列表已填入` + +### E. docs/10 — 验收清单(项目级 SOP) + +用 `Read` 读取 `${CLAUDE_SKILL_DIR}/templates/docs-10-header-template.md`,用 `Write` 原样写到 `docs/10-验收检查清单.md`(跨平台,不用 `cp`)。 + +完成后,用 `Edit` 在 `docs/08-模块任务管理.md` 中勾选: +- ` - [ ] docs/10 验收清单已生成` + +### F. 验证 + 勾选 docs/08 进度 + 结束 Plan + +1. 一致性检查 + 自主修复循环(最多 3 轮,docs/01 是 REQ SSoT 不动): + + **检查项**: + - 每个 docs/01 REQ 都出现在 docs/05(作为接口,如适用) + - `docs/02 § 二` 的 `module_id` 集合 = `docs/08 § 二` 的 `module_id` 集合 + + **不一致 → 按差异类型自主修复**: + - **REQ 缺 docs/05 endpoint** → 按步骤 B 规则为该 REQ 推测,并追加到 docs/05 + - **module_id 缺 docs/08 § 二** → 按步骤 D 规则渲染该模块 bullet(含 REQ 子项),按 `module_id` 字母序插入正确位置 + - **module_id 缺 docs/02 § 二** → 重算该模块的 `req_order` 段(步骤 A 子流程),按拓扑序插入 docs/02 § 二 + + 修复后重跑检查;通过 → 进入 2;3 轮仍失败 → 停下,打印最终残留差异 + 已尝试的 3 轮修复摘要让用户介入。 + +2. **最终占位符扫描 + 结构性残留检查**(覆盖 Plan 阶段全部产出): + + a. **`TBD` → 自动补齐**:Grep 搜索 `TBD(A3 自动补)` 和 `TBD(A5 自动补)`。有命中则就地补填(A3 残留 → 查 docs/03 填 `依赖表`;A5 残留 → 查 docs/05 按 REQ-ID 填 `依赖接口`),再 Grep 确认 0 命中;仍残留报错停下。 + + b. **结构性残留检查(不只看字面占位符,校验 SSoT 完整性)**: + + - **docs/05 每个端点都有请求/响应 schema**:逐个解析 docs/05 的每个 endpoint 段(以 `### REQ-` 开头的小节)。每段必须同时含非空的 `- **请求**:` 与 `- **响应**:` 行——值不得为空、`TBD`、`—` 或 `【人工填写:…】`。缺失/留空 → 按步骤 B 规则就地为该端点推测补全请求/响应 schema,再复核;3 轮仍补不全则计入残留清单(见下方 c),交由 QA 循环让用户介入。 + - **docs/02 DAG 覆盖每个 REQ**:收集 docs/01 全部 REQ-ID 集合,与 `docs/02 § 二、开发顺序清单` 表中出现的 `req_id` 集合比对。任一 docs/01 REQ 未出现在 docs/02 顺序清单 → 按步骤 A 子流程把该 REQ 插入其所属模块段的正确拓扑位置(保持同模块 REQ 连续),再复核;3 轮仍无法补齐则计入残留清单交由 QA 循环。 + + c. **`【人工填写:...】` + 结构性残留 → QA 循环等用户补**: + + 循环执行直到(搜索不到 `【人工填写:`)**且**(步骤 b 两项结构检查均通过)且用户选「继续」: + - 0 残留 → 直接放行进入步骤 3 + - 有残留 → 打印残留清单(含字面占位符 `<文件:行号> — <内容摘要>`,以及结构性缺口 `docs/05 端点 缺请求/响应 schema` / `docs/02 顺序清单缺 REQ `),用 `AskUserQuestion` 弹「继续」/「有疑问想先沟通」二选一;用户回答后重扫 + 重跑结构检查再决定放行 / 继续循环 + + **每次弹 QA 前都重扫一次**(含两项结构检查)——保证用户看到的 N 是最新的,避免「用户以为填完但实际还有残留」直接放行。 + +3. **docs/05 + docs/02 人工评审闸(强制,未确认不得勾选 A5)**: + + 向用户摘要展示两份 SSoT 的关键内容,请其确认无误: + - **docs/05 API 契约**:列出全部端点(`METHOD PATH — REQ-ID`),并标注任何「由 A5 自动推断」的端点/字段供重点核对。 + - **docs/02 构建顺序**:展示 `req_order[]` 顺序,**特别标出所有 `note ≠ —` 的环依赖打破项**(启发式选定的顺序 + 原因),供用户判断该顺序是否可接受。 + + 用 `AskUserQuestion` 同时问两项确认(多问题表单),每项二选一: + - 「docs/05 端点/字段确认无误」:`确认` / `需要修改` + - 「docs/02 构建顺序可接受(含 cycle-breaking 选定的顺序)」:`确认` / `需要修改` + + 裁决: + - 两项均 `确认` → 进入步骤 4 勾选 A5。 + - 任一为 `需要修改` → 用 `AskUserQuestion` 收集具体修改点,就地修订对应文档(docs/05 端点/字段或 docs/02 顺序/备注),改完重新展示摘要并重跑本评审闸,直到两项均 `确认`。**未两项确认前禁止勾选 A5、禁止打印终止横幅。** + +4. 完成后,用 `Edit` 在 `docs/08-模块任务管理.md` 勾选 A5 父项: + - `- [ ] A5 下游文档生成 — downstream-gen` + +5. 打印 A5 完成横幅并**停下**(A6 仍未跑——A5 之后由 plan-start 派发 A6 frontend-scope-lock,A6 完成后再由 plan-start 跑 5 项终结闸;只有终结闸全过才会提示运行 coding-start): + + ``` + ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + [downstream-gen] ✅ A5 下游文档生成完成(A0~A5) + + docs/02 / docs/05 / docs/06 § 三 / docs/08 § 二 / docs/10 已就绪; + docs/05 + docs/02 评审闸已通过;docs/08 § 一 A0~A5 已全勾。 + + ⏭️ 下一步:运行 /erp-workflow:plan-start + plan-start 会派发到 A6 frontend-scope-lock 锁定前端 scope, + A6 完成后再由 plan-start 跑 5 项终结闸校验; + 全过才会提示运行 /erp-workflow:coding-start 进入 B 阶段。 + ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + ``` + +## 参考 + +- `${CLAUDE_SKILL_DIR}/templates/docs-02-template.md` +- `${CLAUDE_SKILL_DIR}/templates/docs-05-header-template.md` +- `${CLAUDE_SKILL_DIR}/templates/docs-05-endpoint-template.md` +- `${CLAUDE_SKILL_DIR}/templates/docs-06-module-pagelist-template.md`(追加到 docs/06 § 三) +- `${CLAUDE_SKILL_DIR}/templates/docs-08-module-row-template.md`(模块 bullet 行模板) +- `${CLAUDE_SKILL_DIR}/templates/docs-10-header-template.md` diff --git a/skills/plan/downstream-gen/templates/docs-02-template.md b/skills/plan/downstream-gen/templates/docs-02-template.md new file mode 100644 index 0000000..68d29d5 --- /dev/null +++ b/skills/plan/downstream-gen/templates/docs-02-template.md @@ -0,0 +1,26 @@ +# 02-开发计划 + +## 一、模块依赖表 + +| 模块 ID | 模块名 | 依赖模块 | 依赖表 | +|---|---|---|---| +{{#each modules}} +| {{id}} | {{name}} | {{deps}} | {{tables}} | +{{/each}} + +## 二、开发顺序清单(CC 分发权威) + +> 本清单由 A5 `downstream-gen` 一次性生成。**每行是一个 REQ**,不是模块。Coding 阶段(`coding.mjs` 的 Router)按表格行序确定模块顺序,对每个 REQ 所属模块查 `docs/08 § 二` 的 `里程碑:` 字段 + 本地 `git tag -l 'milestone/'`:tag 存在则跳过,否则(`—` / tag 不存在)选为待跑模块;顶层循环对每个待跑后端模块依次跑功能链(spec→plan→tdd→verify→review)+ 测试闸 + 里程碑,把该模块的所有 REQ 一次做完。 +> +> **约束**:同一模块的所有 REQ 必须**连续排列**。允许打破依赖拓扑(如环依赖、业务必须先做),但必须在「备注」列写明原因。 + +| # | REQ | 所属模块 | 选中理由 | 备注 | +|---|-----|---------|---------|------| +{{#each req_order}} +| {{index}} | **{{req_id}}** | {{module_id}} | {{rationale}} | {{note}} | +{{/each}} + +> **后端模块全部打里程碑后**:`coding.mjs` 的 Router 把全部未完成前端 FE 聚合为**唯一一个** `frontend-phase` 阶段,排在所有后端模块之后由顶层循环跑(prototype/ 门禁已在 Plan 期 A6 `frontend-scope-lock` 前移完成)。前端阶段以业务功能(不是 HTML 文件数)为粒度拆分 FE(FE-NN,路径限 `frontend/`),每个 FE 跑一次功能链,整个阶段打 **1 个**里程碑 tag(分支 `frontend-phase`,`milestone/frontend-phase`,记录在 `docs/08 § 三 整体里程碑`)。 + +## 三、关键说明 +{{notes}} diff --git a/skills/plan/downstream-gen/templates/docs-05-endpoint-template.md b/skills/plan/downstream-gen/templates/docs-05-endpoint-template.md new file mode 100644 index 0000000..91a1fda --- /dev/null +++ b/skills/plan/downstream-gen/templates/docs-05-endpoint-template.md @@ -0,0 +1,12 @@ +### {{req_id}} {{title}} + +- **Method**: {{method}} +- **Path**: `{{path}}` +- **Auth**: {{auth}} +- **请求**: {{request_summary}} +- **响应**: {{response_summary}} + +#### 错误码 +{{#each errors}} +- `{{code}}` — {{message}} +{{/each}} diff --git a/skills/plan/downstream-gen/templates/docs-05-header-template.md b/skills/plan/downstream-gen/templates/docs-05-header-template.md new file mode 100644 index 0000000..e89cc3d --- /dev/null +++ b/skills/plan/downstream-gen/templates/docs-05-header-template.md @@ -0,0 +1,30 @@ +# 05-API接口契约 + +BasePath: `{{base_path}}` +端口: `【人工填写:后端端口,默认 8080】` + +## 全局约定 + +### 响应格式 +```json +{"code": 200, "message": "操作成功", "data": {}, "timestamp": 1700000000000} +``` + +### 错误码 +| 范围 | 含义 | +|---|---| +| 200 | 成功 | +| 400xx | 客户端参数错误 | +| 401xx | 认证/授权错误 | +| 403xx | 权限不足 | +| 404xx | 资源不存在 | +| 500xx | 服务端内部错误 | + +### 鉴权 +{{auth_note}} + +### 分页参数 +{{pagination_note}} + +## 接口清单 +(各模块接口段落见下方,由 `downstream-gen` 按 REQ 填入) diff --git a/skills/plan/downstream-gen/templates/docs-06-module-pagelist-template.md b/skills/plan/downstream-gen/templates/docs-06-module-pagelist-template.md new file mode 100644 index 0000000..36f18a5 --- /dev/null +++ b/skills/plan/downstream-gen/templates/docs-06-module-pagelist-template.md @@ -0,0 +1,9 @@ +### {{module_id}} {{module_name}} + +{{#each pages}} +- **{{page_name}}** (`{{route}}`) + - 类型: {{page_type}} (列表页 / 表单页 / 详情页 / 树形管理页) + - 对应 REQ: {{req_ids}} + - 入口菜单: {{menu_path}} + - 主要交互: {{interactions}} +{{/each}} diff --git a/skills/plan/downstream-gen/templates/docs-08-module-row-template.md b/skills/plan/downstream-gen/templates/docs-08-module-row-template.md new file mode 100644 index 0000000..edd15f1 --- /dev/null +++ b/skills/plan/downstream-gen/templates/docs-08-module-row-template.md @@ -0,0 +1,6 @@ +- {{module_id}} {{module_name}} + - 依赖: {{depends_on}} + - 路径: {{path_scopes}} + - 里程碑: — + - 功能: +{{req_checklist}} diff --git a/skills/plan/downstream-gen/templates/docs-10-header-template.md b/skills/plan/downstream-gen/templates/docs-10-header-template.md new file mode 100644 index 0000000..4440bff --- /dev/null +++ b/skills/plan/downstream-gen/templates/docs-10-header-template.md @@ -0,0 +1,16 @@ +# 10-验收检查清单 + +通用验收项(全项目适用): + +- [ ] `node scripts/test.mjs` 本地全绿 +- [ ] 所有 schema 改动都有对应 `sql/migrations/V_n__.sql` +- [ ] 所有新接口在 `docs/05` 中有契约定义 +- [ ] 所有新功能代码注释含 REQ-XXX-NNN +- [ ] 统一响应格式 `{code, message, data, timestamp}` +- [ ] 异常走全局处理器,不暴露堆栈到前端 +- [ ] 前端不存敏感信息到 localStorage + +> 本文档仅维护项目级验收 SOP。粒度更细的验收信息分散在: +> - **每 REQ 的业务验收点**:`docs/01-需求清单//.md § 验收` +> - **每模块的实测验收(数据 / UI / 自动化用例位置)**:由 B 阶段 coding.mjs 的 module-report stage 在该模块完成时填入模块完成报告 +> - **REQ 开发进度(review stage approve 状态)**:`docs/08 § 二` diff --git a/skills/plan/frontend-scope-lock/SKILL.md b/skills/plan/frontend-scope-lock/SKILL.md new file mode 100644 index 0000000..1fa8942 --- /dev/null +++ b/skills/plan/frontend-scope-lock/SKILL.md @@ -0,0 +1,130 @@ +--- +name: frontend-scope-lock +description: A6 前端范围锁定(Plan 期)——检查项目根 prototype/*.html,从 prototype + docs/01 REQ 卡片 + docs/05/06 提炼项目级 UI 约定、Design Tokens、组件库选型,逐项 AskUserQuestion 确认后写入 docs/06(UI 交互规范)+ docs/04(前端栈),并为每个 FE-NN 锁定设计决策表。把全部前端歧义前移到 Plan 期问清,使 Coding 阶段前端循环无需再弹窗。 +user-invocable: false +allowed-tools: Read Write Edit Glob Grep Skill AskUserQuestion +--- + +**所有输出必须使用中文。** + +# frontend-scope-lock + +A6 是 **Plan 阶段最后一个前端守门 skill**,由 `plan-start` 在 A5(downstream-gen)完成后派发。 + +**定位**:把原 Coding 阶段晚到的前端闸(`frontend-start` 的 prototype 检查 + `fe-feature-brainstorm` / `fe-feature-plan` 的交互式 Q&A)整体**前移到 Plan 期**。Plan 期允许 `AskUserQuestion` 问人;问清后写入 SSoT(docs/06 + docs/04),Coding 阶段的前端循环只读不问。 + +## 阶段范围 + +锁定**项目级**前端契约:UI 约定 / Design Tokens / 组件库选型 + 每个 FE-NN 的设计决策。**不涉及** SQL / migration / controller / service / DTO(后端范畴),也**不在此实现**任何页面代码(Coding 阶段做)。 + +## 执行步骤 + +> **关于 AskUserQuestion**:下文只描述「问什么、给哪些选项、各选项导向什么后续」。`header` / 各选项的 `description` / `multiSelect` 等具体参数由你按工具 schema 自行填全合法值——不要把下文的选项文字当成完整调用照抄。 + +### 步骤 0:打印当前位置流程图 + +向用户**直接输出**(模型自己打印,不调 bash / cat)当前位置: + +``` +┌────────────────────────────────────────────────────────┐ +│ 📋 阶段 A:规划(一次性) │ +│ A0 初始化 → A1 锁范围 → A2 骨架 → A3 DB 设计 │ +│ → A4 DB 初始化 → A5 下游文档 │ +│ ▶ A6 前端范围锁定(prototype + tokens + 约定) │ +│ 规划阶段到此结束 │ +└────────────────────────────────────────────────────────┘ +``` + +### 步骤 1:检查 prototype(缺失则在此问) + +用 `Glob` 检查项目根 `prototype/**/*.html`: + +- **至少 1 个 `.html`** → 通过,记下文件清单,进入步骤 2。 +- **0 个** → 这是 Plan 期,**可以问**。用 `AskUserQuestion` 告知用户「未在 prototype/ 找到任何 .html 原型,前端范围锁定依赖原型作为页面骨架权威」,给「我已补齐原型,请重新检查」和「本项目无前端,跳过 A6」两个选项。 + - 选「已补齐」→ 重新 `Glob`:命中则进入步骤 2,仍为 0 则重复本问。 + - 选「无前端」→ 在 docs/08 § 一 把 A6 的**父项 + 全部 3 个子项**一并勾选并在父项行尾注明「(无前端,A6 跳过)」,打印步骤 6 的终止横幅(产出标注「跳过」),**停止**,不写 docs/06 / docs/04。 + > 必须同时勾子项:`plan-start` 的分发依据是「§ 一 第一个未勾 [ ] 子项」,若只勾父项会让下一次 plan-start 重复派发回本 skill,无前端项目无法满足 Plan 终结闸。具体要勾的子项: + > - ` - [x] docs/06 项目级 UI 约定 + Design Tokens + 组件库已锁定(无前端跳过)` + > - ` - [x] docs/04 § 二 前端栈已锁定(引用 docs/06)(无前端跳过)` + > - ` - [x] 各 FE-NN 设计决策表已生成(docs/06 § 三之后 / docs/08 § 三)(无前端跳过)` + +### 步骤 2:收集证据(只读,不问) + +为提炼项目级约定,`Read` 以下来源: + +- **prototype/**:所有 `*.html`,作为页面布局 / 组件 / 交互的**实测权威**(DOM 结构、表单展现、列表范式、状态色实例)。 +- **docs/01-需求清单/**:各 `_module.md` + `REQ-*.md`,提取 UI 描述、业务校验、acceptance 中与界面相关的部分。 +- **docs/05-API接口契约.md**:端点列表,确认前端要消费的接口集合(影响页面状态机 / 加载态)。 +- **docs/06-UI交互规范.md**:已有的通用交互规则(§ 一)、Design Tokens(§ 二)、页面清单(§ 三 由 A5 填)。布局以项目根 `prototype/` 为权威,docs/06 不设独立布局小节。本 skill 在此基础上**收敛 / 补全**,不推翻已确认内容。 +- **docs/04-技术规范.md § 零**:技术栈表里的前端行(如 `前端 UI 组件` = Ant Design),作为组件库选型默认值来源。 + +把证据归纳为三组**草案**:(a) 项目级 UI 约定、(b) Design Tokens(全局调色板 + 组件级状态色)、(c) 组件库选型。草案优先复用 docs/06 / docs/04 既有值(已锁定的不重问),仅对 prototype 与现文档**不一致**或**缺失**的点进入步骤 3 确认。 + +### 步骤 3:逐项 AskUserQuestion 确认 + +**一次一问**,仅对真歧义点。每问给出「从证据提炼的默认值」让用户**确认 / 覆盖**,不造无意义确认题。建议覆盖(无歧义的项直接采用默认值,不弹问): + +1. **UI 约定**:整体布局骨架、最小视口 / 响应式策略、列表页范式、表单展现阈值(Modal / Drawer / 独立页)、操作反馈范式、数据展示约定、前端权限控制方式。 +2. **Design Tokens**:全局调色板语义→变量→默认值;组件级状态色表(编辑 / 只读 / 悬浮 的 bg/fg)。prototype 中出现但未登记的色值 → 问是否新增 token。 +3. **组件库选型**:UI 组件库 + 版本(默认取 docs/04 § 零)、主题接入方式、图标库、表格 / 表单是否二次封装。 + +每个确认结果即时记入对应草案。**绝不**留 `【人工填写:】` / `{{占位}}` / `TBD` 作为最终值。 + +### 步骤 4:写入 docs/06 + docs/04 + +用 `${CLAUDE_SKILL_DIR}/templates/fe-scope-template.md` 作为填充骨架,把步骤 3 确认后的真实值填入(剥掉模板内 HTML 注释),分别落盘: + +- **docs/06-UI交互规范.md**(用 `Edit` 合并,不另起文件;小节编号以 `skeleton-gen/templates/docs-06-static-template.md` 为权威:§ 一 通用交互规则 / § 二 Design Tokens / § 三 页面清单): + - 模板 § 一 → 收敛 / 补全 docs/06 § 一(通用交互规则)的项目级约定。 + - 模板 § 二 → 写入 / 校正 docs/06 § 二(Design Tokens 全局调色板 + 组件级状态色 + Token 默认值),与 `src/styles/tokens.css` 命名规范(docs/04 § 2.5)一致。 + - 模板 § 五 → 追加到 docs/06 § 三(页面清单)之后,作为 **FE 级设计决策表**:FE 清单来自 docs/08 § 三(若 § 三 尚无 FE bullet,则在此按 prototype + docs/01 + docs/05 推导 FE 清单并**同时写入 docs/08 § 三**「功能:」项,行格式见 docs/08 模板)。一 FE 一行。 +- **docs/04-技术规范.md § 二(前端编码规范)**(用 `Edit`): + - 把组件库选型 + 模板 § 四前端栈摘要写入 / 校正 § 2.3(组件 / 页面编写规范)与 § 2.5(样式与主题)的引用说明;色值约定指向 docs/06 § 二。 + - 不重复抄 docs/06 全文,只写「前端组件库 = X、tokens 锁定于 docs/06 § 二」这类引用,保持 SSoT。 + +写入时遵循模板的字面安全约定:值含 `$` / `{` / `}` 等字符**原样写入**,不做二次解释。 + +### 步骤 5:自审(inline 修,不等用户) + +- 模板五节均已填充,**无** `{{...}}` / `【人工填写:】` / `TBD` 残留(`Grep` 校验 docs/06 + docs/04 本次写入区域)。 +- 组件库选型与 docs/04 § 零前端行一致;如确认值覆盖了 § 零默认值,回写 § 零保持一致。 +- docs/06 § 五 / docs/08 § 三 的 FE-NN 集合一致,每个 FE 行字段非空。 +- 命中残留 → 就地修正后重新校验;无法自决的歧义 → 回步骤 3 补问。 + +### 步骤 6:勾选 docs/08 + 终止横幅 + +1. 用 `Edit` 在 `docs/08-模块任务管理.md § 一` 勾选 A6 子项 + 父项: + - ` - [ ] docs/06 项目级 UI 约定 + Design Tokens + 组件库已锁定` + - ` - [ ] docs/04 § 二 前端栈已锁定(引用 docs/06)` + - ` - [ ] 各 FE-NN 设计决策表已生成(docs/06 § 三之后 / docs/08 § 三)` + - `- [ ] A6 前端范围锁定 — frontend-scope-lock` +2. 向用户**直接输出**终止横幅并**停止**(不自动进入 B 阶段,回交给 plan-start 的终结闸判定): + +``` +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + [frontend-scope-lock] ✅ A6 前端范围锁定完成 + + 产出: + ✓ docs/06 § 一 项目级 UI 约定(通用交互规则) + ✓ docs/06 § 二 Design Tokens(全局调色板 + 组件级状态色) + ✓ docs/06 § 三之后 各 FE-NN 设计决策表 + ✓ docs/04 § 二 前端栈 + 组件库选型(引用 docs/06) + + 前端契约已全部锁定,Coding 阶段前端循环将只读不问。 + + Plan 阶段(A0~A6)到此结束。请运行 /erp-workflow:plan-start + 让终结闸校验全部前移闸门是否通过,再进入 B 阶段。 +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +``` + +## 参考 + +- `${CLAUDE_SKILL_DIR}/templates/fe-scope-template.md`(产出骨架) +- `prototype/**/*.html`(页面骨架实测权威,步骤 1 前置门由本 skill 自承) +- `docs/01-需求清单/**/*.md`(UI 描述 / 业务校验来源) +- `docs/05-API接口契约.md`(前端消费端点) +- `docs/06-UI交互规范.md`(写入目标:§ 一 通用交互约定、§ 二 Tokens、§ 三之后 FE 决策表) +- `docs/04-技术规范.md § 二 / § 零`(前端栈 + 组件库选型写入目标) +- `docs/08-模块任务管理.md § 一`(A6 进度勾选)/ `§ 三`(FE 清单) +- 上游:`plan-start`(A5 完成后派发到此) +- 下游:`plan-start` 终结闸(A6 完成后回交校验);Coding 阶段 `workflows/coding.mjs` 前端循环消费本 skill 的产出 diff --git a/skills/plan/frontend-scope-lock/templates/fe-scope-template.md b/skills/plan/frontend-scope-lock/templates/fe-scope-template.md new file mode 100644 index 0000000..bb8bd6a --- /dev/null +++ b/skills/plan/frontend-scope-lock/templates/fe-scope-template.md @@ -0,0 +1,65 @@ + +## 一、项目级 UI 约定 + +> 来源:prototype/*.html 实测 + docs/01 REQ 卡片 UI 描述 + docs/06 已有布局。经用户确认。 + +| 约定项 | 锁定值 | 依据 | +| --- | --- | --- | +| 整体布局骨架 | {{LAYOUT_SKELETON}} | {{LAYOUT_SOURCE}} | +| 最小支持视口 / 响应式策略 | {{VIEWPORT_POLICY}} | {{VIEWPORT_SOURCE}} | +| 列表页交互范式 | {{LIST_PATTERN}} | {{LIST_SOURCE}} | +| 表单展现规则(Modal / Drawer / 独立页阈值) | {{FORM_PATTERN}} | {{FORM_SOURCE}} | +| 操作反馈范式(成功 / 失败 / 二次确认) | {{FEEDBACK_PATTERN}} | {{FEEDBACK_SOURCE}} | +| 数据展示约定(状态 / 日期 / 金额 / 空值 / 操作列) | {{DISPLAY_PATTERN}} | {{DISPLAY_SOURCE}} | +| 前端权限控制方式 | {{AUTH_PATTERN}} | {{AUTH_SOURCE}} | + +## 二、Design Tokens + +> 单元格写 token 名(`--color-xxx`),不写裸 hex;色值默认值落地于 `src/styles/tokens.css`。命名规范见 docs/04 § 2.5。 + +### 2.1 全局调色板 + +| 语义 | 变量名 | 默认值 | 用途 | +| --- | --- | --- | --- | +| {{TOKEN_SEMANTIC}} | {{TOKEN_VAR}} | {{TOKEN_VALUE}} | {{TOKEN_USAGE}} | + +### 2.2 组件级状态色 + +| 序号 | 组件 | 编辑 bg | 只读 bg | 悬浮 bg | 编辑 fg | 只读 fg | 悬浮 fg | 备注 | +| --- | --- | --- | --- | --- | --- | --- | --- | --- | +| {{COMP_NO}} | {{COMP_NAME}} | {{COMP_BG_EDIT}} | {{COMP_BG_READONLY}} | {{COMP_BG_HOVER}} | {{COMP_FG_EDIT}} | {{COMP_FG_READONLY}} | {{COMP_FG_HOVER}} | {{COMP_NOTE}} | + +## 三、组件库选型 + +| 项 | 锁定值 | 依据 / 备注 | +| --- | --- | --- | +| 前端 UI 组件库 | {{UI_LIB}} | {{UI_LIB_SOURCE}} | +| 版本 | {{UI_LIB_VERSION}} | 与 docs/04 § 零 一致 | +| 主题接入方式 | {{UI_LIB_THEME}} | 如 ConfigProvider.theme.token 引用 § 二全局调色板 | +| 图标库 | {{ICON_LIB}} | {{ICON_LIB_SOURCE}} | +| 表格 / 表单封装策略 | {{WRAP_STRATEGY}} | 是否二次封装、统一 props 约定 | + +## 四、前端栈摘要(同步 docs/04 § 二) + +| 分层 | 技术 | 版本 | 说明 | +| --- | --- | --- | --- | +| {{FE_LAYER}} | {{FE_TECH}} | {{FE_VERSION}} | {{FE_NOTE}} | + +## 五、各 FE 设计决策表 + +> 一 FE 一行,FE 清单来自 docs/08 § 三。每行锁定该 FE 的页面骨架来源、页面类型、组件库选型与状态机要点,供 Coding 阶段前端循环直接消费(不再二次问人)。 + +| FE-NN | 功能名 | 关联 REQ | 关联原型 | 页面类型 | 核心组件树要点 | 关键状态机(loading/empty/error/正常/提交中) | 引用 Design Tokens | +| --- | --- | --- | --- | --- | --- | --- | --- | +| {{FE_ID}} | {{FE_NAME}} | {{FE_REQS}} | {{FE_PROTOTYPES}} | {{FE_PAGE_TYPE}} | {{FE_COMPONENT_TREE}} | {{FE_STATE_MACHINE}} | {{FE_TOKENS}} | diff --git a/skills/plan/plan-start/SKILL.md b/skills/plan/plan-start/SKILL.md new file mode 100644 index 0000000..67bac3b --- /dev/null +++ b/skills/plan/plan-start/SKILL.md @@ -0,0 +1,145 @@ +--- +name: plan-start +description: A 阶段(Plan)入口与分发器。根据 docs/08 § 一 的 checkbox 状态派发到 A0~A6 对应 skill。Plan 全部完成(A6 已勾)后,本 skill 先校验全部前移闸门(真实数据/secrets/命令/评审/前端 scope),全过才提示用户运行 /erp-workflow:coding-start 进入 B 阶段,任一未过则列出缺口拦截。 +user-invocable: true +allowed-tools: Skill Read Glob Grep +--- + +**所有输出必须使用中文。** + +你是 ERP 项目**规划阶段的编排器**。你**只派发 A 阶段(A0~A6)的 skill**;docs/08 § 一 全部勾选后,你**不立即放行**——先执行 §2.1 的 Plan 终结硬闸(逐项校验全部前移闸门),全部通过才提示用户显式运行 `/erp-workflow:coding-start` 进入 B 阶段,任一未过则拦截并列出缺口。你不直接生成任何文件。 + +## 第一步:读取 docs/08 + 决定分发目标 + +docs/08 § 一 是**Plan 阶段进度追踪**(A0~A6 的 checkbox)。§ 二的模块元数据由 coding-start 读写,本 skill 不读。 + +### 分发判定 + +1. **docs/08 是否存在** + 用 `Glob` 检查 `docs/08-模块任务管理.md`。 + - 如果不存在 → 后续 = `project-init`。 + +2. **根据 § 一 找到当前进度** + + **判定算法(务必按此执行,不要凭"表里含 Axx"判断;docs/08 § 一 模板始终列出 A0~A6 全部行,"含"恒为真)**: + - 用 Read / Grep 把 `docs/08-模块任务管理.md § 一` 全文读出,按文件顺序自上而下扫描,找到**第一个 `- [ ]` 未勾子项**(仅看 § 一,§ 二 / § 三 不参与判定)。 + - 该子项归属的父项 `Axx`(A0~A6)即为当前阶段,按下表派发到对应 skill。 + - 若 § 一 所有 `[ ]` 都已变成 `[x]`(含父项与全部子项)→ 进入 §2.1 Plan 终结闸。 + +| `第一个未勾子项归属` | `后续` | `阶段` | +|---|---|---| +| 无 docs/08(文件不存在) | `project-init` | `A0` | +| A0 父项或其任一子项 | `project-init` | `A0` | +| A1 父项或其任一子项 | `scope-lock` | `A1` | +| A2 父项或其任一子项 | `skeleton-gen` | `A2` | +| A3 父项或其任一子项 | `db-design-gen` | `A3` | +| A4 父项或其任一子项 | `db-init` | `A4` | +| A5 父项或其任一子项 | `downstream-gen` | `A5` | +| A6 父项或其任一子项 | `frontend-scope-lock` | `A6` | +| § 一 全部 `[x]` | **无分发** → §2.1 Plan 终结闸 | - | + +## 第二步:分发通知 + 调用目标 skill + +### 2.1 Plan 已完成 — 终结硬闸(HARD GATE) + +A 阶段所有 checkbox 均 `[x]` 时**不代表可以进 B 阶段**。Coding 阶段为全自动静默 Workflow(子代理无法弹窗问人),因此**所有需求/配置必须在 Plan 期锁死**。本步骤是**硬闸**:先逐项校验下列全部前移闸门,**全部通过**才提示用户运行 `coding-start`;**任一未过**则**不提示进 B 阶段**,转而列出缺口并指明回填位置。 + +#### 第 1 步:逐项校验前移闸门(用 Read / Glob / Grep,禁止跳过任何一项) + +逐项检查,记录每项 `通过` / `缺口`。任一缺口即整闸 `不通过`。 + +1. **REQ 卡片真实数据**(来自 A1 scope-lock) + - `Glob` 找出全部 REQ 卡片(如 `docs/01-需求清单/**/*.md`)。 + - 对每张卡片 `Grep` 残留占位:命中任一即缺口 — + `【人工填写`、`TBD`、`待补`、`<示例`、`【示例行`(与 scope-lock E.1 同强度——`<示例` 兜底 `<示例值>`,`【示例行` 兜底未删的模板示例行 `【示例行,替换为真实字段】`;避免半填卡片绕过本闸)。 + - 缺口表述示例:`REQ-USER-001 仍含 TBD / 示例值未替换为真实约束 / 示例行未删除`。 + +2. **secrets / 项目配置全锁**(来自 A1 收集的 secret/account/package-name/namespace 清单) + - `Read` `.env.local`(真实 secret 值所在;gitignored,docs/07 只记规则不记值):校验 `config-vars.yaml` 的 `secrets_ref` 列出的每个 secret 键(如 `DB_PASSWORD` / `JWT_SECRET`)均有真实值,无 `【人工填写`/`TBD`/空值。 + - `Read` `config-vars.yaml`(非敏感项目级配置):校验包名 / namespace / 端口 / 初始账号等字段均已填,无 `【人工填写`/`TBD`。 + - 任一未填即缺口。(docs/07-环境配置.md 仅承载规则/约定,不参与值校验。) + +3. **docs/04 §零 命令齐**(来自 A1 收集的每栈构建/lint/单测/e2e 命令) + - `Read` `docs/04-技术规范.md`,定位 `§ 零` 命令区。 + - 校验:每个技术栈的 build / lint / unit / e2e 命令均显式存在且非占位。缺命令或留 `TBD` 即缺口(Coding 期 test-gate / featureLoop 依赖这些命令,缺即无法静默跑)。 + +4. **docs/05 + docs/02 已评审**(来自 A5 downstream-gen 的评审闸) + - `Read` `docs/05-API接口契约.md` 与 `docs/02-开发计划.md`。 + - 校验:(a) docs/05 每个端点都有请求/响应 schema、无 `【人工填写`/`TBD`;(b) docs/02 每个 REQ 都在构建顺序 DAG 中、cycle-breaking 顺序有 `note` 说明。缺任一即缺口。(A5 父项已勾本身即蕴含 downstream-gen 评审闸已过——downstream-gen 在用户未确认时禁止勾 A5,故无需独立的「已评审」标记。) + +5. **A6 前端 scope 已锁**(来自 A6 frontend-scope-lock) + - **无前端项目分支**:先 `Read` `docs/08-模块任务管理.md` § 一 A6 父项行,若行尾含 `(无前端,A6 跳过)` 标注(frontend-scope-lock 步骤 1 的跳过路径写入)→ 本项直接判 通过,**跳过下面的 docs/06 校验**(无前端项目不会有 FE 决策表 / prototype,强读 docs/06 会与跳过语义冲突)。 + - 否则(有前端):`Read` `docs/06-UI交互规范.md`,校验项目级 UI 约定 / Design Tokens / 组件库选型已确认;每个 FE-NN 的设计决策表非占位;prototype 闸门已过(docs/08 § 一 A6 勾选即代表此项已由 A6 skill 锁定,但仍核对 docs/06 无 `【人工填写`/`TBD` 残留)。缺任一即缺口。 + +#### 第 2 步(A):全部通过 → 放行 + +仅当第 1 步 **5 项全部 `通过`** 时,向用户输出完成横幅: + +``` +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + [plan-start] ✅ Plan 阶段全部完成,前移闸门全部通过 + + 已校验通过: + ✓ REQ 卡片均为真实数据(无占位/示例残留) + ✓ .env.local secrets + config-vars.yaml(account/package/namespace)全锁 + ✓ docs/04 §零 各栈 build/lint/unit/e2e 命令齐全 + ✓ docs/05 API 契约 + docs/02 构建顺序已评审 + ✓ A6 前端 scope(UI 约定 / tokens / 组件库)已锁 + + ⚠️ 进入 B 阶段前必须完成: + 1. 人工通读 docs/* + CLAUDE.md + sql/migrations/V1 + 各 scripts/* + + 2. 把全部 Plan 产物 commit 到本地默认分支(main / master): + git add -A && git commit -m "chore: plan phase A0~A6 done" + + 3. B 阶段全程纯本地(无需远程仓库 / push / MR): + 每个模块由 coding.mjs 的 milestone stage 本地 merge 进默认分支并打 milestone/ tag。 + 确认当前已在本地默认分支(main / master)上即可。 + + 4. 运行 /erp-workflow:coding-start 进入 B 阶段 +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +``` + +不调任何下游 skill。 + +#### 第 2 步(B):存在缺口 → 拦截,**不提示进 B 阶段** + +只要第 1 步出现**任一缺口**,**禁止**输出上面的放行横幅、**禁止**提示运行 `coding-start`。改为输出拦截横幅,逐条列出缺口与回填位置,让用户先补齐: + +``` +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + [plan-start] ⛔ Plan 终结闸未通过 — 暂不能进入 B 阶段 + + Coding 阶段全自动静默,缺失项无法在编码期补问,必须现在锁死。 + 以下缺口需补齐后重新运行 /erp-workflow:plan-start: + + <逐条列出每个缺口,格式:[闸门] 缺口描述 → 回填位置> + 例: + [REQ 真实数据] REQ-USER-001 输入字段「示例值」列仍为模板占位 → docs/01-需求清单/... + [secrets] DB_PASSWORD 未填 → .env.local + [docs/04 §零] node 栈缺 e2e 命令 → docs/04-技术规范.md §零 + + 补齐后再次运行 /erp-workflow:plan-start 重新校验。 +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +``` + +输出拦截横幅后**停下**,不调任何下游 skill,不提示 coding-start。 + +### 2.2 正常派发(`后续` 非空) + +打印简短分发通知: + +``` +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + [plan-start] → 派发到 <后续> + 未勾项: +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +``` + +立即用 `Skill` 工具调用 `后续`。 + +## 参考 + +- `docs/08-模块任务管理.md`(进度追踪) +- `CLAUDE.md`(项目指令) +- 后续 skills(通过 `Skill` 工具按名称调用) diff --git a/skills/plan/project-init/SKILL.md b/skills/plan/project-init/SKILL.md new file mode 100644 index 0000000..1b93b12 --- /dev/null +++ b/skills/plan/project-init/SKILL.md @@ -0,0 +1,110 @@ +--- +name: project-init +description: A0 项目初始化——从插件模板幂等地用 Read/Write 落盘 CLAUDE.md / docs/01-需求清单/index.md / docs/04-技术规范.md / docs/08-模块任务管理.md(已存在则跳过),做跨平台依赖检查(git/mysql/node 缺失则按 OS 给安装指引并停下),并初始化 Git(如未初始化)。plan-start 在 docs/08 缺失时派发本 skill。 +user-invocable: false +allowed-tools: Read Write Glob Edit Skill Bash(node *) Bash(git init) Bash(git rev-parse *) +--- + +**所有输出必须使用中文。** + +你负责在项目目录中创建初始文件结构,已存在的文件不覆盖。 + +## 执行步骤 + +### A. 幂等复制模板文件(用 Glob + Read + Write,跨平台无 shell) + +对下表每个文件:先用 `Glob` 判断目标路径是否已存在;**已存在则跳过**(不覆盖,幂等);不存在则用 `Read` 读模板、用 `Write` **原样**写到目标路径(`Write` 会自动创建缺失的父目录 `docs/01-需求清单/`,无需 `mkdir`)。 + +| 模板 | 目标路径 | +|---|---| +| `${CLAUDE_SKILL_DIR}/templates/CLAUDE-template.md` | `CLAUDE.md` | +| `${CLAUDE_SKILL_DIR}/templates/docs-01-index-template.md` | `docs/01-需求清单/index.md` | +| `${CLAUDE_SKILL_DIR}/templates/docs-04-stack-template.md` | `docs/04-技术规范.md` | +| `${CLAUDE_SKILL_DIR}/templates/docs-08-initial-template.md` | `docs/08-模块任务管理.md` | + +完成后,用 `Edit` 在 `docs/08-模块任务管理.md` 中勾选: +- ` - [ ] 项目文件骨架已创建(CLAUDE.md + docs/01-需求清单/index.md + docs/04-技术规范.md)` + +### B. 依赖检查(跨平台,只检测不自动安装) + +对 **git、mysql、node** 三个命令做**跨平台 PATH 检测**:缺失则按当前操作系统(`process.platform`)打印对应安装指引并**停下**(不自动安装、不改 PATH——自动包管理在 Windows / 受限环境下不可靠,且静默改 PATH 有副作用)。 + +用 `Bash` 跑下面这段 `node` 脚本(用 `process.platform` 区分 `darwin` / `win32` / `linux`,跨平台检测命令是否在 PATH 上): + +```bash +node -e ' +const { spawnSync } = require("node:child_process"); +const plat = process.platform; +const has = (cmd) => { + const r = plat === "win32" + ? spawnSync("where", [cmd], { stdio: "ignore" }) + : spawnSync("sh", ["-c", "command -v " + cmd], { stdio: "ignore" }); + return r.status === 0; +}; +const guide = { + darwin: { git: "xcode-select --install 或 brew install git", + mysql: "brew install mysql", + node: "brew install node 或见 https://nodejs.org" }, + linux: { git: "sudo apt-get install git / sudo yum install git / sudo apk add git", + mysql: "sudo apt-get install mysql-client / sudo yum install mysql", + node: "sudo apt-get install nodejs 或见 https://nodejs.org" }, + win32: { git: "winget install Git.Git 或见 https://git-scm.com/download/win", + mysql: "winget install Oracle.MySQL 或见 https://dev.mysql.com/downloads/", + node: "winget install OpenJS.NodeJS 或见 https://nodejs.org" }, +}[plat] || {}; +const tools = ["git", "mysql", "node"]; +const missing = tools.filter((t) => !has(t)); +const mark = (t) => (missing.includes(t) ? "✗" : "✓"); +console.log("[project-init] 依赖检查 (" + plat + "): " + tools.map((t) => t + " " + mark(t)).join(" ")); +if (missing.length) { + console.error("[project-init] 缺失依赖,请先安装后重跑:"); + for (const t of missing) console.error(" - " + t + " : " + (guide[t] || "见对应官网")); + process.exit(1); +} +' +``` + +- 退出码 `0`(全部 ✓)→ 进入步骤 C +- 退出码 `1`(有缺失)→ 已打印缺失工具 + OS 安装指引,**停下**,提示用户安装后重跑本 skill + +完成后,用 `Edit` 在 `docs/08-模块任务管理.md` 中勾选: +- ` - [ ] 依赖检查通过` + +### C. 初始化 Git(如尚未初始化) + +用 `Glob` 检查 `.git/` 目录是否存在。 +- 不存在 → 用 `Bash` 执行 `git init`。 +- 已存在 → 跳过。 + +完成后,用 `Edit` 在 `docs/08-模块任务管理.md` 中勾选(A0 子项 + A0 顶层): +- ` - [ ] Git 已初始化` +- `- [ ] A0 项目初始化 — project-init` + +### D. 打印完成横幅并进入 A1 + +向用户输出: + +``` +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + [project-init] 项目初始化完成 + + 已创建: + ✓ CLAUDE.md(从插件模板复制) + ✓ docs/01-需求清单/index.md(待人工填写模块索引) + ✓ docs/04-技术规范.md(默认技术栈,A1 让用户确认) + ✓ docs/08-模块任务管理.md(全流程进度跟踪) + 已勾选:A0 项目初始化 + + 下一步:A1 scope-lock(填写项目概述 + 技术栈 + 需求索引 + REQ 卡片) +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +``` + +立即调用 `Skill(scope-lock)` 进入 A1,不等用户手动输入。 + +## 参考 + +- `${CLAUDE_SKILL_DIR}/templates/CLAUDE-template.md`(项目级 CLAUDE.md 模板) +- `${CLAUDE_SKILL_DIR}/templates/docs-01-index-template.md`(需求索引初稿) +- `${CLAUDE_SKILL_DIR}/templates/docs-04-stack-template.md`(默认技术栈) +- `${CLAUDE_SKILL_DIR}/templates/docs-08-initial-template.md`(A 阶段进度初始化) +- 下游:`scope-lock`(A1,自动派发) diff --git a/skills/plan/project-init/templates/CLAUDE-template.md b/skills/plan/project-init/templates/CLAUDE-template.md new file mode 100644 index 0000000..776a923 --- /dev/null +++ b/skills/plan/project-init/templates/CLAUDE-template.md @@ -0,0 +1,255 @@ +# CLAUDE.md — ERP项目 Claude Code 主指令文件 + +> 本文件是 Claude Code 的"操作手册"。Claude Code 启动时会自动读取此文件。 + +--- + +## 🎯 项目概述 + +- **项目名称**: 【人工填写:公司 + 项目名,例如"XX 公司 ERP 管理系统"】 +- **项目简述**: 【人工填写:一句话描述项目目标,例如"面向中小制造企业的全流程 ERP,涵盖采购/库存/生产/销售/财务"】 +- **目标用户**: 【人工填写:谁会用,例如"企业内部管理人员(采购员、仓管员、生产主管、销售员、财务人员、管理层)"】 +- **部署方式**: 【人工填写:私有化部署 / 云部署 / Docker 容器化 等】 + +--- + +## 🔄 B 阶段开发流程(后端模块循环 → 前端整体阶段) + +B 阶段整体是**一个静默 Workflow 脚本 `workflows/coding.mjs`**(由瘦入口 skill 启动)。入口:`/erp-workflow:coding-start`。子代理无法弹窗 → 缺值即写阻塞点并 halt(结构性静默)。 + +### 入口与路由(coding-start skill → coding.mjs Router) + +`/erp-workflow:coding-start` 是瘦入口:校验 Plan 终结闸(docs/08 § 一 全勾、git 在默认分支、工作树干净)后,调用 `Workflow({scriptPath:"…/workflows/coding.mjs", args:{projectRoot}})` 启动整个编码阶段。`coding.mjs` 的 **Router** stage 扫描 docs/08 § 二/§ 三 里程碑字段 + 本地 `git tag -l`,产出结构化模块清单(`{id, done, reqs[], feItems[]}`),过滤待跑模块;docs/08 字段与 git tag 不一致 → halt。 + +| `backend_done` | `frontend_done` | 行为 | +|---|---|---| +| `false` | 任意 | Router 列出待跑后端模块,进入后端模块循环 | +| `true` | `false` | 进入前端阶段(`feItems` 非空的模块) | +| `true` | `true` | "所有阶段已完成" | + +### 后端阶段(每模块一个里程碑 tag) + +- **模块循环(顶层 `for module`,fail-fast)**:`featureLoop(reqs,'backend')` → `testGate('backend')`(红色自动重试 1 次防 flaky,仍红 → HALT)→ 跨模块改动记录 → 模块报告 → milestone(本地 `git merge --no-ff` 进默认分支 + 打 `milestone/` tag + 回写 docs/08 § 二)→ 下一模块(无人工介入) +- **功能循环(内,每 REQ-XXX-NNN 一遍,同构 `featureLoop`)**:spec → plan → tdd → verify → review(`reviewWithFixLoop` 有界 5 轮:approve 即过;request-changes → fix → 重审;第 5 轮仍未过 → HALT) +- 后端阶段任务严格落在 `backend/` 路径下;docs/01 REQ 卡片的 UI 描述在此阶段忽略,UI 推迟到前端阶段。 + +### 前端阶段(整体一个里程碑 tag,所有后端模块打里程碑后启动) + +- **FE 清单(AI 自主推导,无审阅断点)**:FE 业务功能清单在 Plan 阶段 A6 + Router 阶段确定并写入 `docs/08 § 三`。**FE 是业务功能粒度,与 prototype HTML 文件数无关**——一个 HTML 可拆多个 FE,多个 HTML 也可合成一个 FE。 +- **FE 循环(外)**:`featureLoop(feItems,'frontend')` → `testGate('frontend')` → milestone(分支 `frontend-phase`,docs/08 § 三 整体里程碑)。 +- **FE 功能循环(内,每个 FE-NN 一遍,同构 `featureLoop`)**:spec → plan → tdd → verify → review(统一 `code-reviewer` agent,`phase=frontend` 附加 7 维 checklist) +- 前端阶段任务严格落在 `frontend/` 路径下;布局以 `prototype/` 为权威。 + +### 里程碑前测试闸门 + +- `coding.mjs` 的 **testGate** stage:后端阶段子代理跑 `scripts/test.mjs`(含本模块新增 + 已合并模块回归);前端阶段跑 vitest + playwright(命令取自 docs/04 § 零)。 +- testGate 是打里程碑 tag 前唯一的硬测试门;红色重试 1 次仍红 → HALT,不得跳过进入 report / milestone stage。 + +--- + +## ✅ 阶段完成判定规则 + +`docs/08-模块任务管理.md` 分两段: +- `§ 二`:后端模块元数据表(每个模块一行 bullet,记录依赖 / 路径 / 里程碑 tag / 功能子项) +- `§ 三`:前端阶段元数据(整体里程碑 + FE 子项清单,由 Plan 阶段 A6 + `coding.mjs` 在所有后端模块打里程碑后填入) + +**阶段完成判定**统一以 `里程碑:` 字段(§ 二 各模块) / `整体里程碑:` 字段(§ 三)+ 本地 `git tag -l 'milestone/'` 判定;子项勾选只作可视化进度,不参与完成判定。 + +### 后端模块格式 + +每个后端模块在 docs/08 § 二 中长这样: + +```markdown +- module_sys 系统管理 + - 依赖: — + - 路径: backend/module/sys/ + - 里程碑: — + - 功能: + - [ ] REQ-SYS-001 用户登录 + - [ ] REQ-SYS-002 用户注册 +``` + +- `里程碑:` 字段由 `coding.mjs` 的 milestone stage 在打里程碑 tag 时从 `—` 改为 `milestone/`。 +- 每个 `REQ-*` 子项由 `coding.mjs` 的 review stage 在 `verdict=approve` 时自动勾选为 `[x]`。 +- 路径限定为后端目录(如 `backend/module/sys/`);前端代码不在此阶段产生。 + +### 前端阶段格式(§ 三) + +```markdown +- 整体里程碑: — +- 功能: + - [ ] FE-01 用户登录与注册 | 关联 REQ:REQ-SYS-001, REQ-SYS-002 | 关联原型:prototype/auth.html + - [ ] FE-02 仪表盘总览 | 关联 REQ:REQ-DASH-001 | 关联原型:prototype/dashboard.html +``` + +- `整体里程碑:` 字段由 `coding.mjs` 的 milestone stage 在打前端里程碑 tag 时从 `—` 改为 `milestone/frontend-phase`。 +- "功能:" 列表由 Plan 阶段 A6(`frontend-scope-lock`)+ `coding.mjs` 推导写入(无人工审阅断点)。FE 是业务功能粒度,与 prototype HTML 文件数无关。 +- 每个 `FE-NN` 子项由 `coding.mjs` 的 review stage 在 `verdict=approve` 时自动勾选为 `[x]`。 +- prototype/ 门禁在 Plan 阶段 A6 `frontend-scope-lock` 强制检查项目根 `prototype/` 至少含 1 个 `*.html` mockup。 + +### 状态语义(后端模块 + 前端阶段共用) + +| `里程碑:` 字段 | `git tag -l` | 含义 | 你(Claude Code)的行为 | +|---|---|---|---| +| `—` | tag 不存在 | 该阶段未开始 / 进行中(未打里程碑) | ✅ 开始 / 继续该阶段开发 | +| `milestone/` | tag 存在 | 阶段**已完成** | 🟢 后端:进入下一未完成模块;后端全完 → 前端阶段;前端已打里程碑 → 全部完成 | + +### 模块完成报告 + +由 `coding.mjs` 的 report stage 产出(12 节标准化,含跨模块改动等 CLAUDE.md 软规则映射节)。CC 不手写模块报告。 + +--- + +## 🏷️ 占位符统一约定 + +项目文档里有 **2 种填写占位** + **1 种提示占位**: + +| 格式 | 谁填 | 使用阶段 | 说明 | +|------|-----|---------|------| +| `【人工填写:<简短说明>】` | 人 | 仅 A 阶段文档 | 密钥 / 账密 / 包名 / 命名约定 / 小版本号等人工才能决定的值;B 阶段 plan/spec 禁止出现,查不到真值时用 `AskUserQuestion` 问用户 | +| `TBD(<责任人>)` | CC 自动 | A 或 B | 后缀附带责任方(如 `TBD(A3 自动补)` / `TBD(A5 自动补)`);由对应 skill / `coding.mjs` stage 就地补填,模块完成报告 § ⑦ 检查 `TBD(CC 补)` 残留 | + +**HTML 注释 ``**:提示占位,是**插件内部大纲模板**里给 LLM 的**填空提示 / 章节引导**,指引 LLM 按结构填实际内容。skill 生成时会**剥除**这些注释,最终产物里注释不会保留。 + +--- + +## 📐 编码行为约束 + +### 你必须做的 ✅ + +1. **严格遵循** `docs/04-技术规范.md`——命名 / 编码 / 统一响应 / 异常处理 / 数据访问 / 配置与安全 等项目专属技术规约全部在此 +2. **严格遵循** `docs/09-项目目录结构.md`——文件放对位置 +3. **每个后端接口** 必须先在 `docs/05-API接口契约.md` 定义,再编码实现 +4. **每个功能可追溯到 `REQ-XXX-NNN`**——commit tag + 代码注释(如 `// REQ-SYS-001: 用户登录`)+ plan/spec 文件名均用此 tag +5. **遇到跨模块改动**(动到非当前模块的代码)——按 § 🟡 软规则 **S2** 执行(允许改,但必须留痕) +6. **遇到技术栈外组件引入**(`docs/04 § 零` 技术栈表外的框架 / 中间件 / 关键库),按 § 🟡 软规则 **S1** 执行(允许引入,但必须先 AskUserQuestion) + +### 你禁止做的 🚫 + +1. **主会话直接 `mysql -e` 跑业务 DDL**(只读查询 / 临时本地调试除外)——业务 schema 必须走 `sql/migrations/V_n__*.sql`,详见下方 Schema 演化规约 +2. **手动 Edit `docs/08 § 二/§ 三` 的 `里程碑:` / `整体里程碑:` 字段**,必须要由 `coding.mjs` 的 milestone stage 自动回写 + +### Schema 演化规约(Flyway migration) + +1. **文件命名**:`sql/migrations/V__.sql`,例:`V5__add_user_email_unique_index.sql` +2. **版本号分配**:建文件前 `ls sql/migrations/V*.sql` 查当前最大 n,新文件 `n_max + 1` +3. **Apply 方式**:Spring Boot 启动 / 测试启动时 Flyway 自动 apply(项目必须在 `pom.xml` 声明 `flyway-core` + `flyway-mysql` 依赖)。`scripts/setup-test-db.mjs` 只负责清空库,不做 apply +4. **已合并的 migration 永不修改**:发现错了写一个补救 migration(如 `V7__fix_V5_index_name.sql`),旧 `V_n.sql` +5. **临时调试 DDL**:临时在本地试字段/索引可手动 `mysql -e`,但不写 migration;下次 `setup-test-db.mjs` 会 drop+create 清掉 +6. **A4 生成的 V1**:`V1__initial_schema.sql` 是 A 阶段由 `db-init` 从 `docs/03-数据库设计文档.md`(A3 正向设计的 schema SSoT)翻译生成的初始版本;后续 V2/V3/... 由 B 阶段每个 REQ 按需写入,**同时**反向同步更新 docs/03 对应表小节以保持 SSoT 一致 + +--- + +## 🗂️ Git 提交规范 + +每次提交必须遵循以下格式: + +``` +(): +``` + +- `scope`: 模块名,如 `user` / `inventory` / `order` +- `subject`: 简短描述;业务类(feat / fix / test)必须带 `REQ-XXX-NNN` 后缀 + +`type` 含义: + +| type | 看到它意味着 | +|-----|-------------| +| `feat` | **新能力上线**——用户多了一个功能、接口、页面或业务规则 | +| `fix` | **修 bug**——原来行为错了,这次改对 | +| `refactor` | **重构**——外部行为不变,只改代码结构 / 命名 / 抽象 | +| `docs` | **文档改动**——只动 Markdown / 代码注释,不动实现 | +| `style` | **格式调整**——空白 / 缩进 / import 顺序,逻辑 0 变化 | +| `test` | **只动测试代码**——补用例 / 修 fixture,不碰实现 | +| `chore` | **流程维护**——构建 / 依赖 / 工具 / 证据档案 / 里程碑元数据等非业务动作 | + +--- + +## 🚩 中断机制 + +功能循环(每个功能 REQ-XXX 的 Brainstorm → Plan → TDD → Verify → AI 自审)默认 **静默编程**,但触发以下任何一条必须**立刻停下、记录原因、等人决策**,不得自行绕过: + +| # | 中断 | 例子 | +| - | --- | --- | +| 1 | **测试反复失败** | 同一测试同一功能内连续 **10 次**修复失败 | +| 2 | **要改密钥 / 账密 / 包名** | 密钥 / 账密 在 `.env.local`、包名 / 命名空间 / 端口等在 `config-vars.yaml` 里由人工标注必须填的字段(规则见 `docs/07-环境配置.md`) | +| 3 | **外部接口不可达** | 第三方 API 无法连接、证书失效等环境问题,并无法自行解决 | + +> 其余需要人类判断的场景一律走普通 `AskUserQuestion` Q&A,不中断、不写 Blocker 文件。 + +**触发中断时的固定动作:** + +1. `coding.mjs` 子代理在当前功能的 plan 文件里追加一节 `## 🚩 Blocker`(记录原因 / 阻塞点),并 throw 进入 HALT 终止态 +2. 整阶段 fail-fast:halt 后停止后续所有模块/功能的静默执行 +3. Workflow 返回结构化诊断(halt 原因 + blocker 文件路径),等人修复后重跑 `/erp-workflow:coding-start` 从断点续跑 + +--- + +## 🟡 软规则(允许继续,但有强制后续动作) + +以下情况 **不触发中断**,CC 可自行继续推进,但必须在约定位置留痕,模块完成时统一审计。 + +| # | 软规则 | 允许动作 | 强制后续 | +| - | ----- | ------- | ------- | +| S1 | **技术栈外组件引入** | 用 `AskUserQuestion` 给用户三选一:接受引入 / 换方案 / 拒绝 | ① **接受** → 同会话直接在 `docs/04 § 零` 追加一行 → 继续流程 ② **换方案 / 拒绝** → 视为常规歧义澄清,继续 Q&A 收敛 ③ 不写 Blocker、不中断流程 | +| S2 | **跨模块改动** | **默认不改**,仅为当前模块实现所必需时允许修改 | `coding.mjs` 的 cross-module stage 在模块循环内记录改动并补「原因 / 影响评估」,「跨模块改动」节完整贴入《模块完成报告》 | + +--- + +## 🧭 通用工作准则(General Principles) + +### 1. Think Before Coding + +**Don't assume. Don't hide confusion. Surface tradeoffs.** + +Before implementing: +- State your assumptions explicitly. If uncertain, ask. +- If multiple interpretations exist, present them - don't pick silently. +- If a simpler approach exists, say so. Push back when warranted. +- If something is unclear, stop. Name what's confusing. Ask. + +### 2. Simplicity First + +**Minimum code that solves the problem. Nothing speculative.** + +- No features beyond what was asked. +- No abstractions for single-use code. +- No "flexibility" or "configurability" that wasn't requested. +- No error handling for impossible scenarios. +- If you write 200 lines and it could be 50, rewrite it. + +Ask yourself: "Would a senior engineer say this is overcomplicated?" If yes, simplify. + +### 3. Surgical Changes + +**Touch only what you must. Clean up only your own mess.** + +When editing existing code: +- Don't "improve" adjacent code, comments, or formatting. +- Don't refactor things that aren't broken. +- Match existing style, even if you'd do it differently. +- If you notice unrelated dead code, mention it - don't delete it. + +When your changes create orphans: +- Remove imports/variables/functions that YOUR changes made unused. +- Don't remove pre-existing dead code unless asked. + +The test: Every changed line should trace directly to the user's request. + +### 4. Goal-Driven Execution + +**Define success criteria. Loop until verified.** + +Transform tasks into verifiable goals: +- "Add validation" → "Write tests for invalid inputs, then make them pass" +- "Fix the bug" → "Write a test that reproduces it, then make it pass" +- "Refactor X" → "Ensure tests pass before and after" + +For multi-step tasks, state a brief plan: +``` +1. [Step] → verify: [check] +2. [Step] → verify: [check] +3. [Step] → verify: [check] +``` + +Strong success criteria let you loop independently. Weak criteria ("make it work") require constant clarification. diff --git a/skills/plan/project-init/templates/docs-01-index-template.md b/skills/plan/project-init/templates/docs-01-index-template.md new file mode 100644 index 0000000..08e326a --- /dev/null +++ b/skills/plan/project-init/templates/docs-01-index-template.md @@ -0,0 +1,16 @@ +# 需求清单 + +> 本目录按模块组织所有功能需求。每个模块一个子目录,含 `_module.md`(模块头)和 `REQ-XXX-NNN.md`(每张 REQ 卡片一个文件)。下方核心功能点供 CC 拆分出 REQ 编号 + 标题 + 草拟规则;卡片内输入 / 输出的简述句和 N 张字段表由人工编辑。 + +## 模块索引 + +| 模块代码 | 模块名称 | 核心功能点(简要) | +|----------|----------|--------------------| +| 【人工填写:模块代码】 | 【人工填写:模块名称】 | 【人工填写:核心功能点】 | +| SYS | 系统管理 | 用户/角色/权限/部门/字典 等 | + +## 填写说明 + +1. 每个模块占一行,`模块代码` 用大写英文缩写(如 SYS / PUR / INV / SAL / FIN / HR) +2. `核心功能点` 只需列关键词,CC 会基于此拆分出 N 张 REQ 卡片骨架(卡片内输入 / 输出的简述句和字段表仍由人工编辑) +3. 填完后运行 `/erp-workflow:plan-start`,CC 会自动检测并进入需求生成阶段 diff --git a/skills/plan/project-init/templates/docs-04-stack-template.md b/skills/plan/project-init/templates/docs-04-stack-template.md new file mode 100644 index 0000000..234b200 --- /dev/null +++ b/skills/plan/project-init/templates/docs-04-stack-template.md @@ -0,0 +1,32 @@ +# 04-技术规范 + +## 零、技术栈总览 + +| 分层模块 | 技术 | 版本要求 | 说明 | +|---|---|---|---| +| 前端基础框架 | React | 18.x | 构建前端应用 | +| 前端 UI 组件 | Ant Design | 5.x | 页面组件与交互控件 | +| 前端状态管理 | Redux Toolkit | 最新稳定版 | 管理全局状态 | +| 前端路由管理 | React Router | v6 | 页面路由与导航 | +| 前端工程化构建 | Vite | 最新稳定版 | 前端开发与打包构建 | +| 前端接口通信 | Axios | 最新稳定版 | 调用后端 API | +| 后端基础框架 | Spring Boot | 3.x | 构建后端服务 | +| 后端数据访问 | MyBatis-Plus | 最新稳定版 | 数据库访问与 ORM 增强 | +| 工作流引擎 | Activiti | 6.x | 审批流、流程流转 | +| 缓存服务 | Redis | 最新稳定版 | 缓存、会话、分布式能力 | +| 报表打印 | JXLS | 2.8.1 | 基于 Excel 模板生成报表 | +| Excel 导入导出 | EasyExcel | 4.0.3 | Excel 数据导入导出 | +| 关系型数据库 | MySQL | 8.x | 核心业务数据存储 | +| 数据库 schema 迁移 | Flyway (`flyway-core` + `flyway-mysql`) | 10.x / 最新稳定版 | `sql/migrations/V_n__*.sql` 顺序 apply;Spring Boot 启动时自动应用 | +| 接口风格 | RESTful API | 统一规范 | 前后端接口设计规范 | +| 权限认证 | Spring Security / JWT | 最新稳定版 | 登录认证、权限控制 | +| API 文档 | OpenAPI / Swagger | 最新稳定版 | 接口文档与调试 | +| 项目构建管理 | Maven | 3.9.x | Java 项目依赖与构建 | +| JDK 运行环境 | Java | 17 / 21 | Spring Boot 3 推荐版本 | +| 部署容器 | Docker | 最新稳定版 | 容器化部署 | +| Web 服务器 / 反向代理 | Nginx | 最新稳定版 | 前端托管、反向代理、负载分发 | +| 日志管理 | Logback | 默认集成 / 最新稳定版 | 应用日志输出 | +| 对象映射工具 | MapStruct | 最新稳定版 | DTO / VO / Entity 转换 | +| 工具类库 | Hutool / Apache Commons | 最新稳定版 | 常用工具方法支持 | + +> 本表由 scope-lock 锁定。后续所有规范基于此表推导。 diff --git a/skills/plan/project-init/templates/docs-08-initial-template.md b/skills/plan/project-init/templates/docs-08-initial-template.md new file mode 100644 index 0000000..61fc530 --- /dev/null +++ b/skills/plan/project-init/templates/docs-08-initial-template.md @@ -0,0 +1,76 @@ +# 08-工作流进度 + +> 全流程进度跟踪。CC 每完成一项产出就勾选一项。 +> - **§ 一 Plan(A0~A6)**:`plan-start` 找第一个未勾 A 子项分发到对应 skill +> - **§ 二 Coding(模块)**:分发以 `docs/02-开发计划.md § 二 开发顺序清单` 为准;`coding-start` 按 docs/02 顺序扫描,对每个 REQ 所属模块查询本 § 二的 `里程碑:` 字段 + 本地 `git tag -l 'milestone/'`,找第一个未打里程碑模块分发。本 § 二 行序无语义,仅作模块元数据表 + +## 一、Plan 阶段(一次性) + +- [ ] A0 项目初始化 — project-init + - [ ] 依赖检查通过 + - [ ] 项目文件骨架已创建(CLAUDE.md + docs/01-需求清单/index.md + docs/04-技术规范.md) + - [ ] Git 已初始化 + +- [ ] A1 范围锁定 — scope-lock + - [ ] 项目概述已填写(CLAUDE.md § 🎯 项目概述) + - [ ] 技术栈已确认(docs/04 § 零) + - [ ] 需求清单索引已填写(docs/01-需求清单/index.md) + - [ ] REQ 卡片骨架已生成(docs/01-需求清单//REQ-*.md,业务内容留待人工填写) + +- [ ] A2 骨架生成 — skeleton-gen + - [ ] 架构文档已生成(docs/04 § 一+、docs/06、docs/07、docs/09) + - [ ] 工具脚本已生成(scripts/*.mjs、.env.local) + - [ ] 样式 token 骨架已生成(src/styles/tokens.css) + - [ ] .gitignore 已配置 + +- [ ] A3 DB 设计 + REQ 回填 — db-design-gen + - [ ] docs/03-数据库设计文档.md 已生成 + - [ ] docs/01 各 REQ 卡片"依赖表" + 模块头"涉及表" 已回填 + +- [ ] A4 DB 初始化 — db-init + - [ ] sql/migrations/V1__initial_schema.sql 已生成 + - [ ] DDL 与 docs/03 全量一致 + - [ ] .env.local 凭据已验证(mysql -e "SELECT 1" OK) + - [ ] setup-test-db.mjs 防护通过 + DROP+CREATE + apply V1 已执行 + - [ ] DDL ↔ docs/03 apply 后 5 维一致(validate-ddl.mjs) + +- [ ] A5 下游文档生成 — downstream-gen + - [ ] docs/02 开发计划已生成 + - [ ] docs/05 API 契约已生成 + - [ ] docs/06 § 三 页面清单已填入 + - [ ] docs/10 验收清单已生成 + - [ ] 下方模块列表已填入 + - [ ] REQ 卡片依赖接口已回填 + +- [ ] A6 前端范围锁定 — frontend-scope-lock + - [ ] docs/06 项目级 UI 约定 + Design Tokens + 组件库已锁定 + - [ ] docs/04 § 二 前端栈已锁定(引用 docs/06) + - [ ] 各 FE-NN 设计决策表已生成(docs/06 § 三之后 / docs/08 § 三) + +## 二、Coding 阶段(后端模块循环) + +(A5 填入后,每行一个后端模块。每个模块的 `里程碑:` 字段在 `—` 和 `milestone/` 之间变化,完成由本地 `git tag -l` 判定。`coding-start` 每次按 docs/02 REQ 序扫每模块的里程碑 tag 决定派发。后端模块全部打里程碑后自动进入 § 三 前端阶段。) + + + +## 三、Coding 阶段(前端整体) + +(FE 业务功能清单在 Plan 期 A6 `frontend-scope-lock` 由 prototype/ + docs/01 + docs/05 推导后写入下方"功能:"项;Coding 阶段 `coding.mjs` 的 Router 把全部未完成 FE 聚合为单一 `frontend-phase` 阶段,排在所有后端模块之后。整个前端阶段 1 个里程碑 tag,分支 `frontend-phase`。) + +- 整体里程碑: — +- 功能: + diff --git a/skills/plan/scope-lock/SKILL.md b/skills/plan/scope-lock/SKILL.md new file mode 100644 index 0000000..bbe71c2 --- /dev/null +++ b/skills/plan/scope-lock/SKILL.md @@ -0,0 +1,231 @@ +--- +name: scope-lock +description: A1 计划范围锁定——引导用户填写项目概述 + 技术栈 + 需求索引,并按模块子目录生成 REQ 卡片骨架(CC 推断 req_id/title/goal/rules/constraints/acceptance;输入/输出 字段表为结构化 6 列表单由人工逐行填真实数据);末尾执行 A1 终结校验:每张 REQ 卡片字段含真实数据、配置字段名锁进 config-vars.yaml(非敏感填值 + secrets_ref 键名引用 .env.local)、build/lint/unit/e2e 命令锁进 docs/04 §零,缺则当场 AskUserQuestion 问清。 +user-invocable: false +allowed-tools: Read Write Edit Grep Glob Skill AskUserQuestion Bash(mkdir *) Bash(node *) Bash(rm *) +--- + +**所有输出必须使用中文。** + +# scope-lock + +> **关于 AskUserQuestion**:下文只描述「问什么、给哪些选项、各选项导向什么后续」。`header` / 各选项的 `description` / `multiSelect` 等具体参数由你按工具 schema 自行填全合法值——不要把下文的选项文字当成完整调用照抄。 + +## 执行步骤 + +### A. 提示用户填写项目概述并等待 + +向用户输出: + +``` +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + [scope-lock] 请填写项目概述 + + 📄 文件位置: ./CLAUDE.md + 📌 编辑位置: § 🎯 项目概述 + + 请将以下占位符替换为实际值: + - 项目名称 + - 项目简述 + - 目标用户 + - 部署方式 + 改完后回来选择「继续」。 +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +``` + +用 `AskUserQuestion` 确认「项目概述填写完毕了吗?」,给「继续」和「有疑问想先沟通」两个选项。 + +- 选「继续」→ 用 `Grep` 在 `CLAUDE.md` 搜索 `【人工填写:`(限定 § 🎯 项目概述 节)。命中 → 打印残留行 + 路径,重新确认一次;0 命中 → 勾选并进入步骤 B。 +- 选「有疑问想先沟通」→ 回答用户问题后,再确认一次。 + +0 命中后,用 `Edit` 在 `docs/08-模块任务管理.md` 中勾选: +- ` - [ ] 项目概述已填写(CLAUDE.md § 🎯 项目概述)` + +### B. 提示用户检查默认技术栈并等待 + +`docs/04-技术规范.md` 已由 A0 `project-init` 用模板复制(默认技术栈,见 `project-init/templates/docs-04-stack-template.md`)。本步骤让用户检查 / 调整 § 零。 + +向用户输出: + +``` +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + [scope-lock] 技术栈已保存 + + 📄 文件位置: ./docs/04-技术规范.md(由 A0 模板生成) + 📌 编辑位置: § 零、技术栈总览 + + 请检查技术栈表: + - 不需要的行直接删除(如纯后端项目删前端行) + - 需要替换的技术直接改 + - 需要新增的条目直接加行 + 改完后回来选择「继续」。 +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +``` + +用 `AskUserQuestion` 确认「技术栈检查完毕了吗?」,给「继续」和「有疑问想先沟通」两个选项。 + +- 选「继续」→ 进入步骤 C。 +- 选「有疑问想先沟通」→ 回答用户问题后,再确认一次。 + +完成后,用 `Edit` 在 `docs/08-模块任务管理.md` 中勾选: +- ` - [ ] 技术栈已确认(docs/04 § 零)` + +### C. 提示用户填写需求清单并等待 + +`docs/01-需求清单/index.md` 已由 `project-init` 写入占位符模板,这里让用户补齐模块清单。 + +向用户输出: + +``` +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + [scope-lock] 请填写需求清单模块索引 + + 📄 文件位置: ./docs/01-需求清单/index.md + 📌 编辑位置: § 模块索引(表格) + + 请按业务列出所有模块: + - 每行一个模块(如 SYS 系统管理 / PUR 采购 / SAL 销售) + - 「核心功能点」只需关键词,CC 会拆分为 REQ 卡片 + 改完后回来选择「继续」。 +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +``` + +用 `AskUserQuestion` 确认「需求清单模块索引填写完毕了吗?」,给「继续」和「有疑问想先沟通」两个选项。 + +- 选「继续」→ 进入步骤 D。 +- 选「有疑问想先沟通」→ 回答用户问题后,再确认一次。 + +完成后,用 `Edit` 在 `docs/08-模块任务管理.md` 中勾选: +- ` - [ ] 需求清单索引已填写(docs/01-需求清单/index.md)` + +### D. 生成 REQ 卡片骨架并停下等人工审阅 + +1. 用 `Grep` 校验 `docs/01-需求清单/index.md` 无 `【人工填写:` 残留;有则回步骤 C。 +2. 用 `Read` 读 `index.md` 解析模块索引。 +3. **逐文件渲染落盘**(用 Node 渲染助手,跨平台、字面量安全): + + - **每模块推断**:三元组 `{module_code, module_name, module_brief}` + N 个 REQ 的六元组 `{req_id, title, goal, rules, constraints, acceptance}`。`req_id`/`title` 从核心功能点拆分;`goal` 展开 `title`;`rules`/`constraints`/`acceptance` 起草业务语义。**不推断**输入 / 输出字段(模板的结构化字段表保留示例行,留待人工逐行填真实数据)。 + - **渲染助手** `lib/render.mjs` 的 CLI 形态为 `node <模板路径> <输出路径>`:读模板 + 读 JSON 变量 + 占位符字面替换 + 自动剥离 HTML 注释,写到输出路径。值含 `$`、`{`、`}`、`}}` 均按字面插入,无需兜底。 + - **每个文件三步**:(a) 用 `Write` 写一个临时 vars JSON(仅含该文件用到的占位符键值);(b) `mkdir -p` 模块目录;(c) `node` 调 render.mjs 渲染。`` / `<模块名>` / `` 等尖括号位置 CC 按 `index.md` 实际值替换。调用形态: + + ```bash + # 模块头:先 Write docs/01-需求清单/-<模块名>/_module.vars.json,内容形如 + # {"module_code":"","module_name":"<模块名>","module_brief":""} + mkdir -p "docs/01-需求清单/-<模块名>" + node "${CLAUDE_PLUGIN_ROOT}/lib/render.mjs" \ + "${CLAUDE_SKILL_DIR}/templates/_module-template.md" \ + "docs/01-需求清单/-<模块名>/_module.vars.json" \ + "docs/01-需求清单/-<模块名>/_module.md" + + # 每个 REQ:先 Write 该 REQ 的 vars JSON,内容形如 + # {"req_id":"","title":"","goal":"<goal>","rules":"<rules>","constraints":"<constraints>","acceptance":"<acceptance>"} + node "${CLAUDE_PLUGIN_ROOT}/lib/render.mjs" \ + "${CLAUDE_SKILL_DIR}/templates/req-card-template.md" \ + "docs/01-需求清单/<MOD>-<模块名>/<REQ-MOD-NNN>.vars.json" \ + "docs/01-需求清单/<MOD>-<模块名>/<REQ-MOD-NNN>.md" + ``` + + - 渲染完成后删除临时 `*.vars.json`(`rm` 或不留亦可,不进入交付物)。 +4. 用 `Edit` 在 `docs/08-模块任务管理.md` 勾选(A1 子项): + - ` - [ ] REQ 卡片骨架已生成(docs/01-需求清单/<module>/REQ-*.md,业务内容留待人工填写)` + + **注意**:此处先**不**勾选 `- [ ] A1 范围锁定 — scope-lock` 顶层项;A1 顶层项必须在步骤 E(A1 终结校验)全部通过后才勾选。 +5. 打印「请人工填写 REQ 卡片」横幅并提示用户填完后回来继续(不停止,下一步是 A1 终结校验): + +``` +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + [scope-lock] REQ 卡片骨架已生成 + + 产出: + ✓ docs/01-需求清单/<module>/_module.md 模块头 + ✓ docs/01-需求清单/<module>/REQ-*.md REQ 卡片骨架 + + ⏸ 现在请你逐张打开 REQ 卡片,把结构化字段表填成真实数据: + - **必改**:`输入字段` / `输出字段` 两张表 + · 删掉「【示例行,替换为真实字段】」示例行,按本 REQ 业务逐行填真实字段 + · 6 列全部填:字段名 / 类型 / 必填 / 校验规则 / 业务规则 / 示例值 + · **「示例值」列必须是真实约束下的合法取值**——留 `<示例值>` 或示例行会被 A1 终结校验阻断 + - **审阅**:目标 / 跨字段规则 / 边界 / 验收(已起草,对照业务校正) + - **保留**:`TBD` 不要改,由之后流程自动回填 + + 填完后回来选择「继续」,进入 A1 终结校验。 +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +``` + +用 `AskUserQuestion` 确认「所有 REQ 卡片的结构化字段都填成真实数据了吗?」,给「继续」和「有疑问想先沟通」两个选项。 + +- 选「继续」→ 进入步骤 E(A1 终结校验)。 +- 选「有疑问想先沟通」→ 回答用户问题后,再确认一次。 + +### E. A1 终结校验(硬闸:全部通过才勾选 A1 顶层) + +> 本步骤把原本会在编码期(coding.mjs 的 spec / plan stage)弹出的需求澄清 / config Q&A **全部前移到此处**。任一检查不满足,用 `AskUserQuestion` 在**此处(Plan 期)**问清并修订,**禁止**留待编码期。三项检查全过后才在 `docs/08` 勾选 `- [ ] A1 范围锁定 — scope-lock`。 + +#### E.1 真实数据校验(每张 REQ 卡片) + +1. 用 `Glob` 列出所有 `docs/01-需求清单/<module>/REQ-*.md`。 +2. 对每张卡片用 `Read` + `Grep` 校验: + - **无模板默认占位**:卡片内**不得**出现 `【示例行,替换为真实字段】` 或 `<示例值>`(用 `Grep` 搜这两个字面量,命中即视为未完成)。 + - **结构化字段非空**:`输入字段` / `输出字段` 两张表每行 6 列均非空,且不是模板示例行内容;至少各有 1 行真实字段(除非该 REQ 确实无输入/输出,需在卡片显式标注)。 + - **`示例值` 列已填真实取值**:每行示例值列为真实约束下的合法取值,非占位。 + - **`{{...}}` 残留**:不得残留任何 `{{` 占位(说明渲染未替换)。 +3. 任一卡片不通过:打印不通过的卡片路径 + 具体缺口行,用 `AskUserQuestion` 引导用户当场补齐(可针对具体字段含义/校验规则发问),修订后重跑 E.1,直到全部通过。 + +#### E.2 配置字段名锁进 config-vars.yaml(敏感键名引用 .env.local) + +1. 用 `Read` 读 `docs/04-技术规范.md` § 零技术栈,结合 REQ 卡片,盘点本项目需人工提供 / 确认的配置字段,分两类: + - **非敏感、项目级**:后端根包名 / 命名空间(Java package / C# namespace / Python 顶层包 / Go module path 等)、应用端口、前端包名 / scope、前端 dev 端口、管理员初始账号等。 + - **敏感凭据**:数据库密码、JWT / 签名密钥、Redis 密码、第三方 API key/secret、OSS / 对象存储凭证、短信 / 邮件服务凭证、管理员初始密码等。 +2. 用 `Read` 读模板 `${CLAUDE_SKILL_DIR}/templates/config-vars-template.yaml`,用 `Write` 落盘到仓库根 `config-vars.yaml`: + - **非敏感字段**:按技术栈推断默认值直接填入(如 `http_port: 8080`、`base_package: com.<org>.<app>`);无对应技术栈的整节删除(如纯后端项目删 `frontend:`);无法可靠推断的留 `【人工填写:…】`(A2 skeleton-gen 补填)。 + - **敏感字段**:只把「键名 + 含义」登记进 `secrets_ref` 列表,**绝不写真实值**(真实值由 A2 写进 `.env.local`,A2 据 `secrets_ref` 核对齐全)。 +3. **不**在此创建 / 填写 `docs/07-环境配置.md`——它由 A2 skeleton-gen 生成,只记规则不记具体值。 +4. 用 `AskUserQuestion` 向用户确认:「以下配置 / 凭据字段已登记进 config-vars.yaml,是否齐全?还有遗漏的吗?」展示非敏感字段 + `secrets_ref` 键名清单。用户补充则继续登记,直到确认齐全。 + +#### E.3 build / lint / unit / e2e 命令锁进 docs/04 § 零 + +1. 用 `Read` 读 `docs/04-技术规范.md` § 零技术栈表,确定本项目涉及的每个 stack(如后端、前端,可能多个)。 +2. 对**每个 stack**,用 `AskUserQuestion`(如默认值可推断则展示默认值让用户确认/覆盖)收集四类命令: + - **build**(构建命令,如 `mvn package` / `npm run build`) + - **lint**(静态检查命令,如 `npm run lint`) + - **unit**(单元测试命令,如 `mvn test` / `npm run test:unit`) + - **e2e**(端到端测试命令,如 `npm run test:e2e`;无则显式记 `无`) +3. 把确认后的命令写入 `docs/04-技术规范.md` § 零(若 § 零无「命令」小节则用 `Edit` 新增一个「命令清单」小节,按 stack 分组列出 build/lint/unit/e2e 四行)。这些命令是 Coding 阶段 `coding.mjs` 的 tdd / test-gate 读取来源,必须在此锁全。 + +#### E.4 全部通过后勾选 A1 顶层并停止 + +三项检查(E.1 / E.2 / E.3)全部通过后: + +1. 用 `Edit` 在 `docs/08-模块任务管理.md` 勾选 `- [ ] A1 范围锁定 — scope-lock` 顶层项。 +2. 打印 A1 完成横幅并**停止**: + +``` +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + [scope-lock] ✅ A1 范围锁定完成(终结校验通过) + + 产出 & 锁定: + ✓ CLAUDE.md § 🎯 项目概述 + ✓ docs/04 § 零 技术栈 + build/lint/unit/e2e 命令 + ✓ docs/01-需求清单/index.md 模块索引 + ✓ docs/01-需求清单/<module>/_module.md 模块头 + ✓ docs/01-需求清单/<module>/REQ-*.md 字段表已填真实数据 + ✓ config-vars.yaml 配置字段 + secrets_ref 键名已锁(敏感真实值留待 A2 .env.local) + + 运行以下命令继续进入 A2: + /erp-workflow:plan-start + +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +``` + +## 参考 + +- `CLAUDE.md` § 🎯 项目概述(写入目标) +- `docs/04-技术规范.md`(技术栈输出,供 skeleton-gen 读取使用) +- `docs/01-需求清单/index.md`(模块索引输入) +- `docs/01-需求清单/<module>/_module.md`(模块头输出) +- `docs/01-需求清单/<module>/REQ-*.md`(REQ 卡片骨架输出,A3 db-design-gen / A5 downstream-gen 会回填 TBD 字段) +- `config-vars.yaml`(A1 终结校验 E.2 输出:非敏感配置字段填值 + secrets_ref 键名锁定;仓库根) +- `${CLAUDE_SKILL_DIR}/templates/config-vars-template.yaml`(E.2 渲染来源;跨栈中立,YAML 注释引导) +- `${CLAUDE_SKILL_DIR}/templates/req-card-template.md`(结构化 6 列字段表) +- `${CLAUDE_SKILL_DIR}/templates/_module-template.md` +- `${CLAUDE_PLUGIN_ROOT}/lib/render.mjs`(步骤 D 渲染助手;CLI 形态 `node render.mjs <模板> <vars.json> <输出>`,字面量安全 + 自动剥 HTML 注释) diff --git a/skills/plan/scope-lock/templates/_module-template.md b/skills/plan/scope-lock/templates/_module-template.md new file mode 100644 index 0000000..5425b83 --- /dev/null +++ b/skills/plan/scope-lock/templates/_module-template.md @@ -0,0 +1,5 @@ +# {{module_code}}-{{module_name}} + +- **模块简述**: {{module_brief}} +- **依赖模块**: TBD(A5 自动补) +- **涉及表**: TBD(A3 自动补) diff --git a/skills/plan/scope-lock/templates/config-vars-template.yaml b/skills/plan/scope-lock/templates/config-vars-template.yaml new file mode 100644 index 0000000..f986f4e --- /dev/null +++ b/skills/plan/scope-lock/templates/config-vars-template.yaml @@ -0,0 +1,30 @@ +# config-vars.yaml — 项目配置清单 +# +# 用途:登记「需人工提供 / 确认」的非敏感、项目级配置(根包名、应用端口、前端包名、初始账号等)。 +# YAML 分组,逐项填写与核对一目了然。 +# 规则:命名约定 / 端口约定 / 安全要求统一写在 docs/07-环境配置.md,本文件只放值、不重复写规则。 +# 边界: +# - 机器 / 环境相关的连接信息(DB_HOST / DB_PORT / DB_USER / DB_SCHEMA 等)→ 仓库根 .env.local,不写在此。 +# - 敏感凭据(密码 / 密钥 / token)→ .env.local;本文件 secrets_ref 只登记键名供核对,绝不写真实值。 +# 填写:A1 scope-lock 按 docs/04 § 零 技术栈推断默认值填入;无对应技术栈的整节删除;无法推断的留 【人工填写:…】(A2 skeleton-gen 补填)。 + +backend: + base_package: 【人工填写:后端根包名 / 命名空间,如 com.acme.erp】 + http_port: 【人工填写:后端 HTTP 端口,默认 8080】 + +frontend: + pkg_name: 【人工填写:前端包名,如 acme-erp-web】 + dev_port: 【人工填写:前端开发服务器端口,默认 5173】 + +admin_init: + username: 【人工填写:超级管理员初始账号,如 admin】 + # 初始密码属敏感 → 见 .env.local 的 ADMIN_INIT_PASSWORD + +# 敏感值引用:真实值在 .env.local,此处只登记「键名 + 含义」,供 A2 skeleton-gen 核对 .env.local 是否齐全。 +# 按技术栈增删行(注释行表示可选,按需取消注释)。 +secrets_ref: + - DB_PASSWORD # 数据库密码 + - JWT_SECRET # JWT / 令牌签名密钥 + # - REDIS_PASSWORD # 缓存 / 会话(用 Redis 时) + # - ADMIN_INIT_PASSWORD # 超级管理员初始密码(有初始账号时) + # - OSS_ACCESS_KEY_SECRET / SMS_API_SECRET ... # 第三方凭证按需添加 diff --git a/skills/plan/scope-lock/templates/req-card-template.md b/skills/plan/scope-lock/templates/req-card-template.md new file mode 100644 index 0000000..1b88515 --- /dev/null +++ b/skills/plan/scope-lock/templates/req-card-template.md @@ -0,0 +1,44 @@ +<!-- +req-card-template:单张 REQ 卡片骨架。每张卡片是 docs/01-需求清单/<module>/REQ-XXX-NNN.md 一个独立文件。 + +渲染约定: +1) scope-lock 渲染时替换 6 个占位符:{{req_id}} / {{title}} / {{goal}} / {{rules}} / {{constraints}} / {{acceptance}} + 这 6 项由 CC 根据 docs/01-需求清单/index.md 的「核心功能点」推断起草: + - req_id / title:从核心功能点拆分命名得来 + - goal:用一句话展开 title + - rules / constraints / acceptance:业务语义层面的合理起草,待人工审阅修订 +2) `**输入字段**` / `**输出字段**` 为**结构化字段表**:每个字段一行,6 列固定结构 + (字段名 | 类型 | 必填 | 校验规则 | 业务规则 | 示例值)。 + 模板内每张表给出一行示例行,列首注明 `【示例行,替换为真实字段】`。 + 人工拿到卡片后按本 REQ 实际业务**逐行替换为真实字段 / 增删行**: + - 字段名:本 REQ 真实的输入 / 输出字段 + - 类型:真实数据类型(文本 / 整数 / 金额 / 日期 / 布尔 / 枚举 / …) + - 必填:是 / 否 + - 校验规则:长度 / 格式 / 范围 / 唯一性等可验证约束(如「3-20 位字母数字下划线;系统内唯一」) + - 业务规则:该字段的业务含义 / 来源 / 默认值 / 联动逻辑 + - 示例值:一个真实约束下的合法取值 +3) **「示例值」列必须替换为真实约束下的取值。留模板默认占位(`【示例行,替换为真实字段】` 或 `<示例值>`)即视为该 REQ 卡片未完成,A1 终结校验会阻断进入下一阶段。** +4) `**依赖表**: TBD(A3 自动补)` 和 `**依赖接口**: TBD(A5 自动补)` 是后续 skill 自动回填的占位,渲染时**保持原样**,不要替换为 `-` 也不要替换为 `{{...}}` +5) 渲染后这段 HTML 注释要**剥掉**,不进入最终卡片(lib/render.mjs 自动剥离) +--> +### {{req_id}} {{title}} + +**目标**: {{goal}} + +**输入字段**: + +| 字段名 | 类型 | 必填 | 校验规则 | 业务规则 | 示例值 | +| --- | --- | --- | --- | --- | --- | +| 【示例行,替换为真实字段】 | 文本 | 是 | 3-20 位字母数字下划线;系统内唯一 | 用户登录账号,系统内唯一标识 | <示例值> | + +**输出字段**: + +| 字段名 | 类型 | 必填 | 校验规则 | 业务规则 | 示例值 | +| --- | --- | --- | --- | --- | --- | +| 【示例行,替换为真实字段】 | 整数 | 是 | 大于 0 | 新建记录的主键 id | <示例值> | + +- **跨字段规则**: {{rules}} +- **边界**: {{constraints}} +- **验收**: {{acceptance}} +- **依赖表**: TBD(A3 自动补) +- **依赖接口**: TBD(A5 自动补) diff --git a/skills/plan/skeleton-gen/SKILL.md b/skills/plan/skeleton-gen/SKILL.md new file mode 100644 index 0000000..c953d05 --- /dev/null +++ b/skills/plan/skeleton-gen/SKILL.md @@ -0,0 +1,160 @@ +--- +name: skeleton-gen +description: A2 骨架生成——基于 docs/04 § 零 技术栈 + docs/01-需求清单/index.md 模块索引,生成项目专属的架构文档(docs/04 § 一+、docs/06、docs/07、docs/09)和工具脚本(.mjs,跨平台)。固定工具文件用 Read/Write 落盘,架构文档由 LLM 按大纲生成。 +user-invocable: false +allowed-tools: Read Write Edit Skill Grep Glob AskUserQuestion Bash(node *) +--- + +**所有输出必须使用中文。** + +# skeleton-gen + +## 执行步骤 + +### A. 读取锁定的输入 + +用 `Read` 读取: +- `docs/04-技术规范.md` § 零 技术栈表 +- `docs/01-需求清单/index.md` 需求索引 +- `docs/01-需求清单/` 需求卡片 + +后续所有内容都基于它们推导。 + +### B.1 生成 3 个全新架构文档(docs/06 / 07 / 09) + +对下表每个目标文件: +1. 读取对应的大纲模板 +2. 基于步骤 A 的输入,按大纲生成项目专属内容 +3. 剥掉 HTML 注释(注释是给 LLM 的提示,不应出现在最终文档里) +4. 写入目标路径 + +| 目标文件 | 大纲模板 | +|---|---| +| `docs/06-UI交互规范.md`(§ 一 ~ 三;FE 决策表由 A6 frontend-scope-lock 追加到 § 三之后) | `${CLAUDE_SKILL_DIR}/templates/docs-06-static-template.md` | +| `docs/07-环境配置.md` | `${CLAUDE_SKILL_DIR}/templates/docs-07-env-template.md` | +| `docs/09-项目目录结构.md` | `${CLAUDE_SKILL_DIR}/templates/docs-09-structure-template.md` | + +> **docs/07 只记规则,不记具体配置值**:端口 / 包名 / 库名 / 初始账号等真实值在 `config-vars.yaml`(A1 scope-lock 已锁)与 `.env.local`(敏感)里,docs/07 只写命名约定、端口约定、安全规则,并指向这两个文件。 + +项目专属标识(根包名 / 命名空间)保留 `【人工填写:<说明>】` 占位,等人工在 docs/09 顶部补填一次后,其他文件复用。 + +### B.2 追加 docs/04 § 一+(保留 § 零 不覆盖) + +docs/04 已由 scope-lock 写入 § 零。本步骤追加 § 一 ~ 三。 + +1. 读取 `docs/04-技术规范.md`(现有 § 零 完整内容)。 +2. 读取 `${CLAUDE_SKILL_DIR}/templates/docs-04-skeleton-template.md`。 +3. 基于技术栈,按大纲生成 § 一 ~ 三 的项目专属内容,剥掉 HTML 注释。 +4. 拼接原有内容和新生成内容,写回 `docs/04-技术规范.md`。 + +完成后,用 `Edit` 在 `docs/08-模块任务管理.md` 中勾选: +- ` - [ ] 架构文档已生成(docs/04 § 一+、docs/06、docs/07、docs/09)` + +### C. 生成工具脚本 + +#### C.1 复制固定模板文件(用 Read + Write,跨平台无 shell) + +对下表每个文件:用 `Read` 读模板内容,用 `Write` **原样**写到目标路径(`Write` 会自动创建缺失的父目录,无需 `mkdir`)。`.gitkeep` 用 `Write` 写空文件。 + +| 模板 | 目标路径 | +|---|---| +| `${CLAUDE_SKILL_DIR}/templates/env-local-template` | `.env.local` | +| `${CLAUDE_SKILL_DIR}/templates/scripts-setup-test-db-template.mjs` | `scripts/setup-test-db.mjs` | +| `${CLAUDE_SKILL_DIR}/templates/styles-tokens-template.css` | `src/styles/tokens.css` | +| (空文件) | `sql/migrations/.gitkeep` | + +> **`.env.local` 须与 `config-vars.yaml` 的 `secrets_ref` 对齐**:写完 `.env.local` 后用 `Read` 读仓库根 `config-vars.yaml` 的 `secrets_ref` 列表,逐个核对键名。env-local-template 已含 `DB_*` / `JWT_SECRET`;`secrets_ref` 里其余项目专属键(如 `REDIS_PASSWORD` / `ADMIN_INIT_PASSWORD` / 第三方凭证)用 `Edit` 追加到 `.env.local`,值统一为 `【人工填写:<说明>】`。 + +#### C.2 渲染 scripts/test.mjs + +用 `Read` 读取 `${CLAUDE_SKILL_DIR}/templates/scripts-test-template.mjs`,基于步骤 A 的技术栈(docs/04 § 零)为 7 个占位推断命令后用 `Write` 写到 `scripts/test.mjs`: + +- `{{backend_build}}` / `{{backend_lint}}` / `{{backend_test}}` 后端各 stage 命令 +- `{{frontend_build}}` / `{{frontend_lint}}` / `{{frontend_test}}` 前端各 stage 命令 +- `{{e2e_cmd}}` E2E(无 E2E 工具则填 `echo "[test.mjs] e2e 略"`) + +> 占位是普通 shell 命令字符串,模板在运行期用 `spawnSync(cmd, { shell:true })` 跨平台执行(Windows 走 cmd.exe,*nix 走 /bin/sh),缺席 stack 由模板内的 `existsSync('backend')` / `existsSync('frontend')` 守卫跳过。 +> 推断规则:根据 `docs/04 § 零` 。 +> - 「后端*」存在 → 据后端技术栈推 backend 三槽(build / lint / test 命令) +> - 「前端*」存在 → 据前端技术栈推 frontend 三槽 +> - 缺席 stack → 三槽全填 `echo skip`(该 stack 目录不存在时模板不会执行,但占位须为合法命令) +> - `{{e2e_cmd}}` 通常仅前端,按上述前端规则或填 `echo "[test.mjs] e2e 略"` +> +> 表结构异常(列名变更 / 无中文前缀)时停下,用 `AskUserQuestion` 让用户显式确认每 stack 命令。 + +> 注:生成的 `scripts/*.mjs` 由 `node` 直接执行,**无需 `chmod +x`**(跨平台无文件权限位概念)。 + +完成后,用 `Edit` 在 `docs/08-模块任务管理.md` 中勾选: +- ` - [ ] 工具脚本已生成(scripts/*.mjs、.env.local)` +- ` - [ ] 样式 token 骨架已生成(src/styles/tokens.css)` + +### D. 追加 .gitignore 忽略项 + +调 `${CLAUDE_PLUGIN_ROOT}/lib/merge-gitignore.mjs`(跨平台纯 Node,逐行判重并集合并,把 append 模板内容并入项目 `.gitignore`,原地写回第一个参数): + +```bash +node "${CLAUDE_PLUGIN_ROOT}/lib/merge-gitignore.mjs" .gitignore "${CLAUDE_SKILL_DIR}/templates/gitignore-append-template" +``` + +> `.gitignore` 不存在时先用 `Write` 建一个空文件再调用(`merge-gitignore.mjs` 的第一个参数须可读)。 + +完成后,用 `Edit` 在 `docs/08-模块任务管理.md` 中勾选: +- ` - [ ] .gitignore 已配置` + +### E. 占位符补填 + QA 闸门 + +#### E.1 扫描 + 分组 + +用 `Grep` 在以下路径扫 `【人工填写:`,记录命中(文件 / 行号 / 说明): +- `docs/04-技术规范.md` / `docs/06-UI交互规范.md` / `docs/07-环境配置.md` / `docs/09-项目目录结构.md` +- `config-vars.yaml`(A1 留下的未推断字段,如包名 / 端口) +- `scripts/*.mjs` / `.gitignore` +- `.env.local` + +分两组: +- **敏感组**:`.env.local` 路径命中(凭据 / 密钥)。**不弹 QA**(凭据不进会话),E.3 提示用户自填。 +- **非敏感组**:其余文件。按说明文字聚合为「根占位」(相同说明 = 同一值,多处共用)或「派生占位」(说明表达派生关系,如"后端 java 根包路径"派生自"根包名")。 + +无命中 → 跳 E.4。 + +#### E.2 问根占位 + 推派生 + 批量 Edit + +- 每个根占位用 `AskUserQuestion` 问(给合理默认值 + 自由输入),用 `Edit` 批量替换所有命中位置 +- 派生占位**不问**,CC 基于根占位值推断后 `Edit`;不能可靠推断则回退当独立根占位问 + +#### E.3 敏感占位提示(不弹 QA) + +若敏感组非空:打印提示横幅,列出 `.env.local` 待填字段名 + 告诉用户"直接编辑文件,凭据不进会话"。 + +#### E.4 验证 + QA 闸门 + +循环直到两条件**同时**满足: +(a) `Grep` 重新扫 E.1 全部路径,0 命中 +(b) 用户 `AskUserQuestion` 选「继续」 + +每次弹 QA 前重扫;有残留则打印残留位置清单(文件:行号 — 说明)+ 再弹 QA。 + +QA 横幅涵盖:产出文件清单(docs/04 / 06 / 07 / 09 + config-vars.yaml + scripts/*.mjs + .env.local + .gitignore)、占位状态(N=0 或待填清单)、「继续」/「有疑问先沟通」两选项。 + +通过后(N=0 且用户选「继续」),用 `Edit` 在 `docs/08-模块任务管理.md` 中勾选: +- `- [ ] A2 骨架生成 — skeleton-gen` + +### F. 进入 A3 + +输出 `skeleton-gen: 完成`,立即调用 `Skill(db-design-gen)`。 + +## 参考 + +- `docs/04-技术规范.md` § 零(技术栈输入) +- `docs/01-需求清单/index.md`(模块索引输入) +- `${CLAUDE_SKILL_DIR}/templates/docs-04-skeleton-template.md`(大纲) +- `${CLAUDE_SKILL_DIR}/templates/docs-06-static-template.md`(大纲) +- `${CLAUDE_SKILL_DIR}/templates/docs-07-env-template.md`(大纲) +- `${CLAUDE_SKILL_DIR}/templates/docs-09-structure-template.md`(大纲) +- `${CLAUDE_SKILL_DIR}/templates/scripts-test-template.mjs`(推断命令填充 7 槽:backend/frontend × build/lint/test + e2e;缺席 stack 填 `echo skip`) +- `${CLAUDE_SKILL_DIR}/templates/scripts-setup-test-db-template.mjs`(0 槽位,跨平台 .env.local 解析 + DROP/CREATE) +- `${CLAUDE_SKILL_DIR}/templates/env-local-template`(0 槽位;C.1 据 `config-vars.yaml` 的 `secrets_ref` 追加项目专属 secret 键) +- `config-vars.yaml`(A1 scope-lock 输出,仓库根;C.1 读其 `secrets_ref` 对齐 `.env.local`,E.1 扫其残留 `【人工填写:`) +- `${CLAUDE_SKILL_DIR}/templates/gitignore-append-template`(0 槽位) +- `${CLAUDE_SKILL_DIR}/templates/styles-tokens-template.css`(0 槽位,样式 token 骨架) +- `${CLAUDE_PLUGIN_ROOT}/lib/merge-gitignore.mjs`(.gitignore 逐行判重并集合并,跨平台纯 Node) diff --git a/skills/plan/skeleton-gen/templates/docs-04-skeleton-template.md b/skills/plan/skeleton-gen/templates/docs-04-skeleton-template.md new file mode 100644 index 0000000..7f2c116 --- /dev/null +++ b/skills/plan/skeleton-gen/templates/docs-04-skeleton-template.md @@ -0,0 +1,69 @@ +<!-- +本文件是 docs/04-技术规范.md 的 § 一+ 大纲。 +skeleton-gen 读取 docs/04 § 零(技术栈表)和 docs/01-需求清单/index.md(模块索引), +按下述大纲生成本项目专属的规范内容。LLM 不要原样拷贝提示文字,只保留 section 标题。 +--> + +## 一、后端规范 + +### 1.1 规则 +<!-- 后端通用约定:保留下方占位符不要代填,由人工在 skeleton-gen § E 填写;每条一个 bullet,按需复制本行新增更多。 --> +- 【人工填写:一条后端通用约定,按需复制本行新增更多;无则填「无」】 + +### 1.2 分层结构 +<!-- 按 § 零 的后端框架定层次:controller/service/mapper 等;每层职责一句话。 --> + +### 1.3 命名约定 +<!-- 包名(根包用【人工填写:根包名】占位)/ 类名 / 方法名 / 常量的大小写规则,含 2 个示例。 --> + +### 1.4 统一响应格式 +<!-- 成功/失败的 JSON 结构,错误码段位划分。 --> + +### 1.5 异常处理 +<!-- 全局异常处理器的使用方式;哪些异常要 catch,哪些禁止;**接口响应禁止回显后端异常堆栈**(返用户友好错误码 + 文案)。 --> + +### 1.6 事务 +<!-- 事务边界(通常 service 层);跨服务调用的禁止/替代方案。 --> + +### 1.7 认证 +<!-- 基于 § 零 认证方案推导:token 生命周期、刷新机制、密钥管理。 --> + +## 二、前端规范 + +### 2.1 目录约定 +<!-- 基于 § 零 前端框架推导:api/components/pages/store/hooks/utils 的职责;**前端禁止直接写 SQL / 操作 DB**,所有数据访问走 api/ 层统一封装。 --> + +### 2.2 状态管理 +<!-- 基于 § 零 状态管理技术推导:全局 vs 局部、服务端数据的存放。 --> + +### 2.3 请求封装 +<!-- HTTP 客户端的拦截器、超时、错误重试、鉴权注入。 --> + +### 2.4 错误处理 +<!-- 网络错误 / 业务错误 / 页面级错误的分层处理。 --> + +### 2.5 样式与主题 +<!-- 基于 § 零 UI 库给出 CSS 变量约定: + - 命名格式 `--color-<scope>-<role>-<state>`(scope=form/table-row/...,role=bg/fg/border,state=edit/readonly/hover/selected) + - 文件位置 `src/styles/tokens.css`,由 skeleton-gen 生成空骨架,色值由 docs/06 § 四锁定后填入 + - 组件样式中只用 var(--color-xxx),禁止硬编码 hex/rgba + - 与 UI 库主题对接(如 Ant Design ConfigProvider.theme.token)的映射方式 + 具体 token 表见 docs/06 § 四。 --> + +## 三、共同约定 + +### 3.1 Git 提交 +`<type>(<scope>): <subject> REQ-XXX-NNN` + +### 3.2 分页查询 +<!-- 后端分页对象 + 前端分页组件,入参出参约定。 --> + +### 3.3 日期与金额 +<!-- 后端类型(如 LocalDateTime / BigDecimal)+ 前端展示工具;金额精度约定。 --> + +### 3.4 数据访问规约 +<!-- 基于 § 零 数据访问技术(MyBatis-Plus / JPA 等):SELECT 字段显式列举,**禁止 `SELECT *`**;循环中不得执行 DB 查询(**N+1 反模式**),改用批量查 / IN 子句 / JOIN;Mapper XML 里字段与表名用常量或引用,避免拼字符串。 --> + +### 3.5 配置与安全 +<!-- 配置:DB 连接 / 端口 / 密钥 / 第三方 URL 等一律放 `application.yml` + `.env.local`,代码里**禁止硬编码**。 + 前端安全:`localStorage` 不存敏感信息(token / 身份 / 个人数据),推荐 HttpOnly Cookie 或 内存 + 刷新 token 模式;接口响应禁止回显后端异常堆栈(与 § 1.5 一致)。 --> diff --git a/skills/plan/skeleton-gen/templates/docs-06-static-template.md b/skills/plan/skeleton-gen/templates/docs-06-static-template.md new file mode 100644 index 0000000..21dd358 --- /dev/null +++ b/skills/plan/skeleton-gen/templates/docs-06-static-template.md @@ -0,0 +1,42 @@ +<!-- +本文件是 docs/06-UI交互规范.md 的 § 一 ~ 三 大纲(§ 三页面清单由 downstream-gen 按模块追加;FE 决策表由 A6 frontend-scope-lock 追加到 § 三之后)。 +skeleton-gen 读取 docs/04 § 零 和 docs/01 index,按下述大纲生成项目专属内容。 +布局/页面骨架以项目根的 prototype/ 静态 HTML mockup 为权威,本文件仅承载跨页面通用规则与 Design Tokens。 +--> + +# 06-UI交互规范 + +> 本项目所有页面布局以项目根 `prototype/` 目录下的静态 HTML mockup 为权威。前端阶段实现时直接以 prototype/ HTML 推导组件树与样式。本文件仅承载跨页面通用规则与 Design Tokens。 + +## 一、通用交互规则 + +### 1.1 操作反馈 +<!-- 成功/失败消息;危险操作二次确认;长耗时按钮 loading 态。 --> + +### 1.2 数据展示 +<!-- 空状态 / 加载 / 异常 的统一组件与文案。 --> + +### 1.3 权限控制(前端) +<!-- 菜单级 / 按钮级 / 路由级的控制方式,关联后端 RBAC。 --> + +## 二、Design Tokens + +<!-- 所有色值统一以 CSS 变量定义于 src/styles/tokens.css;命名规范见 docs/04 § 2.5。 --> + +### 2.1 全局调色板 +<!-- 与 § 零 UI 库主题对齐:列名 = 语义 / 变量名 / 默认值 / 用途。 + 至少含:主色/成功/警告/错误/主文字/次文字/边框/背景。 --> + +### 2.2 组件级状态色 +<!-- 场景 × 状态映射表:列名 = 序号 / 组件 / 编辑bg / 只读bg / 悬浮bg / 编辑fg / 只读fg / 悬浮fg / 备注。 + 单元格写 token 名(var(--color-xxx) 形式),不写 hex;"—" 表示该状态不适用。 + 表后追加「Token 默认值」表,列出每个 --color-xxx 在 tokens.css 的默认值。 --> + +### 2.3 引用约定 +<!-- 一句话三条: + - 组件样式只用 var(--color-xxx),禁止硬编码 + - 新增 token 须先登记到 § 2.1/2.2 再补 tokens.css + - 修改色值只改 tokens.css 一处,不允许组件覆盖 --> + +## 三、页面清单 +(由 `downstream-gen` 按模块追加段落) diff --git a/skills/plan/skeleton-gen/templates/docs-07-env-template.md b/skills/plan/skeleton-gen/templates/docs-07-env-template.md new file mode 100644 index 0000000..bc246c9 --- /dev/null +++ b/skills/plan/skeleton-gen/templates/docs-07-env-template.md @@ -0,0 +1,34 @@ +<!-- +本文件是 docs/07-环境配置.md 的大纲。 +docs/07 只记规则与约定,不记具体配置值——端口 / 包名 / 库名等真实值在 config-vars.yaml(A1 锁定)与 .env.local(敏感)。 +skeleton-gen 基于 docs/04 § 零 技术栈表推导各节内容: + § 一 依赖清单 → 从技术栈的每一行技术推导运行时和构建依赖 + § 二 端口约定 → 从后端/前端/数据库/缓存/反向代理 各取默认端口(约定值;项目实际采用值记在 config-vars.yaml) + § 四 常用命令 → 基于构建工具、包管理器给出开发者最常用命令 +--> + +# 07-环境配置 + +## 一、依赖清单 + +<!-- 表格:| 层 | 依赖 | 版本 | 说明 |;覆盖 运行时 / 构建 / 容器 / CLI 工具。 --> + +## 二、端口约定 + +<!-- 表格:| 服务 | 端口 | 说明 |;至少列 后端 HTTP / 前端 dev / 数据库 / 缓存 / 反代。这里给默认约定值;项目实际采用的端口记在 config-vars.yaml。 --> + +## 三、配置与凭据规则 + +项目配置分两处存放,**本文档只记规则、不记具体值**: + +- **非敏感、项目级配置**(根包名 / 命名空间、应用端口、前端包名、管理员初始账号等)→ 仓库根 `config-vars.yaml`,结构化 YAML,随项目提交。 +- **敏感凭据**(数据库密码、JWT / 签名密钥、Redis 密码、第三方 key/secret、管理员初始密码等)→ 仓库根 `.env.local`,入 `.gitignore`,**不提交**;`config-vars.yaml` 末尾 `secrets_ref` 只登记键名作引用。 + +规则: +- 根包名 / 命名空间一经在 `config-vars.yaml` 锁定,全项目复用,不得各模块各写。 +- 端口遵循 § 二 约定;调整时改 `config-vars.yaml`,本文档不写具体端口。 +- 任何敏感值不得出现在 `config-vars.yaml`、docs、源码或日志中——只允许出现在 `.env.local`。 + +## 四、常用命令 + +<!-- 表格:| 命令 | 说明 |;包含 启动后端 / 启动前端 / 打包 / 运行测试 / 重置测试数据。 --> diff --git a/skills/plan/skeleton-gen/templates/docs-09-structure-template.md b/skills/plan/skeleton-gen/templates/docs-09-structure-template.md new file mode 100644 index 0000000..d913c08 --- /dev/null +++ b/skills/plan/skeleton-gen/templates/docs-09-structure-template.md @@ -0,0 +1,45 @@ +<!-- +本文件是 docs/09-项目目录结构.md 的大纲。 +skeleton-gen 基于 docs/04 § 零 技术栈推导目录树: + § 二 后端目录 → 按后端框架的惯例(如 Spring Boot 的 src/main/java) + § 三 前端目录 → 按前端框架的惯例(如 Vite + React 的 src/) + § 四 docs 目录 → 沿用插件标准 + § 五 命名约定 → 按后端语言的包/命名空间习惯 + +模块划分参考 docs/01-需求清单/index.md 的模块索引,将业务模块落到代码目录。 +--> + +# 09-项目目录结构 + +## 一、仓库顶层 + +<!-- 用代码块画出顶层目录树,含 CLAUDE.md / README.md / .env.local / scripts / docs / sql / backend / frontend 等。 --> + +## 二、后端目录 + +<!-- 基于后端框架的目录树;按 docs/01 index 的模块代码把业务模块列出(module/user/、module/order/ 等)。 --> + +## 三、前端目录 + +<!-- 基于前端框架的目录树;pages/ 下按业务模块建子目录。 --> + +## 四、docs/ 结构 + +``` +docs/ +├── 01-需求清单/ # 每模块一子目录(_module.md 模块头 + REQ-*.md 卡片) +├── 02-开发计划.md +├── 03-数据库设计文档.md +├── 04-技术规范.md +├── 05-API接口契约.md +├── 06-UI交互规范.md +├── 07-环境配置.md +├── 08-模块任务管理.md +├── 09-项目目录结构.md +├── 10-验收检查清单.md +└── superpowers/ # CC 运行时产物 +``` + +## 五、命名与放置约定 + +<!-- 根包 / 命名空间用【人工填写:】占位;Controller / Service / Mapper / DTO / VO / 前端组件 / 前端页面 的放置规则。 --> diff --git a/skills/plan/skeleton-gen/templates/env-local-template b/skills/plan/skeleton-gen/templates/env-local-template new file mode 100644 index 0000000..43a3bd2 --- /dev/null +++ b/skills/plan/skeleton-gen/templates/env-local-template @@ -0,0 +1,25 @@ +# .env.local — 本地开发凭据(入 .gitignore,不提交) +# +# 规则: +# 1. 值含 `$`、反引号、空格、`!` 等 shell 特殊字符时,必须用单引号包裹: +# DB_PASSWORD='p@ss$w0rd!' +# 否则 `set -a; . .env.local; set +a` 会做变量展开导致密码错乱。 +# 2. DB_HOST 建议保持 localhost / 127.0.0.1;非本地 host 默认会被 scripts/setup-test-db.mjs 防护拒绝。 +# 若必须用远程测试库,把 host 列入下方 TEST_DB_ALLOWED_HOSTS。 +# 3. DB_SCHEMA 建议命名含 test / _dev / _local / _ci,避免与生产库同名。 + +DB_HOST=【人工填写:MySQL host,推荐 localhost】 +DB_PORT=【人工填写:MySQL port,默认 3306】 +DB_USER=【人工填写:开发账号名】 +DB_PASSWORD=【人工填写:对应密码,含特殊字符时用单引号包裹】 +DB_SCHEMA=【人工填写:schema 名,推荐含 test/_dev/_local,例如 erp_dev】 +JWT_SECRET=【人工填写:JWT 签名密钥,256+ bit 随机串】 + +# 可选:额外允许 DROP CREATE 的远程 host(空格或逗号分隔)。仅当 DB_HOST 指向公司测试 MySQL 等 +# 非本地服务器时填写;留空表示只允许 localhost / 127.0.0.1 / ::1。 +# 示例:TEST_DB_ALLOWED_HOSTS="118.178.19.35 test-mysql.internal" +# +# ⚠️ 列入后该 host 每次 test.mjs 都会被 DROP CREATE(无二次确认)。 +# 仅用于你完全可控的测试库;生产/共享库/多人共享的 staging 库**千万别列**。 +# (防护 2 还会检查 schema 名须含 test/_dev/_local/_ci,独立兜底。) +TEST_DB_ALLOWED_HOSTS= diff --git a/skills/plan/skeleton-gen/templates/gitignore-append-template b/skills/plan/skeleton-gen/templates/gitignore-append-template new file mode 100644 index 0000000..ac39aa6 --- /dev/null +++ b/skills/plan/skeleton-gen/templates/gitignore-append-template @@ -0,0 +1,32 @@ +# ==== ERP 插件推荐忽略项(skeleton-gen 追加) ==== +# 本地运行时配置(含真实凭据,严禁入库) +.env.local +.env.*.local + +# Java / Maven +target/ +*.class + +# Node / 前端构建产物 +node_modules/ +dist/ +build/ +coverage/ + +# IDE +.idea/ +.vscode/ +*.iml + +# OS +.DS_Store +Thumbs.db + +# 日志 +*.log +logs/ + +# 插件运行时临时文件 +.tmp/ +*.raw +# ==== 结束 ==== diff --git a/skills/plan/skeleton-gen/templates/scripts-setup-test-db-template.mjs b/skills/plan/skeleton-gen/templates/scripts-setup-test-db-template.mjs new file mode 100644 index 0000000..ec56d45 --- /dev/null +++ b/skills/plan/skeleton-gen/templates/scripts-setup-test-db-template.mjs @@ -0,0 +1,126 @@ +#!/usr/bin/env node +// scripts/setup-test-db.mjs — 数据库重置脚本:drop + create 空库。 +// schema apply 由 Flyway 在 Spring Boot 启动时自动处理(见 docs/04 技术栈 + sql/migrations/V*.sql)。 +// seed 数据由测试框架负责(Spring @Sql / Flyway R__seed.sql / data.sql)。 +// +// 使用场景: +// - scripts/test.mjs 开头:清空库,让 Spring 启动时 Flyway 从 V1 开始重放所有 migration +// - scripts/test.mjs 结尾:清空库,避免测试遗留污染下次运行 +// - 手动调试时:reset 到零状态 +// +// 跨平台:用纯 JS 解析 .env.local(dotenv 风格,逐行 KEY=VALUE),**绝不** shell-source, +// 因此 mac / Windows 原生 node 均可运行,且消除 shell 注入 / 变量展开隐患。 +// DROP/CREATE 通过 `mysql` 客户端以 argv 数组方式执行(不经 shell),密码不进命令行解析层。 +// +// 防护:本脚本只允许在本地 host + 测试库名上执行;非预期目标会被拒绝, +// 避免 .env.local 误指向 staging/prod 时触发不可逆 DROP。 + +import { spawnSync } from 'node:child_process' +import { existsSync, readFileSync } from 'node:fs' +import { dirname, join } from 'node:path' +import { fileURLToPath } from 'node:url' + +const SCRIPT_DIR = dirname(fileURLToPath(import.meta.url)) +const ENV_FILE = join(SCRIPT_DIR, '..', '.env.local') + +// dotenv 风格解析:逐行 KEY=VALUE,跳过空行与 # 注释,去除两侧空白, +// 可选地剥离一层成对单/双引号。**不做**变量展开,特殊字符按字面保留。 +function parseEnv(text) { + const env = {} + for (const rawLine of text.split(/\r?\n/)) { + const line = rawLine.trim() + if (line === '' || line.startsWith('#')) continue + const eq = line.indexOf('=') + if (eq === -1) continue + const key = line.slice(0, eq).trim() + if (!key) continue + let value = line.slice(eq + 1).trim() + if ( + value.length >= 2 && + ((value.startsWith("'") && value.endsWith("'")) || + (value.startsWith('"') && value.endsWith('"'))) + ) { + value = value.slice(1, -1) + } + env[key] = value + } + return env +} + +if (!existsSync(ENV_FILE)) { + console.error(`[setup-test-db] .env.local 不存在(${ENV_FILE})`) + process.exit(1) +} + +const env = parseEnv(readFileSync(ENV_FILE, 'utf8')) + +const DB_HOST = env.DB_HOST ?? '' +const DB_PORT = env.DB_PORT ?? '3306' +const DB_USER = env.DB_USER ?? '' +const DB_PASSWORD = env.DB_PASSWORD ?? '' +const DB_SCHEMA = env.DB_SCHEMA ?? '' +const TEST_DB_ALLOW_REMOTE = env.TEST_DB_ALLOW_REMOTE ?? process.env.TEST_DB_ALLOW_REMOTE ?? '0' +const TEST_DB_ALLOW_PROD_NAME = + env.TEST_DB_ALLOW_PROD_NAME ?? process.env.TEST_DB_ALLOW_PROD_NAME ?? '0' + +// 防护 1:默认只允许本地 host(localhost / 127.0.0.1 / ::1)。 +// 额外允许的远程 host 在 .env.local 的 TEST_DB_ALLOWED_HOSTS 中(空格或逗号分隔)。 +const extraHosts = (env.TEST_DB_ALLOWED_HOSTS ?? '') + .split(/[\s,]+/) + .filter(Boolean) +const allowedHosts = ['localhost', '127.0.0.1', '::1', ...extraHosts] +if (!allowedHosts.includes(DB_HOST)) { + console.error(`[setup-test-db] 拒绝在非白名单 host (${DB_HOST}) 上执行 DROP DATABASE`) + console.error(` 当前白名单:${allowedHosts.join(' ')}`) + console.error(' 加入 host:在 .env.local 追加 TEST_DB_ALLOWED_HOSTS="<host1> <host2>"') + console.error(' 一次性绕过:在 .env.local 设 TEST_DB_ALLOW_REMOTE=1') + if (TEST_DB_ALLOW_REMOTE !== '1') process.exit(1) +} + +// 防护 2:schema 名需像测试/开发库(含 test / _dev / _local / _ci),否则要求显式确认。 +const schemaLooksLikeTest = + /test/.test(DB_SCHEMA) || /_dev$/.test(DB_SCHEMA) || /_local$/.test(DB_SCHEMA) || /_ci$/.test(DB_SCHEMA) +if (!schemaLooksLikeTest) { + console.error( + `[setup-test-db] schema '${DB_SCHEMA}' 不像测试库(期望命名含 test / _dev / _local / _ci)` + ) + console.error(' 如确为期望行为,请显式声明:在 .env.local 设 TEST_DB_ALLOW_PROD_NAME=1') + if (TEST_DB_ALLOW_PROD_NAME !== '1') process.exit(1) +} + +// 防护 3:显式 banner,让人看见自己在 drop 什么;远程 host 额外提示白名单内容。 +console.log(`[setup-test-db] 即将 DROP + CREATE \`${DB_SCHEMA}\` on ${DB_HOST}:${DB_PORT}`) +if (!['localhost', '127.0.0.1', '::1'].includes(DB_HOST)) { + console.log( + '[setup-test-db] 目标是 **远程** host(已在 TEST_DB_ALLOWED_HOSTS 白名单中,每次 test.mjs 都会 DROP)' + ) + console.log(`[setup-test-db] 当前白名单: ${allowedHosts.join(' ')}`) + console.log( + '[setup-test-db] 若不希望每次自动 DROP,从 .env.local 的 TEST_DB_ALLOWED_HOSTS 删掉此 host' + ) +} + +const sql = + `DROP DATABASE IF EXISTS \`${DB_SCHEMA}\`; ` + + `CREATE DATABASE \`${DB_SCHEMA}\` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;` + +// 以 argv 数组调用 mysql(不经 shell):密码不进 shell 解析,跨平台一致。 +const mysqlArgs = [ + `-h${DB_HOST}`, + `-P${DB_PORT}`, + `-u${DB_USER}`, + `-p${DB_PASSWORD}`, + '-e', + sql, +] +const res = spawnSync('mysql', mysqlArgs, { stdio: 'inherit' }) +if (res.error) { + console.error(`[setup-test-db] FATAL: 无法执行 mysql(请确认其在 PATH 中): ${res.error.message}`) + process.exit(1) +} +if (res.status !== 0) { + console.error(`[setup-test-db] FAIL: mysql exit=${res.status}`) + process.exit(res.status === null ? 1 : res.status) +} + +console.log('[setup-test-db] done — schema will be applied by Flyway when Spring Boot starts') diff --git a/skills/plan/skeleton-gen/templates/scripts-test-template.mjs b/skills/plan/skeleton-gen/templates/scripts-test-template.mjs new file mode 100644 index 0000000..9f0ab8c --- /dev/null +++ b/skills/plan/skeleton-gen/templates/scripts-test-template.mjs @@ -0,0 +1,69 @@ +#!/usr/bin/env node +// scripts/test.mjs —— 合并到默认分支(main / master)前的测试闸门。 +// 顺序:detect → setup-db → build → lint → unit+integration → e2e → reset-db +// 由 coding.mjs 的 test-gate stage(通过子会话)调用。 +// +// 跨平台:所有命令经 child_process.spawnSync(cmd, { shell:true }) 执行, +// 在 Windows 走 cmd.exe,在 *nix 走 /bin/sh,无需 WSL / Git-Bash。 +// 命令字符串来自 docs/04 §零(构建/lint/单测/e2e)——由 skeleton-gen 在 Plan 期填充。 + +import { spawnSync } from 'node:child_process' +import { existsSync } from 'node:fs' +import { dirname, join } from 'node:path' +import { fileURLToPath } from 'node:url' + +const PROJECT_ROOT = join(dirname(fileURLToPath(import.meta.url)), '..') + +// 在指定子目录下跑一条 shell 命令;非零退出码即终止整个闸门并透传该码。 +function run(label, command, cwd = PROJECT_ROOT) { + console.log(`[test.mjs] ${label}: ${command}`) + const res = spawnSync(command, { cwd, shell: true, stdio: 'inherit' }) + if (res.error) { + console.error(`[test.mjs] FATAL: 无法执行 (${label}): ${res.error.message}`) + process.exit(1) + } + if (res.status !== 0) { + console.error(`[test.mjs] FAIL (${label}) exit=${res.status}`) + process.exit(res.status === null ? 1 : res.status) + } +} + +// Stack detection (runtime, mode-agnostic) +const hasBackend = existsSync(join(PROJECT_ROOT, 'backend')) +const hasFrontend = existsSync(join(PROJECT_ROOT, 'frontend')) +if (!hasBackend && !hasFrontend) { + console.error('[test.mjs] FATAL: neither backend/ nor frontend/ exists') + process.exit(1) +} + +const backendDir = join(PROJECT_ROOT, 'backend') +const frontendDir = join(PROJECT_ROOT, 'frontend') + +console.log('[test.mjs] 1/6 setup test db') +run('setup-test-db', `node ${JSON.stringify(join('scripts', 'setup-test-db.mjs'))}`) + +console.log('[test.mjs] 2/6 build') +if (hasBackend) run('backend build', '{{backend_build}}', backendDir) +else console.log('[test.mjs] skip backend build') +if (hasFrontend) run('frontend build', '{{frontend_build}}', frontendDir) +else console.log('[test.mjs] skip frontend build') + +console.log('[test.mjs] 3/6 lint') +if (hasBackend) run('backend lint', '{{backend_lint}}', backendDir) +else console.log('[test.mjs] skip backend lint') +if (hasFrontend) run('frontend lint', '{{frontend_lint}}', frontendDir) +else console.log('[test.mjs] skip frontend lint') + +console.log('[test.mjs] 4/6 unit + integration') +if (hasBackend) run('backend test', '{{backend_test}}', backendDir) +else console.log('[test.mjs] skip backend test') +if (hasFrontend) run('frontend test', '{{frontend_test}}', frontendDir) +else console.log('[test.mjs] skip frontend test') + +console.log('[test.mjs] 5/6 E2E') +run('e2e', '{{e2e_cmd}}') + +console.log('[test.mjs] 6/6 reset test db') +run('reset-test-db', `node ${JSON.stringify(join('scripts', 'setup-test-db.mjs'))}`) + +console.log('[test.mjs] GREEN') diff --git a/skills/plan/skeleton-gen/templates/styles-tokens-template.css b/skills/plan/skeleton-gen/templates/styles-tokens-template.css new file mode 100644 index 0000000..bc8a542 --- /dev/null +++ b/skills/plan/skeleton-gen/templates/styles-tokens-template.css @@ -0,0 +1,43 @@ +/* + * src/styles/tokens.css — Design Tokens + * 命名规范见 docs/04-技术规范.md § 2.5 + * 色值锁定见 docs/06-UI交互规范.md § 四 + * + * 命名格式:--color-<scope>-<role>-<state> + * <scope> 组件域:form / table-row / table-header / ... + * <role> 作用:bg(背景)/ fg(前景/字体)/ border + * <state> 状态:edit / readonly / hover / selected(无状态时省略) + * + * 约束: + * - 组件样式中只用 var(--color-xxx),禁止硬编码 hex / rgba + * - 修改色值只改本文件,不允许在组件级覆盖 + * - 新增 token 须先登记到 docs/06 § 4.1 / 4.2,再补到此处 + */ + +:root { + /* === 1. 全局调色板(与 Ant Design 主题对齐) === */ + --color-primary: #1890ff; + --color-success: #52c41a; + --color-warning: #faad14; + --color-error: #ff4d4f; + --color-text: rgba(0, 0, 0, 0.85); + --color-text-secondary: rgba(0, 0, 0, 0.45); + --color-border: #d9d9d9; + --color-bg-base: #f0f2f5; + + /* === 2. 组件级状态色(与 docs/06 § 4.2 一一对应) === */ + + /* form:输入框 / 备注框 / 时间框 / 下拉框共用 */ + --color-form-bg-edit: #ffffff; + --color-form-bg-readonly: #f1f2f8; + --color-form-bg-hover: #f5f5f5; /* 仅下拉框使用 */ + --color-form-fg: #000000; + + /* table */ + --color-table-row-bg-selected: #86d5fb; + --color-table-row-bg-hover: #fff7e6; + --color-table-row-bg-readonly: #f1f2f8; /* = rgb(241, 242, 248) */ + --color-table-row-fg: #000000; + --color-table-header-bg: #f5f5f5; + --color-table-header-fg: rgba(0, 0, 0, 0.85); /* = #000000D9 */ +} diff --git a/skills/project-init/SKILL.md b/skills/project-init/SKILL.md deleted file mode 100644 index 1b93b12..0000000 --- a/skills/project-init/SKILL.md +++ /dev/null @@ -1,110 +0,0 @@ ---- -name: project-init -description: A0 项目初始化——从插件模板幂等地用 Read/Write 落盘 CLAUDE.md / docs/01-需求清单/index.md / docs/04-技术规范.md / docs/08-模块任务管理.md(已存在则跳过),做跨平台依赖检查(git/mysql/node 缺失则按 OS 给安装指引并停下),并初始化 Git(如未初始化)。plan-start 在 docs/08 缺失时派发本 skill。 -user-invocable: false -allowed-tools: Read Write Glob Edit Skill Bash(node *) Bash(git init) Bash(git rev-parse *) ---- - -**所有输出必须使用中文。** - -你负责在项目目录中创建初始文件结构,已存在的文件不覆盖。 - -## 执行步骤 - -### A. 幂等复制模板文件(用 Glob + Read + Write,跨平台无 shell) - -对下表每个文件:先用 `Glob` 判断目标路径是否已存在;**已存在则跳过**(不覆盖,幂等);不存在则用 `Read` 读模板、用 `Write` **原样**写到目标路径(`Write` 会自动创建缺失的父目录 `docs/01-需求清单/`,无需 `mkdir`)。 - -| 模板 | 目标路径 | -|---|---| -| `${CLAUDE_SKILL_DIR}/templates/CLAUDE-template.md` | `CLAUDE.md` | -| `${CLAUDE_SKILL_DIR}/templates/docs-01-index-template.md` | `docs/01-需求清单/index.md` | -| `${CLAUDE_SKILL_DIR}/templates/docs-04-stack-template.md` | `docs/04-技术规范.md` | -| `${CLAUDE_SKILL_DIR}/templates/docs-08-initial-template.md` | `docs/08-模块任务管理.md` | - -完成后,用 `Edit` 在 `docs/08-模块任务管理.md` 中勾选: -- ` - [ ] 项目文件骨架已创建(CLAUDE.md + docs/01-需求清单/index.md + docs/04-技术规范.md)` - -### B. 依赖检查(跨平台,只检测不自动安装) - -对 **git、mysql、node** 三个命令做**跨平台 PATH 检测**:缺失则按当前操作系统(`process.platform`)打印对应安装指引并**停下**(不自动安装、不改 PATH——自动包管理在 Windows / 受限环境下不可靠,且静默改 PATH 有副作用)。 - -用 `Bash` 跑下面这段 `node` 脚本(用 `process.platform` 区分 `darwin` / `win32` / `linux`,跨平台检测命令是否在 PATH 上): - -```bash -node -e ' -const { spawnSync } = require("node:child_process"); -const plat = process.platform; -const has = (cmd) => { - const r = plat === "win32" - ? spawnSync("where", [cmd], { stdio: "ignore" }) - : spawnSync("sh", ["-c", "command -v " + cmd], { stdio: "ignore" }); - return r.status === 0; -}; -const guide = { - darwin: { git: "xcode-select --install 或 brew install git", - mysql: "brew install mysql", - node: "brew install node 或见 https://nodejs.org" }, - linux: { git: "sudo apt-get install git / sudo yum install git / sudo apk add git", - mysql: "sudo apt-get install mysql-client / sudo yum install mysql", - node: "sudo apt-get install nodejs 或见 https://nodejs.org" }, - win32: { git: "winget install Git.Git 或见 https://git-scm.com/download/win", - mysql: "winget install Oracle.MySQL 或见 https://dev.mysql.com/downloads/", - node: "winget install OpenJS.NodeJS 或见 https://nodejs.org" }, -}[plat] || {}; -const tools = ["git", "mysql", "node"]; -const missing = tools.filter((t) => !has(t)); -const mark = (t) => (missing.includes(t) ? "✗" : "✓"); -console.log("[project-init] 依赖检查 (" + plat + "): " + tools.map((t) => t + " " + mark(t)).join(" ")); -if (missing.length) { - console.error("[project-init] 缺失依赖,请先安装后重跑:"); - for (const t of missing) console.error(" - " + t + " : " + (guide[t] || "见对应官网")); - process.exit(1); -} -' -``` - -- 退出码 `0`(全部 ✓)→ 进入步骤 C -- 退出码 `1`(有缺失)→ 已打印缺失工具 + OS 安装指引,**停下**,提示用户安装后重跑本 skill - -完成后,用 `Edit` 在 `docs/08-模块任务管理.md` 中勾选: -- ` - [ ] 依赖检查通过` - -### C. 初始化 Git(如尚未初始化) - -用 `Glob` 检查 `.git/` 目录是否存在。 -- 不存在 → 用 `Bash` 执行 `git init`。 -- 已存在 → 跳过。 - -完成后,用 `Edit` 在 `docs/08-模块任务管理.md` 中勾选(A0 子项 + A0 顶层): -- ` - [ ] Git 已初始化` -- `- [ ] A0 项目初始化 — project-init` - -### D. 打印完成横幅并进入 A1 - -向用户输出: - -``` -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - [project-init] 项目初始化完成 - - 已创建: - ✓ CLAUDE.md(从插件模板复制) - ✓ docs/01-需求清单/index.md(待人工填写模块索引) - ✓ docs/04-技术规范.md(默认技术栈,A1 让用户确认) - ✓ docs/08-模块任务管理.md(全流程进度跟踪) - 已勾选:A0 项目初始化 - - 下一步:A1 scope-lock(填写项目概述 + 技术栈 + 需求索引 + REQ 卡片) -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ -``` - -立即调用 `Skill(scope-lock)` 进入 A1,不等用户手动输入。 - -## 参考 - -- `${CLAUDE_SKILL_DIR}/templates/CLAUDE-template.md`(项目级 CLAUDE.md 模板) -- `${CLAUDE_SKILL_DIR}/templates/docs-01-index-template.md`(需求索引初稿) -- `${CLAUDE_SKILL_DIR}/templates/docs-04-stack-template.md`(默认技术栈) -- `${CLAUDE_SKILL_DIR}/templates/docs-08-initial-template.md`(A 阶段进度初始化) -- 下游:`scope-lock`(A1,自动派发) diff --git a/skills/project-init/templates/CLAUDE-template.md b/skills/project-init/templates/CLAUDE-template.md deleted file mode 100644 index 776a923..0000000 --- a/skills/project-init/templates/CLAUDE-template.md +++ /dev/null @@ -1,255 +0,0 @@ -# CLAUDE.md — ERP项目 Claude Code 主指令文件 - -> 本文件是 Claude Code 的"操作手册"。Claude Code 启动时会自动读取此文件。 - ---- - -## 🎯 项目概述 - -- **项目名称**: 【人工填写:公司 + 项目名,例如"XX 公司 ERP 管理系统"】 -- **项目简述**: 【人工填写:一句话描述项目目标,例如"面向中小制造企业的全流程 ERP,涵盖采购/库存/生产/销售/财务"】 -- **目标用户**: 【人工填写:谁会用,例如"企业内部管理人员(采购员、仓管员、生产主管、销售员、财务人员、管理层)"】 -- **部署方式**: 【人工填写:私有化部署 / 云部署 / Docker 容器化 等】 - ---- - -## 🔄 B 阶段开发流程(后端模块循环 → 前端整体阶段) - -B 阶段整体是**一个静默 Workflow 脚本 `workflows/coding.mjs`**(由瘦入口 skill 启动)。入口:`/erp-workflow:coding-start`。子代理无法弹窗 → 缺值即写阻塞点并 halt(结构性静默)。 - -### 入口与路由(coding-start skill → coding.mjs Router) - -`/erp-workflow:coding-start` 是瘦入口:校验 Plan 终结闸(docs/08 § 一 全勾、git 在默认分支、工作树干净)后,调用 `Workflow({scriptPath:"…/workflows/coding.mjs", args:{projectRoot}})` 启动整个编码阶段。`coding.mjs` 的 **Router** stage 扫描 docs/08 § 二/§ 三 里程碑字段 + 本地 `git tag -l`,产出结构化模块清单(`{id, done, reqs[], feItems[]}`),过滤待跑模块;docs/08 字段与 git tag 不一致 → halt。 - -| `backend_done` | `frontend_done` | 行为 | -|---|---|---| -| `false` | 任意 | Router 列出待跑后端模块,进入后端模块循环 | -| `true` | `false` | 进入前端阶段(`feItems` 非空的模块) | -| `true` | `true` | "所有阶段已完成" | - -### 后端阶段(每模块一个里程碑 tag) - -- **模块循环(顶层 `for module`,fail-fast)**:`featureLoop(reqs,'backend')` → `testGate('backend')`(红色自动重试 1 次防 flaky,仍红 → HALT)→ 跨模块改动记录 → 模块报告 → milestone(本地 `git merge --no-ff` 进默认分支 + 打 `milestone/<id>` tag + 回写 docs/08 § 二)→ 下一模块(无人工介入) -- **功能循环(内,每 REQ-XXX-NNN 一遍,同构 `featureLoop`)**:spec → plan → tdd → verify → review(`reviewWithFixLoop` 有界 5 轮:approve 即过;request-changes → fix → 重审;第 5 轮仍未过 → HALT) -- 后端阶段任务严格落在 `backend/` 路径下;docs/01 REQ 卡片的 UI 描述在此阶段忽略,UI 推迟到前端阶段。 - -### 前端阶段(整体一个里程碑 tag,所有后端模块打里程碑后启动) - -- **FE 清单(AI 自主推导,无审阅断点)**:FE 业务功能清单在 Plan 阶段 A6 + Router 阶段确定并写入 `docs/08 § 三`。**FE 是业务功能粒度,与 prototype HTML 文件数无关**——一个 HTML 可拆多个 FE,多个 HTML 也可合成一个 FE。 -- **FE 循环(外)**:`featureLoop(feItems,'frontend')` → `testGate('frontend')` → milestone(分支 `frontend-phase`,docs/08 § 三 整体里程碑)。 -- **FE 功能循环(内,每个 FE-NN 一遍,同构 `featureLoop`)**:spec → plan → tdd → verify → review(统一 `code-reviewer` agent,`phase=frontend` 附加 7 维 checklist) -- 前端阶段任务严格落在 `frontend/` 路径下;布局以 `prototype/` 为权威。 - -### 里程碑前测试闸门 - -- `coding.mjs` 的 **testGate** stage:后端阶段子代理跑 `scripts/test.mjs`(含本模块新增 + 已合并模块回归);前端阶段跑 vitest + playwright(命令取自 docs/04 § 零)。 -- testGate 是打里程碑 tag 前唯一的硬测试门;红色重试 1 次仍红 → HALT,不得跳过进入 report / milestone stage。 - ---- - -## ✅ 阶段完成判定规则 - -`docs/08-模块任务管理.md` 分两段: -- `§ 二`:后端模块元数据表(每个模块一行 bullet,记录依赖 / 路径 / 里程碑 tag / 功能子项) -- `§ 三`:前端阶段元数据(整体里程碑 + FE 子项清单,由 Plan 阶段 A6 + `coding.mjs` 在所有后端模块打里程碑后填入) - -**阶段完成判定**统一以 `里程碑:` 字段(§ 二 各模块) / `整体里程碑:` 字段(§ 三)+ 本地 `git tag -l 'milestone/<id>'` 判定;子项勾选只作可视化进度,不参与完成判定。 - -### 后端模块格式 - -每个后端模块在 docs/08 § 二 中长这样: - -```markdown -- module_sys 系统管理 - - 依赖: — - - 路径: backend/module/sys/ - - 里程碑: — - - 功能: - - [ ] REQ-SYS-001 用户登录 - - [ ] REQ-SYS-002 用户注册 -``` - -- `里程碑:` 字段由 `coding.mjs` 的 milestone stage 在打里程碑 tag 时从 `—` 改为 `milestone/<module_id>`。 -- 每个 `REQ-*` 子项由 `coding.mjs` 的 review stage 在 `verdict=approve` 时自动勾选为 `[x]`。 -- 路径限定为后端目录(如 `backend/module/sys/`);前端代码不在此阶段产生。 - -### 前端阶段格式(§ 三) - -```markdown -- 整体里程碑: — -- 功能: - - [ ] FE-01 用户登录与注册 | 关联 REQ:REQ-SYS-001, REQ-SYS-002 | 关联原型:prototype/auth.html - - [ ] FE-02 仪表盘总览 | 关联 REQ:REQ-DASH-001 | 关联原型:prototype/dashboard.html -``` - -- `整体里程碑:` 字段由 `coding.mjs` 的 milestone stage 在打前端里程碑 tag 时从 `—` 改为 `milestone/frontend-phase`。 -- "功能:" 列表由 Plan 阶段 A6(`frontend-scope-lock`)+ `coding.mjs` 推导写入(无人工审阅断点)。FE 是业务功能粒度,与 prototype HTML 文件数无关。 -- 每个 `FE-NN` 子项由 `coding.mjs` 的 review stage 在 `verdict=approve` 时自动勾选为 `[x]`。 -- prototype/ 门禁在 Plan 阶段 A6 `frontend-scope-lock` 强制检查项目根 `prototype/` 至少含 1 个 `*.html` mockup。 - -### 状态语义(后端模块 + 前端阶段共用) - -| `里程碑:` 字段 | `git tag -l` | 含义 | 你(Claude Code)的行为 | -|---|---|---|---| -| `—` | tag 不存在 | 该阶段未开始 / 进行中(未打里程碑) | ✅ 开始 / 继续该阶段开发 | -| `milestone/<id>` | tag 存在 | 阶段**已完成** | 🟢 后端:进入下一未完成模块;后端全完 → 前端阶段;前端已打里程碑 → 全部完成 | - -### 模块完成报告 - -由 `coding.mjs` 的 report stage 产出(12 节标准化,含跨模块改动等 CLAUDE.md 软规则映射节)。CC 不手写模块报告。 - ---- - -## 🏷️ 占位符统一约定 - -项目文档里有 **2 种填写占位** + **1 种提示占位**: - -| 格式 | 谁填 | 使用阶段 | 说明 | -|------|-----|---------|------| -| `【人工填写:<简短说明>】` | 人 | 仅 A 阶段文档 | 密钥 / 账密 / 包名 / 命名约定 / 小版本号等人工才能决定的值;B 阶段 plan/spec 禁止出现,查不到真值时用 `AskUserQuestion` 问用户 | -| `TBD(<责任人>)` | CC 自动 | A 或 B | 后缀附带责任方(如 `TBD(A3 自动补)` / `TBD(A5 自动补)`);由对应 skill / `coding.mjs` stage 就地补填,模块完成报告 § ⑦ 检查 `TBD(CC 补)` 残留 | - -**HTML 注释 `<!-- ... -->`**:提示占位,是**插件内部大纲模板**里给 LLM 的**填空提示 / 章节引导**,指引 LLM 按结构填实际内容。skill 生成时会**剥除**这些注释,最终产物里注释不会保留。 - ---- - -## 📐 编码行为约束 - -### 你必须做的 ✅ - -1. **严格遵循** `docs/04-技术规范.md`——命名 / 编码 / 统一响应 / 异常处理 / 数据访问 / 配置与安全 等项目专属技术规约全部在此 -2. **严格遵循** `docs/09-项目目录结构.md`——文件放对位置 -3. **每个后端接口** 必须先在 `docs/05-API接口契约.md` 定义,再编码实现 -4. **每个功能可追溯到 `REQ-XXX-NNN`**——commit tag + 代码注释(如 `// REQ-SYS-001: 用户登录`)+ plan/spec 文件名均用此 tag -5. **遇到跨模块改动**(动到非当前模块的代码)——按 § 🟡 软规则 **S2** 执行(允许改,但必须留痕) -6. **遇到技术栈外组件引入**(`docs/04 § 零` 技术栈表外的框架 / 中间件 / 关键库),按 § 🟡 软规则 **S1** 执行(允许引入,但必须先 AskUserQuestion) - -### 你禁止做的 🚫 - -1. **主会话直接 `mysql -e` 跑业务 DDL**(只读查询 / 临时本地调试除外)——业务 schema 必须走 `sql/migrations/V_n__*.sql`,详见下方 Schema 演化规约 -2. **手动 Edit `docs/08 § 二/§ 三` 的 `里程碑:` / `整体里程碑:` 字段**,必须要由 `coding.mjs` 的 milestone stage 自动回写 - -### Schema 演化规约(Flyway migration) - -1. **文件命名**:`sql/migrations/V<n>__<snake_case_desc>.sql`,例:`V5__add_user_email_unique_index.sql` -2. **版本号分配**:建文件前 `ls sql/migrations/V*.sql` 查当前最大 n,新文件 `n_max + 1` -3. **Apply 方式**:Spring Boot 启动 / 测试启动时 Flyway 自动 apply(项目必须在 `pom.xml` 声明 `flyway-core` + `flyway-mysql` 依赖)。`scripts/setup-test-db.mjs` 只负责清空库,不做 apply -4. **已合并的 migration 永不修改**:发现错了写一个补救 migration(如 `V7__fix_V5_index_name.sql`),旧 `V_n.sql` -5. **临时调试 DDL**:临时在本地试字段/索引可手动 `mysql -e`,但不写 migration;下次 `setup-test-db.mjs` 会 drop+create 清掉 -6. **A4 生成的 V1**:`V1__initial_schema.sql` 是 A 阶段由 `db-init` 从 `docs/03-数据库设计文档.md`(A3 正向设计的 schema SSoT)翻译生成的初始版本;后续 V2/V3/... 由 B 阶段每个 REQ 按需写入,**同时**反向同步更新 docs/03 对应表小节以保持 SSoT 一致 - ---- - -## 🗂️ Git 提交规范 - -每次提交必须遵循以下格式: - -``` -<type>(<scope>): <subject> -``` - -- `scope`: 模块名,如 `user` / `inventory` / `order` -- `subject`: 简短描述;业务类(feat / fix / test)必须带 `REQ-XXX-NNN` 后缀 - -`type` 含义: - -| type | 看到它意味着 | -|-----|-------------| -| `feat` | **新能力上线**——用户多了一个功能、接口、页面或业务规则 | -| `fix` | **修 bug**——原来行为错了,这次改对 | -| `refactor` | **重构**——外部行为不变,只改代码结构 / 命名 / 抽象 | -| `docs` | **文档改动**——只动 Markdown / 代码注释,不动实现 | -| `style` | **格式调整**——空白 / 缩进 / import 顺序,逻辑 0 变化 | -| `test` | **只动测试代码**——补用例 / 修 fixture,不碰实现 | -| `chore` | **流程维护**——构建 / 依赖 / 工具 / 证据档案 / 里程碑元数据等非业务动作 | - ---- - -## 🚩 中断机制 - -功能循环(每个功能 REQ-XXX 的 Brainstorm → Plan → TDD → Verify → AI 自审)默认 **静默编程**,但触发以下任何一条必须**立刻停下、记录原因、等人决策**,不得自行绕过: - -| # | 中断 | 例子 | -| - | --- | --- | -| 1 | **测试反复失败** | 同一测试同一功能内连续 **10 次**修复失败 | -| 2 | **要改密钥 / 账密 / 包名** | 密钥 / 账密 在 `.env.local`、包名 / 命名空间 / 端口等在 `config-vars.yaml` 里由人工标注必须填的字段(规则见 `docs/07-环境配置.md`) | -| 3 | **外部接口不可达** | 第三方 API 无法连接、证书失效等环境问题,并无法自行解决 | - -> 其余需要人类判断的场景一律走普通 `AskUserQuestion` Q&A,不中断、不写 Blocker 文件。 - -**触发中断时的固定动作:** - -1. `coding.mjs` 子代理在当前功能的 plan 文件里追加一节 `## 🚩 Blocker`(记录原因 / 阻塞点),并 throw 进入 HALT 终止态 -2. 整阶段 fail-fast:halt 后停止后续所有模块/功能的静默执行 -3. Workflow 返回结构化诊断(halt 原因 + blocker 文件路径),等人修复后重跑 `/erp-workflow:coding-start` 从断点续跑 - ---- - -## 🟡 软规则(允许继续,但有强制后续动作) - -以下情况 **不触发中断**,CC 可自行继续推进,但必须在约定位置留痕,模块完成时统一审计。 - -| # | 软规则 | 允许动作 | 强制后续 | -| - | ----- | ------- | ------- | -| S1 | **技术栈外组件引入** | 用 `AskUserQuestion` 给用户三选一:接受引入 / 换方案 / 拒绝 | ① **接受** → 同会话直接在 `docs/04 § 零` 追加一行 → 继续流程 ② **换方案 / 拒绝** → 视为常规歧义澄清,继续 Q&A 收敛 ③ 不写 Blocker、不中断流程 | -| S2 | **跨模块改动** | **默认不改**,仅为当前模块实现所必需时允许修改 | `coding.mjs` 的 cross-module stage 在模块循环内记录改动并补「原因 / 影响评估」,「跨模块改动」节完整贴入《模块完成报告》 | - ---- - -## 🧭 通用工作准则(General Principles) - -### 1. Think Before Coding - -**Don't assume. Don't hide confusion. Surface tradeoffs.** - -Before implementing: -- State your assumptions explicitly. If uncertain, ask. -- If multiple interpretations exist, present them - don't pick silently. -- If a simpler approach exists, say so. Push back when warranted. -- If something is unclear, stop. Name what's confusing. Ask. - -### 2. Simplicity First - -**Minimum code that solves the problem. Nothing speculative.** - -- No features beyond what was asked. -- No abstractions for single-use code. -- No "flexibility" or "configurability" that wasn't requested. -- No error handling for impossible scenarios. -- If you write 200 lines and it could be 50, rewrite it. - -Ask yourself: "Would a senior engineer say this is overcomplicated?" If yes, simplify. - -### 3. Surgical Changes - -**Touch only what you must. Clean up only your own mess.** - -When editing existing code: -- Don't "improve" adjacent code, comments, or formatting. -- Don't refactor things that aren't broken. -- Match existing style, even if you'd do it differently. -- If you notice unrelated dead code, mention it - don't delete it. - -When your changes create orphans: -- Remove imports/variables/functions that YOUR changes made unused. -- Don't remove pre-existing dead code unless asked. - -The test: Every changed line should trace directly to the user's request. - -### 4. Goal-Driven Execution - -**Define success criteria. Loop until verified.** - -Transform tasks into verifiable goals: -- "Add validation" → "Write tests for invalid inputs, then make them pass" -- "Fix the bug" → "Write a test that reproduces it, then make it pass" -- "Refactor X" → "Ensure tests pass before and after" - -For multi-step tasks, state a brief plan: -``` -1. [Step] → verify: [check] -2. [Step] → verify: [check] -3. [Step] → verify: [check] -``` - -Strong success criteria let you loop independently. Weak criteria ("make it work") require constant clarification. diff --git a/skills/project-init/templates/docs-01-index-template.md b/skills/project-init/templates/docs-01-index-template.md deleted file mode 100644 index 08e326a..0000000 --- a/skills/project-init/templates/docs-01-index-template.md +++ /dev/null @@ -1,16 +0,0 @@ -# 需求清单 - -> 本目录按模块组织所有功能需求。每个模块一个子目录,含 `_module.md`(模块头)和 `REQ-XXX-NNN.md`(每张 REQ 卡片一个文件)。下方核心功能点供 CC 拆分出 REQ 编号 + 标题 + 草拟规则;卡片内输入 / 输出的简述句和 N 张字段表由人工编辑。 - -## 模块索引 - -| 模块代码 | 模块名称 | 核心功能点(简要) | -|----------|----------|--------------------| -| 【人工填写:模块代码】 | 【人工填写:模块名称】 | 【人工填写:核心功能点】 | -| SYS | 系统管理 | 用户/角色/权限/部门/字典 等 | - -## 填写说明 - -1. 每个模块占一行,`模块代码` 用大写英文缩写(如 SYS / PUR / INV / SAL / FIN / HR) -2. `核心功能点` 只需列关键词,CC 会基于此拆分出 N 张 REQ 卡片骨架(卡片内输入 / 输出的简述句和字段表仍由人工编辑) -3. 填完后运行 `/erp-workflow:plan-start`,CC 会自动检测并进入需求生成阶段 diff --git a/skills/project-init/templates/docs-04-stack-template.md b/skills/project-init/templates/docs-04-stack-template.md deleted file mode 100644 index 234b200..0000000 --- a/skills/project-init/templates/docs-04-stack-template.md +++ /dev/null @@ -1,32 +0,0 @@ -# 04-技术规范 - -## 零、技术栈总览 - -| 分层模块 | 技术 | 版本要求 | 说明 | -|---|---|---|---| -| 前端基础框架 | React | 18.x | 构建前端应用 | -| 前端 UI 组件 | Ant Design | 5.x | 页面组件与交互控件 | -| 前端状态管理 | Redux Toolkit | 最新稳定版 | 管理全局状态 | -| 前端路由管理 | React Router | v6 | 页面路由与导航 | -| 前端工程化构建 | Vite | 最新稳定版 | 前端开发与打包构建 | -| 前端接口通信 | Axios | 最新稳定版 | 调用后端 API | -| 后端基础框架 | Spring Boot | 3.x | 构建后端服务 | -| 后端数据访问 | MyBatis-Plus | 最新稳定版 | 数据库访问与 ORM 增强 | -| 工作流引擎 | Activiti | 6.x | 审批流、流程流转 | -| 缓存服务 | Redis | 最新稳定版 | 缓存、会话、分布式能力 | -| 报表打印 | JXLS | 2.8.1 | 基于 Excel 模板生成报表 | -| Excel 导入导出 | EasyExcel | 4.0.3 | Excel 数据导入导出 | -| 关系型数据库 | MySQL | 8.x | 核心业务数据存储 | -| 数据库 schema 迁移 | Flyway (`flyway-core` + `flyway-mysql`) | 10.x / 最新稳定版 | `sql/migrations/V_n__*.sql` 顺序 apply;Spring Boot 启动时自动应用 | -| 接口风格 | RESTful API | 统一规范 | 前后端接口设计规范 | -| 权限认证 | Spring Security / JWT | 最新稳定版 | 登录认证、权限控制 | -| API 文档 | OpenAPI / Swagger | 最新稳定版 | 接口文档与调试 | -| 项目构建管理 | Maven | 3.9.x | Java 项目依赖与构建 | -| JDK 运行环境 | Java | 17 / 21 | Spring Boot 3 推荐版本 | -| 部署容器 | Docker | 最新稳定版 | 容器化部署 | -| Web 服务器 / 反向代理 | Nginx | 最新稳定版 | 前端托管、反向代理、负载分发 | -| 日志管理 | Logback | 默认集成 / 最新稳定版 | 应用日志输出 | -| 对象映射工具 | MapStruct | 最新稳定版 | DTO / VO / Entity 转换 | -| 工具类库 | Hutool / Apache Commons | 最新稳定版 | 常用工具方法支持 | - -> 本表由 scope-lock 锁定。后续所有规范基于此表推导。 diff --git a/skills/project-init/templates/docs-08-initial-template.md b/skills/project-init/templates/docs-08-initial-template.md deleted file mode 100644 index 61fc530..0000000 --- a/skills/project-init/templates/docs-08-initial-template.md +++ /dev/null @@ -1,76 +0,0 @@ -# 08-工作流进度 - -> 全流程进度跟踪。CC 每完成一项产出就勾选一项。 -> - **§ 一 Plan(A0~A6)**:`plan-start` 找第一个未勾 A 子项分发到对应 skill -> - **§ 二 Coding(模块)**:分发以 `docs/02-开发计划.md § 二 开发顺序清单` 为准;`coding-start` 按 docs/02 顺序扫描,对每个 REQ 所属模块查询本 § 二的 `里程碑:` 字段 + 本地 `git tag -l 'milestone/<id>'`,找第一个未打里程碑模块分发。本 § 二 行序无语义,仅作模块元数据表 - -## 一、Plan 阶段(一次性) - -- [ ] A0 项目初始化 — project-init - - [ ] 依赖检查通过 - - [ ] 项目文件骨架已创建(CLAUDE.md + docs/01-需求清单/index.md + docs/04-技术规范.md) - - [ ] Git 已初始化 - -- [ ] A1 范围锁定 — scope-lock - - [ ] 项目概述已填写(CLAUDE.md § 🎯 项目概述) - - [ ] 技术栈已确认(docs/04 § 零) - - [ ] 需求清单索引已填写(docs/01-需求清单/index.md) - - [ ] REQ 卡片骨架已生成(docs/01-需求清单/<module>/REQ-*.md,业务内容留待人工填写) - -- [ ] A2 骨架生成 — skeleton-gen - - [ ] 架构文档已生成(docs/04 § 一+、docs/06、docs/07、docs/09) - - [ ] 工具脚本已生成(scripts/*.mjs、.env.local) - - [ ] 样式 token 骨架已生成(src/styles/tokens.css) - - [ ] .gitignore 已配置 - -- [ ] A3 DB 设计 + REQ 回填 — db-design-gen - - [ ] docs/03-数据库设计文档.md 已生成 - - [ ] docs/01 各 REQ 卡片"依赖表" + 模块头"涉及表" 已回填 - -- [ ] A4 DB 初始化 — db-init - - [ ] sql/migrations/V1__initial_schema.sql 已生成 - - [ ] DDL 与 docs/03 全量一致 - - [ ] .env.local 凭据已验证(mysql -e "SELECT 1" OK) - - [ ] setup-test-db.mjs 防护通过 + DROP+CREATE + apply V1 已执行 - - [ ] DDL ↔ docs/03 apply 后 5 维一致(validate-ddl.mjs) - -- [ ] A5 下游文档生成 — downstream-gen - - [ ] docs/02 开发计划已生成 - - [ ] docs/05 API 契约已生成 - - [ ] docs/06 § 三 页面清单已填入 - - [ ] docs/10 验收清单已生成 - - [ ] 下方模块列表已填入 - - [ ] REQ 卡片依赖接口已回填 - -- [ ] A6 前端范围锁定 — frontend-scope-lock - - [ ] docs/06 项目级 UI 约定 + Design Tokens + 组件库已锁定 - - [ ] docs/04 § 二 前端栈已锁定(引用 docs/06) - - [ ] 各 FE-NN 设计决策表已生成(docs/06 § 三之后 / docs/08 § 三) - -## 二、Coding 阶段(后端模块循环) - -(A5 填入后,每行一个后端模块。每个模块的 `里程碑:` 字段在 `—` 和 `milestone/<id>` 之间变化,完成由本地 `git tag -l` 判定。`coding-start` 每次按 docs/02 REQ 序扫每模块的里程碑 tag 决定派发。后端模块全部打里程碑后自动进入 § 三 前端阶段。) - -<!-- 模块格式示例(由 A5 downstream-gen 追加;功能子项由 coding.mjs 的 review stage 在 approve 时勾选): -- module_sys 系统管理 - - 依赖: — - - 路径: backend/module/sys/ - - 里程碑: — - - 功能: - - [ ] REQ-SYS-001 用户登录 - - [ ] REQ-SYS-002 用户注册 ---> - -## 三、Coding 阶段(前端整体) - -(FE 业务功能清单在 Plan 期 A6 `frontend-scope-lock` 由 prototype/ + docs/01 + docs/05 推导后写入下方"功能:"项;Coding 阶段 `coding.mjs` 的 Router 把全部未完成 FE 聚合为单一 `frontend-phase` 阶段,排在所有后端模块之后。整个前端阶段 1 个里程碑 tag,分支 `frontend-phase`。) - -- 整体里程碑: — -- 功能: - <!-- AI 进入时按以下行格式写入(每行 1 个 FE,可关联多个 REQ / 多份原型): - - [ ] FE-NN 功能名 | 关联 REQ:REQ-A, REQ-B | 关联原型:prototype/<file>.html, prototype/<other>.html - - 示例: - - [ ] FE-01 用户登录与注册 | 关联 REQ:REQ-SYS-001, REQ-SYS-002 | 关联原型:prototype/auth.html - - [ ] FE-02 仪表盘总览 | 关联 REQ:REQ-DASH-001 | 关联原型:prototype/dashboard.html - --> diff --git a/skills/scope-lock/SKILL.md b/skills/scope-lock/SKILL.md deleted file mode 100644 index bbe71c2..0000000 --- a/skills/scope-lock/SKILL.md +++ /dev/null @@ -1,231 +0,0 @@ ---- -name: scope-lock -description: A1 计划范围锁定——引导用户填写项目概述 + 技术栈 + 需求索引,并按模块子目录生成 REQ 卡片骨架(CC 推断 req_id/title/goal/rules/constraints/acceptance;输入/输出 字段表为结构化 6 列表单由人工逐行填真实数据);末尾执行 A1 终结校验:每张 REQ 卡片字段含真实数据、配置字段名锁进 config-vars.yaml(非敏感填值 + secrets_ref 键名引用 .env.local)、build/lint/unit/e2e 命令锁进 docs/04 §零,缺则当场 AskUserQuestion 问清。 -user-invocable: false -allowed-tools: Read Write Edit Grep Glob Skill AskUserQuestion Bash(mkdir *) Bash(node *) Bash(rm *) ---- - -**所有输出必须使用中文。** - -# scope-lock - -> **关于 AskUserQuestion**:下文只描述「问什么、给哪些选项、各选项导向什么后续」。`header` / 各选项的 `description` / `multiSelect` 等具体参数由你按工具 schema 自行填全合法值——不要把下文的选项文字当成完整调用照抄。 - -## 执行步骤 - -### A. 提示用户填写项目概述并等待 - -向用户输出: - -``` -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - [scope-lock] 请填写项目概述 - - 📄 文件位置: ./CLAUDE.md - 📌 编辑位置: § 🎯 项目概述 - - 请将以下占位符替换为实际值: - - 项目名称 - - 项目简述 - - 目标用户 - - 部署方式 - 改完后回来选择「继续」。 -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ -``` - -用 `AskUserQuestion` 确认「项目概述填写完毕了吗?」,给「继续」和「有疑问想先沟通」两个选项。 - -- 选「继续」→ 用 `Grep` 在 `CLAUDE.md` 搜索 `【人工填写:`(限定 § 🎯 项目概述 节)。命中 → 打印残留行 + 路径,重新确认一次;0 命中 → 勾选并进入步骤 B。 -- 选「有疑问想先沟通」→ 回答用户问题后,再确认一次。 - -0 命中后,用 `Edit` 在 `docs/08-模块任务管理.md` 中勾选: -- ` - [ ] 项目概述已填写(CLAUDE.md § 🎯 项目概述)` - -### B. 提示用户检查默认技术栈并等待 - -`docs/04-技术规范.md` 已由 A0 `project-init` 用模板复制(默认技术栈,见 `project-init/templates/docs-04-stack-template.md`)。本步骤让用户检查 / 调整 § 零。 - -向用户输出: - -``` -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - [scope-lock] 技术栈已保存 - - 📄 文件位置: ./docs/04-技术规范.md(由 A0 模板生成) - 📌 编辑位置: § 零、技术栈总览 - - 请检查技术栈表: - - 不需要的行直接删除(如纯后端项目删前端行) - - 需要替换的技术直接改 - - 需要新增的条目直接加行 - 改完后回来选择「继续」。 -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ -``` - -用 `AskUserQuestion` 确认「技术栈检查完毕了吗?」,给「继续」和「有疑问想先沟通」两个选项。 - -- 选「继续」→ 进入步骤 C。 -- 选「有疑问想先沟通」→ 回答用户问题后,再确认一次。 - -完成后,用 `Edit` 在 `docs/08-模块任务管理.md` 中勾选: -- ` - [ ] 技术栈已确认(docs/04 § 零)` - -### C. 提示用户填写需求清单并等待 - -`docs/01-需求清单/index.md` 已由 `project-init` 写入占位符模板,这里让用户补齐模块清单。 - -向用户输出: - -``` -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - [scope-lock] 请填写需求清单模块索引 - - 📄 文件位置: ./docs/01-需求清单/index.md - 📌 编辑位置: § 模块索引(表格) - - 请按业务列出所有模块: - - 每行一个模块(如 SYS 系统管理 / PUR 采购 / SAL 销售) - - 「核心功能点」只需关键词,CC 会拆分为 REQ 卡片 - 改完后回来选择「继续」。 -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ -``` - -用 `AskUserQuestion` 确认「需求清单模块索引填写完毕了吗?」,给「继续」和「有疑问想先沟通」两个选项。 - -- 选「继续」→ 进入步骤 D。 -- 选「有疑问想先沟通」→ 回答用户问题后,再确认一次。 - -完成后,用 `Edit` 在 `docs/08-模块任务管理.md` 中勾选: -- ` - [ ] 需求清单索引已填写(docs/01-需求清单/index.md)` - -### D. 生成 REQ 卡片骨架并停下等人工审阅 - -1. 用 `Grep` 校验 `docs/01-需求清单/index.md` 无 `【人工填写:` 残留;有则回步骤 C。 -2. 用 `Read` 读 `index.md` 解析模块索引。 -3. **逐文件渲染落盘**(用 Node 渲染助手,跨平台、字面量安全): - - - **每模块推断**:三元组 `{module_code, module_name, module_brief}` + N 个 REQ 的六元组 `{req_id, title, goal, rules, constraints, acceptance}`。`req_id`/`title` 从核心功能点拆分;`goal` 展开 `title`;`rules`/`constraints`/`acceptance` 起草业务语义。**不推断**输入 / 输出字段(模板的结构化字段表保留示例行,留待人工逐行填真实数据)。 - - **渲染助手** `lib/render.mjs` 的 CLI 形态为 `node <render.mjs> <模板路径> <vars.json 路径> <输出路径>`:读模板 + 读 JSON 变量 + 占位符字面替换 + 自动剥离 HTML 注释,写到输出路径。值含 `$`、`{`、`}`、`}}` 均按字面插入,无需兜底。 - - **每个文件三步**:(a) 用 `Write` 写一个临时 vars JSON(仅含该文件用到的占位符键值);(b) `mkdir -p` 模块目录;(c) `node` 调 render.mjs 渲染。`<MOD>` / `<模块名>` / `<REQ-MOD-NNN>` 等尖括号位置 CC 按 `index.md` 实际值替换。调用形态: - - ```bash - # 模块头:先 Write docs/01-需求清单/<MOD>-<模块名>/_module.vars.json,内容形如 - # {"module_code":"<MOD>","module_name":"<模块名>","module_brief":"<module_brief>"} - mkdir -p "docs/01-需求清单/<MOD>-<模块名>" - node "${CLAUDE_PLUGIN_ROOT}/lib/render.mjs" \ - "${CLAUDE_SKILL_DIR}/templates/_module-template.md" \ - "docs/01-需求清单/<MOD>-<模块名>/_module.vars.json" \ - "docs/01-需求清单/<MOD>-<模块名>/_module.md" - - # 每个 REQ:先 Write 该 REQ 的 vars JSON,内容形如 - # {"req_id":"<REQ-MOD-NNN>","title":"<title>","goal":"<goal>","rules":"<rules>","constraints":"<constraints>","acceptance":"<acceptance>"} - node "${CLAUDE_PLUGIN_ROOT}/lib/render.mjs" \ - "${CLAUDE_SKILL_DIR}/templates/req-card-template.md" \ - "docs/01-需求清单/<MOD>-<模块名>/<REQ-MOD-NNN>.vars.json" \ - "docs/01-需求清单/<MOD>-<模块名>/<REQ-MOD-NNN>.md" - ``` - - - 渲染完成后删除临时 `*.vars.json`(`rm` 或不留亦可,不进入交付物)。 -4. 用 `Edit` 在 `docs/08-模块任务管理.md` 勾选(A1 子项): - - ` - [ ] REQ 卡片骨架已生成(docs/01-需求清单/<module>/REQ-*.md,业务内容留待人工填写)` - - **注意**:此处先**不**勾选 `- [ ] A1 范围锁定 — scope-lock` 顶层项;A1 顶层项必须在步骤 E(A1 终结校验)全部通过后才勾选。 -5. 打印「请人工填写 REQ 卡片」横幅并提示用户填完后回来继续(不停止,下一步是 A1 终结校验): - -``` -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - [scope-lock] REQ 卡片骨架已生成 - - 产出: - ✓ docs/01-需求清单/<module>/_module.md 模块头 - ✓ docs/01-需求清单/<module>/REQ-*.md REQ 卡片骨架 - - ⏸ 现在请你逐张打开 REQ 卡片,把结构化字段表填成真实数据: - - **必改**:`输入字段` / `输出字段` 两张表 - · 删掉「【示例行,替换为真实字段】」示例行,按本 REQ 业务逐行填真实字段 - · 6 列全部填:字段名 / 类型 / 必填 / 校验规则 / 业务规则 / 示例值 - · **「示例值」列必须是真实约束下的合法取值**——留 `<示例值>` 或示例行会被 A1 终结校验阻断 - - **审阅**:目标 / 跨字段规则 / 边界 / 验收(已起草,对照业务校正) - - **保留**:`TBD` 不要改,由之后流程自动回填 - - 填完后回来选择「继续」,进入 A1 终结校验。 -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ -``` - -用 `AskUserQuestion` 确认「所有 REQ 卡片的结构化字段都填成真实数据了吗?」,给「继续」和「有疑问想先沟通」两个选项。 - -- 选「继续」→ 进入步骤 E(A1 终结校验)。 -- 选「有疑问想先沟通」→ 回答用户问题后,再确认一次。 - -### E. A1 终结校验(硬闸:全部通过才勾选 A1 顶层) - -> 本步骤把原本会在编码期(coding.mjs 的 spec / plan stage)弹出的需求澄清 / config Q&A **全部前移到此处**。任一检查不满足,用 `AskUserQuestion` 在**此处(Plan 期)**问清并修订,**禁止**留待编码期。三项检查全过后才在 `docs/08` 勾选 `- [ ] A1 范围锁定 — scope-lock`。 - -#### E.1 真实数据校验(每张 REQ 卡片) - -1. 用 `Glob` 列出所有 `docs/01-需求清单/<module>/REQ-*.md`。 -2. 对每张卡片用 `Read` + `Grep` 校验: - - **无模板默认占位**:卡片内**不得**出现 `【示例行,替换为真实字段】` 或 `<示例值>`(用 `Grep` 搜这两个字面量,命中即视为未完成)。 - - **结构化字段非空**:`输入字段` / `输出字段` 两张表每行 6 列均非空,且不是模板示例行内容;至少各有 1 行真实字段(除非该 REQ 确实无输入/输出,需在卡片显式标注)。 - - **`示例值` 列已填真实取值**:每行示例值列为真实约束下的合法取值,非占位。 - - **`{{...}}` 残留**:不得残留任何 `{{` 占位(说明渲染未替换)。 -3. 任一卡片不通过:打印不通过的卡片路径 + 具体缺口行,用 `AskUserQuestion` 引导用户当场补齐(可针对具体字段含义/校验规则发问),修订后重跑 E.1,直到全部通过。 - -#### E.2 配置字段名锁进 config-vars.yaml(敏感键名引用 .env.local) - -1. 用 `Read` 读 `docs/04-技术规范.md` § 零技术栈,结合 REQ 卡片,盘点本项目需人工提供 / 确认的配置字段,分两类: - - **非敏感、项目级**:后端根包名 / 命名空间(Java package / C# namespace / Python 顶层包 / Go module path 等)、应用端口、前端包名 / scope、前端 dev 端口、管理员初始账号等。 - - **敏感凭据**:数据库密码、JWT / 签名密钥、Redis 密码、第三方 API key/secret、OSS / 对象存储凭证、短信 / 邮件服务凭证、管理员初始密码等。 -2. 用 `Read` 读模板 `${CLAUDE_SKILL_DIR}/templates/config-vars-template.yaml`,用 `Write` 落盘到仓库根 `config-vars.yaml`: - - **非敏感字段**:按技术栈推断默认值直接填入(如 `http_port: 8080`、`base_package: com.<org>.<app>`);无对应技术栈的整节删除(如纯后端项目删 `frontend:`);无法可靠推断的留 `【人工填写:…】`(A2 skeleton-gen 补填)。 - - **敏感字段**:只把「键名 + 含义」登记进 `secrets_ref` 列表,**绝不写真实值**(真实值由 A2 写进 `.env.local`,A2 据 `secrets_ref` 核对齐全)。 -3. **不**在此创建 / 填写 `docs/07-环境配置.md`——它由 A2 skeleton-gen 生成,只记规则不记具体值。 -4. 用 `AskUserQuestion` 向用户确认:「以下配置 / 凭据字段已登记进 config-vars.yaml,是否齐全?还有遗漏的吗?」展示非敏感字段 + `secrets_ref` 键名清单。用户补充则继续登记,直到确认齐全。 - -#### E.3 build / lint / unit / e2e 命令锁进 docs/04 § 零 - -1. 用 `Read` 读 `docs/04-技术规范.md` § 零技术栈表,确定本项目涉及的每个 stack(如后端、前端,可能多个)。 -2. 对**每个 stack**,用 `AskUserQuestion`(如默认值可推断则展示默认值让用户确认/覆盖)收集四类命令: - - **build**(构建命令,如 `mvn package` / `npm run build`) - - **lint**(静态检查命令,如 `npm run lint`) - - **unit**(单元测试命令,如 `mvn test` / `npm run test:unit`) - - **e2e**(端到端测试命令,如 `npm run test:e2e`;无则显式记 `无`) -3. 把确认后的命令写入 `docs/04-技术规范.md` § 零(若 § 零无「命令」小节则用 `Edit` 新增一个「命令清单」小节,按 stack 分组列出 build/lint/unit/e2e 四行)。这些命令是 Coding 阶段 `coding.mjs` 的 tdd / test-gate 读取来源,必须在此锁全。 - -#### E.4 全部通过后勾选 A1 顶层并停止 - -三项检查(E.1 / E.2 / E.3)全部通过后: - -1. 用 `Edit` 在 `docs/08-模块任务管理.md` 勾选 `- [ ] A1 范围锁定 — scope-lock` 顶层项。 -2. 打印 A1 完成横幅并**停止**: - -``` -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - [scope-lock] ✅ A1 范围锁定完成(终结校验通过) - - 产出 & 锁定: - ✓ CLAUDE.md § 🎯 项目概述 - ✓ docs/04 § 零 技术栈 + build/lint/unit/e2e 命令 - ✓ docs/01-需求清单/index.md 模块索引 - ✓ docs/01-需求清单/<module>/_module.md 模块头 - ✓ docs/01-需求清单/<module>/REQ-*.md 字段表已填真实数据 - ✓ config-vars.yaml 配置字段 + secrets_ref 键名已锁(敏感真实值留待 A2 .env.local) - - 运行以下命令继续进入 A2: - /erp-workflow:plan-start - -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ -``` - -## 参考 - -- `CLAUDE.md` § 🎯 项目概述(写入目标) -- `docs/04-技术规范.md`(技术栈输出,供 skeleton-gen 读取使用) -- `docs/01-需求清单/index.md`(模块索引输入) -- `docs/01-需求清单/<module>/_module.md`(模块头输出) -- `docs/01-需求清单/<module>/REQ-*.md`(REQ 卡片骨架输出,A3 db-design-gen / A5 downstream-gen 会回填 TBD 字段) -- `config-vars.yaml`(A1 终结校验 E.2 输出:非敏感配置字段填值 + secrets_ref 键名锁定;仓库根) -- `${CLAUDE_SKILL_DIR}/templates/config-vars-template.yaml`(E.2 渲染来源;跨栈中立,YAML 注释引导) -- `${CLAUDE_SKILL_DIR}/templates/req-card-template.md`(结构化 6 列字段表) -- `${CLAUDE_SKILL_DIR}/templates/_module-template.md` -- `${CLAUDE_PLUGIN_ROOT}/lib/render.mjs`(步骤 D 渲染助手;CLI 形态 `node render.mjs <模板> <vars.json> <输出>`,字面量安全 + 自动剥 HTML 注释) diff --git a/skills/scope-lock/templates/_module-template.md b/skills/scope-lock/templates/_module-template.md deleted file mode 100644 index 5425b83..0000000 --- a/skills/scope-lock/templates/_module-template.md +++ /dev/null @@ -1,5 +0,0 @@ -# {{module_code}}-{{module_name}} - -- **模块简述**: {{module_brief}} -- **依赖模块**: TBD(A5 自动补) -- **涉及表**: TBD(A3 自动补) diff --git a/skills/scope-lock/templates/config-vars-template.yaml b/skills/scope-lock/templates/config-vars-template.yaml deleted file mode 100644 index f986f4e..0000000 --- a/skills/scope-lock/templates/config-vars-template.yaml +++ /dev/null @@ -1,30 +0,0 @@ -# config-vars.yaml — 项目配置清单 -# -# 用途:登记「需人工提供 / 确认」的非敏感、项目级配置(根包名、应用端口、前端包名、初始账号等)。 -# YAML 分组,逐项填写与核对一目了然。 -# 规则:命名约定 / 端口约定 / 安全要求统一写在 docs/07-环境配置.md,本文件只放值、不重复写规则。 -# 边界: -# - 机器 / 环境相关的连接信息(DB_HOST / DB_PORT / DB_USER / DB_SCHEMA 等)→ 仓库根 .env.local,不写在此。 -# - 敏感凭据(密码 / 密钥 / token)→ .env.local;本文件 secrets_ref 只登记键名供核对,绝不写真实值。 -# 填写:A1 scope-lock 按 docs/04 § 零 技术栈推断默认值填入;无对应技术栈的整节删除;无法推断的留 【人工填写:…】(A2 skeleton-gen 补填)。 - -backend: - base_package: 【人工填写:后端根包名 / 命名空间,如 com.acme.erp】 - http_port: 【人工填写:后端 HTTP 端口,默认 8080】 - -frontend: - pkg_name: 【人工填写:前端包名,如 acme-erp-web】 - dev_port: 【人工填写:前端开发服务器端口,默认 5173】 - -admin_init: - username: 【人工填写:超级管理员初始账号,如 admin】 - # 初始密码属敏感 → 见 .env.local 的 ADMIN_INIT_PASSWORD - -# 敏感值引用:真实值在 .env.local,此处只登记「键名 + 含义」,供 A2 skeleton-gen 核对 .env.local 是否齐全。 -# 按技术栈增删行(注释行表示可选,按需取消注释)。 -secrets_ref: - - DB_PASSWORD # 数据库密码 - - JWT_SECRET # JWT / 令牌签名密钥 - # - REDIS_PASSWORD # 缓存 / 会话(用 Redis 时) - # - ADMIN_INIT_PASSWORD # 超级管理员初始密码(有初始账号时) - # - OSS_ACCESS_KEY_SECRET / SMS_API_SECRET ... # 第三方凭证按需添加 diff --git a/skills/scope-lock/templates/req-card-template.md b/skills/scope-lock/templates/req-card-template.md deleted file mode 100644 index 1b88515..0000000 --- a/skills/scope-lock/templates/req-card-template.md +++ /dev/null @@ -1,44 +0,0 @@ -<!-- -req-card-template:单张 REQ 卡片骨架。每张卡片是 docs/01-需求清单/<module>/REQ-XXX-NNN.md 一个独立文件。 - -渲染约定: -1) scope-lock 渲染时替换 6 个占位符:{{req_id}} / {{title}} / {{goal}} / {{rules}} / {{constraints}} / {{acceptance}} - 这 6 项由 CC 根据 docs/01-需求清单/index.md 的「核心功能点」推断起草: - - req_id / title:从核心功能点拆分命名得来 - - goal:用一句话展开 title - - rules / constraints / acceptance:业务语义层面的合理起草,待人工审阅修订 -2) `**输入字段**` / `**输出字段**` 为**结构化字段表**:每个字段一行,6 列固定结构 - (字段名 | 类型 | 必填 | 校验规则 | 业务规则 | 示例值)。 - 模板内每张表给出一行示例行,列首注明 `【示例行,替换为真实字段】`。 - 人工拿到卡片后按本 REQ 实际业务**逐行替换为真实字段 / 增删行**: - - 字段名:本 REQ 真实的输入 / 输出字段 - - 类型:真实数据类型(文本 / 整数 / 金额 / 日期 / 布尔 / 枚举 / …) - - 必填:是 / 否 - - 校验规则:长度 / 格式 / 范围 / 唯一性等可验证约束(如「3-20 位字母数字下划线;系统内唯一」) - - 业务规则:该字段的业务含义 / 来源 / 默认值 / 联动逻辑 - - 示例值:一个真实约束下的合法取值 -3) **「示例值」列必须替换为真实约束下的取值。留模板默认占位(`【示例行,替换为真实字段】` 或 `<示例值>`)即视为该 REQ 卡片未完成,A1 终结校验会阻断进入下一阶段。** -4) `**依赖表**: TBD(A3 自动补)` 和 `**依赖接口**: TBD(A5 自动补)` 是后续 skill 自动回填的占位,渲染时**保持原样**,不要替换为 `-` 也不要替换为 `{{...}}` -5) 渲染后这段 HTML 注释要**剥掉**,不进入最终卡片(lib/render.mjs 自动剥离) ---> -### {{req_id}} {{title}} - -**目标**: {{goal}} - -**输入字段**: - -| 字段名 | 类型 | 必填 | 校验规则 | 业务规则 | 示例值 | -| --- | --- | --- | --- | --- | --- | -| 【示例行,替换为真实字段】 | 文本 | 是 | 3-20 位字母数字下划线;系统内唯一 | 用户登录账号,系统内唯一标识 | <示例值> | - -**输出字段**: - -| 字段名 | 类型 | 必填 | 校验规则 | 业务规则 | 示例值 | -| --- | --- | --- | --- | --- | --- | -| 【示例行,替换为真实字段】 | 整数 | 是 | 大于 0 | 新建记录的主键 id | <示例值> | - -- **跨字段规则**: {{rules}} -- **边界**: {{constraints}} -- **验收**: {{acceptance}} -- **依赖表**: TBD(A3 自动补) -- **依赖接口**: TBD(A5 自动补) diff --git a/skills/skeleton-gen/SKILL.md b/skills/skeleton-gen/SKILL.md deleted file mode 100644 index c953d05..0000000 --- a/skills/skeleton-gen/SKILL.md +++ /dev/null @@ -1,160 +0,0 @@ ---- -name: skeleton-gen -description: A2 骨架生成——基于 docs/04 § 零 技术栈 + docs/01-需求清单/index.md 模块索引,生成项目专属的架构文档(docs/04 § 一+、docs/06、docs/07、docs/09)和工具脚本(.mjs,跨平台)。固定工具文件用 Read/Write 落盘,架构文档由 LLM 按大纲生成。 -user-invocable: false -allowed-tools: Read Write Edit Skill Grep Glob AskUserQuestion Bash(node *) ---- - -**所有输出必须使用中文。** - -# skeleton-gen - -## 执行步骤 - -### A. 读取锁定的输入 - -用 `Read` 读取: -- `docs/04-技术规范.md` § 零 技术栈表 -- `docs/01-需求清单/index.md` 需求索引 -- `docs/01-需求清单/` 需求卡片 - -后续所有内容都基于它们推导。 - -### B.1 生成 3 个全新架构文档(docs/06 / 07 / 09) - -对下表每个目标文件: -1. 读取对应的大纲模板 -2. 基于步骤 A 的输入,按大纲生成项目专属内容 -3. 剥掉 HTML 注释(注释是给 LLM 的提示,不应出现在最终文档里) -4. 写入目标路径 - -| 目标文件 | 大纲模板 | -|---|---| -| `docs/06-UI交互规范.md`(§ 一 ~ 三;FE 决策表由 A6 frontend-scope-lock 追加到 § 三之后) | `${CLAUDE_SKILL_DIR}/templates/docs-06-static-template.md` | -| `docs/07-环境配置.md` | `${CLAUDE_SKILL_DIR}/templates/docs-07-env-template.md` | -| `docs/09-项目目录结构.md` | `${CLAUDE_SKILL_DIR}/templates/docs-09-structure-template.md` | - -> **docs/07 只记规则,不记具体配置值**:端口 / 包名 / 库名 / 初始账号等真实值在 `config-vars.yaml`(A1 scope-lock 已锁)与 `.env.local`(敏感)里,docs/07 只写命名约定、端口约定、安全规则,并指向这两个文件。 - -项目专属标识(根包名 / 命名空间)保留 `【人工填写:<说明>】` 占位,等人工在 docs/09 顶部补填一次后,其他文件复用。 - -### B.2 追加 docs/04 § 一+(保留 § 零 不覆盖) - -docs/04 已由 scope-lock 写入 § 零。本步骤追加 § 一 ~ 三。 - -1. 读取 `docs/04-技术规范.md`(现有 § 零 完整内容)。 -2. 读取 `${CLAUDE_SKILL_DIR}/templates/docs-04-skeleton-template.md`。 -3. 基于技术栈,按大纲生成 § 一 ~ 三 的项目专属内容,剥掉 HTML 注释。 -4. 拼接原有内容和新生成内容,写回 `docs/04-技术规范.md`。 - -完成后,用 `Edit` 在 `docs/08-模块任务管理.md` 中勾选: -- ` - [ ] 架构文档已生成(docs/04 § 一+、docs/06、docs/07、docs/09)` - -### C. 生成工具脚本 - -#### C.1 复制固定模板文件(用 Read + Write,跨平台无 shell) - -对下表每个文件:用 `Read` 读模板内容,用 `Write` **原样**写到目标路径(`Write` 会自动创建缺失的父目录,无需 `mkdir`)。`.gitkeep` 用 `Write` 写空文件。 - -| 模板 | 目标路径 | -|---|---| -| `${CLAUDE_SKILL_DIR}/templates/env-local-template` | `.env.local` | -| `${CLAUDE_SKILL_DIR}/templates/scripts-setup-test-db-template.mjs` | `scripts/setup-test-db.mjs` | -| `${CLAUDE_SKILL_DIR}/templates/styles-tokens-template.css` | `src/styles/tokens.css` | -| (空文件) | `sql/migrations/.gitkeep` | - -> **`.env.local` 须与 `config-vars.yaml` 的 `secrets_ref` 对齐**:写完 `.env.local` 后用 `Read` 读仓库根 `config-vars.yaml` 的 `secrets_ref` 列表,逐个核对键名。env-local-template 已含 `DB_*` / `JWT_SECRET`;`secrets_ref` 里其余项目专属键(如 `REDIS_PASSWORD` / `ADMIN_INIT_PASSWORD` / 第三方凭证)用 `Edit` 追加到 `.env.local`,值统一为 `【人工填写:<说明>】`。 - -#### C.2 渲染 scripts/test.mjs - -用 `Read` 读取 `${CLAUDE_SKILL_DIR}/templates/scripts-test-template.mjs`,基于步骤 A 的技术栈(docs/04 § 零)为 7 个占位推断命令后用 `Write` 写到 `scripts/test.mjs`: - -- `{{backend_build}}` / `{{backend_lint}}` / `{{backend_test}}` 后端各 stage 命令 -- `{{frontend_build}}` / `{{frontend_lint}}` / `{{frontend_test}}` 前端各 stage 命令 -- `{{e2e_cmd}}` E2E(无 E2E 工具则填 `echo "[test.mjs] e2e 略"`) - -> 占位是普通 shell 命令字符串,模板在运行期用 `spawnSync(cmd, { shell:true })` 跨平台执行(Windows 走 cmd.exe,*nix 走 /bin/sh),缺席 stack 由模板内的 `existsSync('backend')` / `existsSync('frontend')` 守卫跳过。 -> 推断规则:根据 `docs/04 § 零` 。 -> - 「后端*」存在 → 据后端技术栈推 backend 三槽(build / lint / test 命令) -> - 「前端*」存在 → 据前端技术栈推 frontend 三槽 -> - 缺席 stack → 三槽全填 `echo skip`(该 stack 目录不存在时模板不会执行,但占位须为合法命令) -> - `{{e2e_cmd}}` 通常仅前端,按上述前端规则或填 `echo "[test.mjs] e2e 略"` -> -> 表结构异常(列名变更 / 无中文前缀)时停下,用 `AskUserQuestion` 让用户显式确认每 stack 命令。 - -> 注:生成的 `scripts/*.mjs` 由 `node` 直接执行,**无需 `chmod +x`**(跨平台无文件权限位概念)。 - -完成后,用 `Edit` 在 `docs/08-模块任务管理.md` 中勾选: -- ` - [ ] 工具脚本已生成(scripts/*.mjs、.env.local)` -- ` - [ ] 样式 token 骨架已生成(src/styles/tokens.css)` - -### D. 追加 .gitignore 忽略项 - -调 `${CLAUDE_PLUGIN_ROOT}/lib/merge-gitignore.mjs`(跨平台纯 Node,逐行判重并集合并,把 append 模板内容并入项目 `.gitignore`,原地写回第一个参数): - -```bash -node "${CLAUDE_PLUGIN_ROOT}/lib/merge-gitignore.mjs" .gitignore "${CLAUDE_SKILL_DIR}/templates/gitignore-append-template" -``` - -> `.gitignore` 不存在时先用 `Write` 建一个空文件再调用(`merge-gitignore.mjs` 的第一个参数须可读)。 - -完成后,用 `Edit` 在 `docs/08-模块任务管理.md` 中勾选: -- ` - [ ] .gitignore 已配置` - -### E. 占位符补填 + QA 闸门 - -#### E.1 扫描 + 分组 - -用 `Grep` 在以下路径扫 `【人工填写:`,记录命中(文件 / 行号 / 说明): -- `docs/04-技术规范.md` / `docs/06-UI交互规范.md` / `docs/07-环境配置.md` / `docs/09-项目目录结构.md` -- `config-vars.yaml`(A1 留下的未推断字段,如包名 / 端口) -- `scripts/*.mjs` / `.gitignore` -- `.env.local` - -分两组: -- **敏感组**:`.env.local` 路径命中(凭据 / 密钥)。**不弹 QA**(凭据不进会话),E.3 提示用户自填。 -- **非敏感组**:其余文件。按说明文字聚合为「根占位」(相同说明 = 同一值,多处共用)或「派生占位」(说明表达派生关系,如"后端 java 根包路径"派生自"根包名")。 - -无命中 → 跳 E.4。 - -#### E.2 问根占位 + 推派生 + 批量 Edit - -- 每个根占位用 `AskUserQuestion` 问(给合理默认值 + 自由输入),用 `Edit` 批量替换所有命中位置 -- 派生占位**不问**,CC 基于根占位值推断后 `Edit`;不能可靠推断则回退当独立根占位问 - -#### E.3 敏感占位提示(不弹 QA) - -若敏感组非空:打印提示横幅,列出 `.env.local` 待填字段名 + 告诉用户"直接编辑文件,凭据不进会话"。 - -#### E.4 验证 + QA 闸门 - -循环直到两条件**同时**满足: -(a) `Grep` 重新扫 E.1 全部路径,0 命中 -(b) 用户 `AskUserQuestion` 选「继续」 - -每次弹 QA 前重扫;有残留则打印残留位置清单(文件:行号 — 说明)+ 再弹 QA。 - -QA 横幅涵盖:产出文件清单(docs/04 / 06 / 07 / 09 + config-vars.yaml + scripts/*.mjs + .env.local + .gitignore)、占位状态(N=0 或待填清单)、「继续」/「有疑问先沟通」两选项。 - -通过后(N=0 且用户选「继续」),用 `Edit` 在 `docs/08-模块任务管理.md` 中勾选: -- `- [ ] A2 骨架生成 — skeleton-gen` - -### F. 进入 A3 - -输出 `skeleton-gen: 完成`,立即调用 `Skill(db-design-gen)`。 - -## 参考 - -- `docs/04-技术规范.md` § 零(技术栈输入) -- `docs/01-需求清单/index.md`(模块索引输入) -- `${CLAUDE_SKILL_DIR}/templates/docs-04-skeleton-template.md`(大纲) -- `${CLAUDE_SKILL_DIR}/templates/docs-06-static-template.md`(大纲) -- `${CLAUDE_SKILL_DIR}/templates/docs-07-env-template.md`(大纲) -- `${CLAUDE_SKILL_DIR}/templates/docs-09-structure-template.md`(大纲) -- `${CLAUDE_SKILL_DIR}/templates/scripts-test-template.mjs`(推断命令填充 7 槽:backend/frontend × build/lint/test + e2e;缺席 stack 填 `echo skip`) -- `${CLAUDE_SKILL_DIR}/templates/scripts-setup-test-db-template.mjs`(0 槽位,跨平台 .env.local 解析 + DROP/CREATE) -- `${CLAUDE_SKILL_DIR}/templates/env-local-template`(0 槽位;C.1 据 `config-vars.yaml` 的 `secrets_ref` 追加项目专属 secret 键) -- `config-vars.yaml`(A1 scope-lock 输出,仓库根;C.1 读其 `secrets_ref` 对齐 `.env.local`,E.1 扫其残留 `【人工填写:`) -- `${CLAUDE_SKILL_DIR}/templates/gitignore-append-template`(0 槽位) -- `${CLAUDE_SKILL_DIR}/templates/styles-tokens-template.css`(0 槽位,样式 token 骨架) -- `${CLAUDE_PLUGIN_ROOT}/lib/merge-gitignore.mjs`(.gitignore 逐行判重并集合并,跨平台纯 Node) diff --git a/skills/skeleton-gen/templates/docs-04-skeleton-template.md b/skills/skeleton-gen/templates/docs-04-skeleton-template.md deleted file mode 100644 index 7f2c116..0000000 --- a/skills/skeleton-gen/templates/docs-04-skeleton-template.md +++ /dev/null @@ -1,69 +0,0 @@ -<!-- -本文件是 docs/04-技术规范.md 的 § 一+ 大纲。 -skeleton-gen 读取 docs/04 § 零(技术栈表)和 docs/01-需求清单/index.md(模块索引), -按下述大纲生成本项目专属的规范内容。LLM 不要原样拷贝提示文字,只保留 section 标题。 ---> - -## 一、后端规范 - -### 1.1 规则 -<!-- 后端通用约定:保留下方占位符不要代填,由人工在 skeleton-gen § E 填写;每条一个 bullet,按需复制本行新增更多。 --> -- 【人工填写:一条后端通用约定,按需复制本行新增更多;无则填「无」】 - -### 1.2 分层结构 -<!-- 按 § 零 的后端框架定层次:controller/service/mapper 等;每层职责一句话。 --> - -### 1.3 命名约定 -<!-- 包名(根包用【人工填写:根包名】占位)/ 类名 / 方法名 / 常量的大小写规则,含 2 个示例。 --> - -### 1.4 统一响应格式 -<!-- 成功/失败的 JSON 结构,错误码段位划分。 --> - -### 1.5 异常处理 -<!-- 全局异常处理器的使用方式;哪些异常要 catch,哪些禁止;**接口响应禁止回显后端异常堆栈**(返用户友好错误码 + 文案)。 --> - -### 1.6 事务 -<!-- 事务边界(通常 service 层);跨服务调用的禁止/替代方案。 --> - -### 1.7 认证 -<!-- 基于 § 零 认证方案推导:token 生命周期、刷新机制、密钥管理。 --> - -## 二、前端规范 - -### 2.1 目录约定 -<!-- 基于 § 零 前端框架推导:api/components/pages/store/hooks/utils 的职责;**前端禁止直接写 SQL / 操作 DB**,所有数据访问走 api/ 层统一封装。 --> - -### 2.2 状态管理 -<!-- 基于 § 零 状态管理技术推导:全局 vs 局部、服务端数据的存放。 --> - -### 2.3 请求封装 -<!-- HTTP 客户端的拦截器、超时、错误重试、鉴权注入。 --> - -### 2.4 错误处理 -<!-- 网络错误 / 业务错误 / 页面级错误的分层处理。 --> - -### 2.5 样式与主题 -<!-- 基于 § 零 UI 库给出 CSS 变量约定: - - 命名格式 `--color-<scope>-<role>-<state>`(scope=form/table-row/...,role=bg/fg/border,state=edit/readonly/hover/selected) - - 文件位置 `src/styles/tokens.css`,由 skeleton-gen 生成空骨架,色值由 docs/06 § 四锁定后填入 - - 组件样式中只用 var(--color-xxx),禁止硬编码 hex/rgba - - 与 UI 库主题对接(如 Ant Design ConfigProvider.theme.token)的映射方式 - 具体 token 表见 docs/06 § 四。 --> - -## 三、共同约定 - -### 3.1 Git 提交 -`<type>(<scope>): <subject> REQ-XXX-NNN` - -### 3.2 分页查询 -<!-- 后端分页对象 + 前端分页组件,入参出参约定。 --> - -### 3.3 日期与金额 -<!-- 后端类型(如 LocalDateTime / BigDecimal)+ 前端展示工具;金额精度约定。 --> - -### 3.4 数据访问规约 -<!-- 基于 § 零 数据访问技术(MyBatis-Plus / JPA 等):SELECT 字段显式列举,**禁止 `SELECT *`**;循环中不得执行 DB 查询(**N+1 反模式**),改用批量查 / IN 子句 / JOIN;Mapper XML 里字段与表名用常量或引用,避免拼字符串。 --> - -### 3.5 配置与安全 -<!-- 配置:DB 连接 / 端口 / 密钥 / 第三方 URL 等一律放 `application.yml` + `.env.local`,代码里**禁止硬编码**。 - 前端安全:`localStorage` 不存敏感信息(token / 身份 / 个人数据),推荐 HttpOnly Cookie 或 内存 + 刷新 token 模式;接口响应禁止回显后端异常堆栈(与 § 1.5 一致)。 --> diff --git a/skills/skeleton-gen/templates/docs-06-static-template.md b/skills/skeleton-gen/templates/docs-06-static-template.md deleted file mode 100644 index 21dd358..0000000 --- a/skills/skeleton-gen/templates/docs-06-static-template.md +++ /dev/null @@ -1,42 +0,0 @@ -<!-- -本文件是 docs/06-UI交互规范.md 的 § 一 ~ 三 大纲(§ 三页面清单由 downstream-gen 按模块追加;FE 决策表由 A6 frontend-scope-lock 追加到 § 三之后)。 -skeleton-gen 读取 docs/04 § 零 和 docs/01 index,按下述大纲生成项目专属内容。 -布局/页面骨架以项目根的 prototype/ 静态 HTML mockup 为权威,本文件仅承载跨页面通用规则与 Design Tokens。 ---> - -# 06-UI交互规范 - -> 本项目所有页面布局以项目根 `prototype/` 目录下的静态 HTML mockup 为权威。前端阶段实现时直接以 prototype/ HTML 推导组件树与样式。本文件仅承载跨页面通用规则与 Design Tokens。 - -## 一、通用交互规则 - -### 1.1 操作反馈 -<!-- 成功/失败消息;危险操作二次确认;长耗时按钮 loading 态。 --> - -### 1.2 数据展示 -<!-- 空状态 / 加载 / 异常 的统一组件与文案。 --> - -### 1.3 权限控制(前端) -<!-- 菜单级 / 按钮级 / 路由级的控制方式,关联后端 RBAC。 --> - -## 二、Design Tokens - -<!-- 所有色值统一以 CSS 变量定义于 src/styles/tokens.css;命名规范见 docs/04 § 2.5。 --> - -### 2.1 全局调色板 -<!-- 与 § 零 UI 库主题对齐:列名 = 语义 / 变量名 / 默认值 / 用途。 - 至少含:主色/成功/警告/错误/主文字/次文字/边框/背景。 --> - -### 2.2 组件级状态色 -<!-- 场景 × 状态映射表:列名 = 序号 / 组件 / 编辑bg / 只读bg / 悬浮bg / 编辑fg / 只读fg / 悬浮fg / 备注。 - 单元格写 token 名(var(--color-xxx) 形式),不写 hex;"—" 表示该状态不适用。 - 表后追加「Token 默认值」表,列出每个 --color-xxx 在 tokens.css 的默认值。 --> - -### 2.3 引用约定 -<!-- 一句话三条: - - 组件样式只用 var(--color-xxx),禁止硬编码 - - 新增 token 须先登记到 § 2.1/2.2 再补 tokens.css - - 修改色值只改 tokens.css 一处,不允许组件覆盖 --> - -## 三、页面清单 -(由 `downstream-gen` 按模块追加段落) diff --git a/skills/skeleton-gen/templates/docs-07-env-template.md b/skills/skeleton-gen/templates/docs-07-env-template.md deleted file mode 100644 index bc246c9..0000000 --- a/skills/skeleton-gen/templates/docs-07-env-template.md +++ /dev/null @@ -1,34 +0,0 @@ -<!-- -本文件是 docs/07-环境配置.md 的大纲。 -docs/07 只记规则与约定,不记具体配置值——端口 / 包名 / 库名等真实值在 config-vars.yaml(A1 锁定)与 .env.local(敏感)。 -skeleton-gen 基于 docs/04 § 零 技术栈表推导各节内容: - § 一 依赖清单 → 从技术栈的每一行技术推导运行时和构建依赖 - § 二 端口约定 → 从后端/前端/数据库/缓存/反向代理 各取默认端口(约定值;项目实际采用值记在 config-vars.yaml) - § 四 常用命令 → 基于构建工具、包管理器给出开发者最常用命令 ---> - -# 07-环境配置 - -## 一、依赖清单 - -<!-- 表格:| 层 | 依赖 | 版本 | 说明 |;覆盖 运行时 / 构建 / 容器 / CLI 工具。 --> - -## 二、端口约定 - -<!-- 表格:| 服务 | 端口 | 说明 |;至少列 后端 HTTP / 前端 dev / 数据库 / 缓存 / 反代。这里给默认约定值;项目实际采用的端口记在 config-vars.yaml。 --> - -## 三、配置与凭据规则 - -项目配置分两处存放,**本文档只记规则、不记具体值**: - -- **非敏感、项目级配置**(根包名 / 命名空间、应用端口、前端包名、管理员初始账号等)→ 仓库根 `config-vars.yaml`,结构化 YAML,随项目提交。 -- **敏感凭据**(数据库密码、JWT / 签名密钥、Redis 密码、第三方 key/secret、管理员初始密码等)→ 仓库根 `.env.local`,入 `.gitignore`,**不提交**;`config-vars.yaml` 末尾 `secrets_ref` 只登记键名作引用。 - -规则: -- 根包名 / 命名空间一经在 `config-vars.yaml` 锁定,全项目复用,不得各模块各写。 -- 端口遵循 § 二 约定;调整时改 `config-vars.yaml`,本文档不写具体端口。 -- 任何敏感值不得出现在 `config-vars.yaml`、docs、源码或日志中——只允许出现在 `.env.local`。 - -## 四、常用命令 - -<!-- 表格:| 命令 | 说明 |;包含 启动后端 / 启动前端 / 打包 / 运行测试 / 重置测试数据。 --> diff --git a/skills/skeleton-gen/templates/docs-09-structure-template.md b/skills/skeleton-gen/templates/docs-09-structure-template.md deleted file mode 100644 index d913c08..0000000 --- a/skills/skeleton-gen/templates/docs-09-structure-template.md +++ /dev/null @@ -1,45 +0,0 @@ -<!-- -本文件是 docs/09-项目目录结构.md 的大纲。 -skeleton-gen 基于 docs/04 § 零 技术栈推导目录树: - § 二 后端目录 → 按后端框架的惯例(如 Spring Boot 的 src/main/java) - § 三 前端目录 → 按前端框架的惯例(如 Vite + React 的 src/) - § 四 docs 目录 → 沿用插件标准 - § 五 命名约定 → 按后端语言的包/命名空间习惯 - -模块划分参考 docs/01-需求清单/index.md 的模块索引,将业务模块落到代码目录。 ---> - -# 09-项目目录结构 - -## 一、仓库顶层 - -<!-- 用代码块画出顶层目录树,含 CLAUDE.md / README.md / .env.local / scripts / docs / sql / backend / frontend 等。 --> - -## 二、后端目录 - -<!-- 基于后端框架的目录树;按 docs/01 index 的模块代码把业务模块列出(module/user/、module/order/ 等)。 --> - -## 三、前端目录 - -<!-- 基于前端框架的目录树;pages/ 下按业务模块建子目录。 --> - -## 四、docs/ 结构 - -``` -docs/ -├── 01-需求清单/ # 每模块一子目录(_module.md 模块头 + REQ-*.md 卡片) -├── 02-开发计划.md -├── 03-数据库设计文档.md -├── 04-技术规范.md -├── 05-API接口契约.md -├── 06-UI交互规范.md -├── 07-环境配置.md -├── 08-模块任务管理.md -├── 09-项目目录结构.md -├── 10-验收检查清单.md -└── superpowers/ # CC 运行时产物 -``` - -## 五、命名与放置约定 - -<!-- 根包 / 命名空间用【人工填写:】占位;Controller / Service / Mapper / DTO / VO / 前端组件 / 前端页面 的放置规则。 --> diff --git a/skills/skeleton-gen/templates/env-local-template b/skills/skeleton-gen/templates/env-local-template deleted file mode 100644 index 43a3bd2..0000000 --- a/skills/skeleton-gen/templates/env-local-template +++ /dev/null @@ -1,25 +0,0 @@ -# .env.local — 本地开发凭据(入 .gitignore,不提交) -# -# 规则: -# 1. 值含 `$`、反引号、空格、`!` 等 shell 特殊字符时,必须用单引号包裹: -# DB_PASSWORD='p@ss$w0rd!' -# 否则 `set -a; . .env.local; set +a` 会做变量展开导致密码错乱。 -# 2. DB_HOST 建议保持 localhost / 127.0.0.1;非本地 host 默认会被 scripts/setup-test-db.mjs 防护拒绝。 -# 若必须用远程测试库,把 host 列入下方 TEST_DB_ALLOWED_HOSTS。 -# 3. DB_SCHEMA 建议命名含 test / _dev / _local / _ci,避免与生产库同名。 - -DB_HOST=【人工填写:MySQL host,推荐 localhost】 -DB_PORT=【人工填写:MySQL port,默认 3306】 -DB_USER=【人工填写:开发账号名】 -DB_PASSWORD=【人工填写:对应密码,含特殊字符时用单引号包裹】 -DB_SCHEMA=【人工填写:schema 名,推荐含 test/_dev/_local,例如 erp_dev】 -JWT_SECRET=【人工填写:JWT 签名密钥,256+ bit 随机串】 - -# 可选:额外允许 DROP CREATE 的远程 host(空格或逗号分隔)。仅当 DB_HOST 指向公司测试 MySQL 等 -# 非本地服务器时填写;留空表示只允许 localhost / 127.0.0.1 / ::1。 -# 示例:TEST_DB_ALLOWED_HOSTS="118.178.19.35 test-mysql.internal" -# -# ⚠️ 列入后该 host 每次 test.mjs 都会被 DROP CREATE(无二次确认)。 -# 仅用于你完全可控的测试库;生产/共享库/多人共享的 staging 库**千万别列**。 -# (防护 2 还会检查 schema 名须含 test/_dev/_local/_ci,独立兜底。) -TEST_DB_ALLOWED_HOSTS= diff --git a/skills/skeleton-gen/templates/gitignore-append-template b/skills/skeleton-gen/templates/gitignore-append-template deleted file mode 100644 index ac39aa6..0000000 --- a/skills/skeleton-gen/templates/gitignore-append-template +++ /dev/null @@ -1,32 +0,0 @@ -# ==== ERP 插件推荐忽略项(skeleton-gen 追加) ==== -# 本地运行时配置(含真实凭据,严禁入库) -.env.local -.env.*.local - -# Java / Maven -target/ -*.class - -# Node / 前端构建产物 -node_modules/ -dist/ -build/ -coverage/ - -# IDE -.idea/ -.vscode/ -*.iml - -# OS -.DS_Store -Thumbs.db - -# 日志 -*.log -logs/ - -# 插件运行时临时文件 -.tmp/ -*.raw -# ==== 结束 ==== diff --git a/skills/skeleton-gen/templates/scripts-setup-test-db-template.mjs b/skills/skeleton-gen/templates/scripts-setup-test-db-template.mjs deleted file mode 100644 index ec56d45..0000000 --- a/skills/skeleton-gen/templates/scripts-setup-test-db-template.mjs +++ /dev/null @@ -1,126 +0,0 @@ -#!/usr/bin/env node -// scripts/setup-test-db.mjs — 数据库重置脚本:drop + create 空库。 -// schema apply 由 Flyway 在 Spring Boot 启动时自动处理(见 docs/04 技术栈 + sql/migrations/V*.sql)。 -// seed 数据由测试框架负责(Spring @Sql / Flyway R__seed.sql / data.sql)。 -// -// 使用场景: -// - scripts/test.mjs 开头:清空库,让 Spring 启动时 Flyway 从 V1 开始重放所有 migration -// - scripts/test.mjs 结尾:清空库,避免测试遗留污染下次运行 -// - 手动调试时:reset 到零状态 -// -// 跨平台:用纯 JS 解析 .env.local(dotenv 风格,逐行 KEY=VALUE),**绝不** shell-source, -// 因此 mac / Windows 原生 node 均可运行,且消除 shell 注入 / 变量展开隐患。 -// DROP/CREATE 通过 `mysql` 客户端以 argv 数组方式执行(不经 shell),密码不进命令行解析层。 -// -// 防护:本脚本只允许在本地 host + 测试库名上执行;非预期目标会被拒绝, -// 避免 .env.local 误指向 staging/prod 时触发不可逆 DROP。 - -import { spawnSync } from 'node:child_process' -import { existsSync, readFileSync } from 'node:fs' -import { dirname, join } from 'node:path' -import { fileURLToPath } from 'node:url' - -const SCRIPT_DIR = dirname(fileURLToPath(import.meta.url)) -const ENV_FILE = join(SCRIPT_DIR, '..', '.env.local') - -// dotenv 风格解析:逐行 KEY=VALUE,跳过空行与 # 注释,去除两侧空白, -// 可选地剥离一层成对单/双引号。**不做**变量展开,特殊字符按字面保留。 -function parseEnv(text) { - const env = {} - for (const rawLine of text.split(/\r?\n/)) { - const line = rawLine.trim() - if (line === '' || line.startsWith('#')) continue - const eq = line.indexOf('=') - if (eq === -1) continue - const key = line.slice(0, eq).trim() - if (!key) continue - let value = line.slice(eq + 1).trim() - if ( - value.length >= 2 && - ((value.startsWith("'") && value.endsWith("'")) || - (value.startsWith('"') && value.endsWith('"'))) - ) { - value = value.slice(1, -1) - } - env[key] = value - } - return env -} - -if (!existsSync(ENV_FILE)) { - console.error(`[setup-test-db] .env.local 不存在(${ENV_FILE})`) - process.exit(1) -} - -const env = parseEnv(readFileSync(ENV_FILE, 'utf8')) - -const DB_HOST = env.DB_HOST ?? '' -const DB_PORT = env.DB_PORT ?? '3306' -const DB_USER = env.DB_USER ?? '' -const DB_PASSWORD = env.DB_PASSWORD ?? '' -const DB_SCHEMA = env.DB_SCHEMA ?? '' -const TEST_DB_ALLOW_REMOTE = env.TEST_DB_ALLOW_REMOTE ?? process.env.TEST_DB_ALLOW_REMOTE ?? '0' -const TEST_DB_ALLOW_PROD_NAME = - env.TEST_DB_ALLOW_PROD_NAME ?? process.env.TEST_DB_ALLOW_PROD_NAME ?? '0' - -// 防护 1:默认只允许本地 host(localhost / 127.0.0.1 / ::1)。 -// 额外允许的远程 host 在 .env.local 的 TEST_DB_ALLOWED_HOSTS 中(空格或逗号分隔)。 -const extraHosts = (env.TEST_DB_ALLOWED_HOSTS ?? '') - .split(/[\s,]+/) - .filter(Boolean) -const allowedHosts = ['localhost', '127.0.0.1', '::1', ...extraHosts] -if (!allowedHosts.includes(DB_HOST)) { - console.error(`[setup-test-db] 拒绝在非白名单 host (${DB_HOST}) 上执行 DROP DATABASE`) - console.error(` 当前白名单:${allowedHosts.join(' ')}`) - console.error(' 加入 host:在 .env.local 追加 TEST_DB_ALLOWED_HOSTS="<host1> <host2>"') - console.error(' 一次性绕过:在 .env.local 设 TEST_DB_ALLOW_REMOTE=1') - if (TEST_DB_ALLOW_REMOTE !== '1') process.exit(1) -} - -// 防护 2:schema 名需像测试/开发库(含 test / _dev / _local / _ci),否则要求显式确认。 -const schemaLooksLikeTest = - /test/.test(DB_SCHEMA) || /_dev$/.test(DB_SCHEMA) || /_local$/.test(DB_SCHEMA) || /_ci$/.test(DB_SCHEMA) -if (!schemaLooksLikeTest) { - console.error( - `[setup-test-db] schema '${DB_SCHEMA}' 不像测试库(期望命名含 test / _dev / _local / _ci)` - ) - console.error(' 如确为期望行为,请显式声明:在 .env.local 设 TEST_DB_ALLOW_PROD_NAME=1') - if (TEST_DB_ALLOW_PROD_NAME !== '1') process.exit(1) -} - -// 防护 3:显式 banner,让人看见自己在 drop 什么;远程 host 额外提示白名单内容。 -console.log(`[setup-test-db] 即将 DROP + CREATE \`${DB_SCHEMA}\` on ${DB_HOST}:${DB_PORT}`) -if (!['localhost', '127.0.0.1', '::1'].includes(DB_HOST)) { - console.log( - '[setup-test-db] 目标是 **远程** host(已在 TEST_DB_ALLOWED_HOSTS 白名单中,每次 test.mjs 都会 DROP)' - ) - console.log(`[setup-test-db] 当前白名单: ${allowedHosts.join(' ')}`) - console.log( - '[setup-test-db] 若不希望每次自动 DROP,从 .env.local 的 TEST_DB_ALLOWED_HOSTS 删掉此 host' - ) -} - -const sql = - `DROP DATABASE IF EXISTS \`${DB_SCHEMA}\`; ` + - `CREATE DATABASE \`${DB_SCHEMA}\` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;` - -// 以 argv 数组调用 mysql(不经 shell):密码不进 shell 解析,跨平台一致。 -const mysqlArgs = [ - `-h${DB_HOST}`, - `-P${DB_PORT}`, - `-u${DB_USER}`, - `-p${DB_PASSWORD}`, - '-e', - sql, -] -const res = spawnSync('mysql', mysqlArgs, { stdio: 'inherit' }) -if (res.error) { - console.error(`[setup-test-db] FATAL: 无法执行 mysql(请确认其在 PATH 中): ${res.error.message}`) - process.exit(1) -} -if (res.status !== 0) { - console.error(`[setup-test-db] FAIL: mysql exit=${res.status}`) - process.exit(res.status === null ? 1 : res.status) -} - -console.log('[setup-test-db] done — schema will be applied by Flyway when Spring Boot starts') diff --git a/skills/skeleton-gen/templates/scripts-test-template.mjs b/skills/skeleton-gen/templates/scripts-test-template.mjs deleted file mode 100644 index 9f0ab8c..0000000 --- a/skills/skeleton-gen/templates/scripts-test-template.mjs +++ /dev/null @@ -1,69 +0,0 @@ -#!/usr/bin/env node -// scripts/test.mjs —— 合并到默认分支(main / master)前的测试闸门。 -// 顺序:detect → setup-db → build → lint → unit+integration → e2e → reset-db -// 由 coding.mjs 的 test-gate stage(通过子会话)调用。 -// -// 跨平台:所有命令经 child_process.spawnSync(cmd, { shell:true }) 执行, -// 在 Windows 走 cmd.exe,在 *nix 走 /bin/sh,无需 WSL / Git-Bash。 -// 命令字符串来自 docs/04 §零(构建/lint/单测/e2e)——由 skeleton-gen 在 Plan 期填充。 - -import { spawnSync } from 'node:child_process' -import { existsSync } from 'node:fs' -import { dirname, join } from 'node:path' -import { fileURLToPath } from 'node:url' - -const PROJECT_ROOT = join(dirname(fileURLToPath(import.meta.url)), '..') - -// 在指定子目录下跑一条 shell 命令;非零退出码即终止整个闸门并透传该码。 -function run(label, command, cwd = PROJECT_ROOT) { - console.log(`[test.mjs] ${label}: ${command}`) - const res = spawnSync(command, { cwd, shell: true, stdio: 'inherit' }) - if (res.error) { - console.error(`[test.mjs] FATAL: 无法执行 (${label}): ${res.error.message}`) - process.exit(1) - } - if (res.status !== 0) { - console.error(`[test.mjs] FAIL (${label}) exit=${res.status}`) - process.exit(res.status === null ? 1 : res.status) - } -} - -// Stack detection (runtime, mode-agnostic) -const hasBackend = existsSync(join(PROJECT_ROOT, 'backend')) -const hasFrontend = existsSync(join(PROJECT_ROOT, 'frontend')) -if (!hasBackend && !hasFrontend) { - console.error('[test.mjs] FATAL: neither backend/ nor frontend/ exists') - process.exit(1) -} - -const backendDir = join(PROJECT_ROOT, 'backend') -const frontendDir = join(PROJECT_ROOT, 'frontend') - -console.log('[test.mjs] 1/6 setup test db') -run('setup-test-db', `node ${JSON.stringify(join('scripts', 'setup-test-db.mjs'))}`) - -console.log('[test.mjs] 2/6 build') -if (hasBackend) run('backend build', '{{backend_build}}', backendDir) -else console.log('[test.mjs] skip backend build') -if (hasFrontend) run('frontend build', '{{frontend_build}}', frontendDir) -else console.log('[test.mjs] skip frontend build') - -console.log('[test.mjs] 3/6 lint') -if (hasBackend) run('backend lint', '{{backend_lint}}', backendDir) -else console.log('[test.mjs] skip backend lint') -if (hasFrontend) run('frontend lint', '{{frontend_lint}}', frontendDir) -else console.log('[test.mjs] skip frontend lint') - -console.log('[test.mjs] 4/6 unit + integration') -if (hasBackend) run('backend test', '{{backend_test}}', backendDir) -else console.log('[test.mjs] skip backend test') -if (hasFrontend) run('frontend test', '{{frontend_test}}', frontendDir) -else console.log('[test.mjs] skip frontend test') - -console.log('[test.mjs] 5/6 E2E') -run('e2e', '{{e2e_cmd}}') - -console.log('[test.mjs] 6/6 reset test db') -run('reset-test-db', `node ${JSON.stringify(join('scripts', 'setup-test-db.mjs'))}`) - -console.log('[test.mjs] GREEN') diff --git a/skills/skeleton-gen/templates/styles-tokens-template.css b/skills/skeleton-gen/templates/styles-tokens-template.css deleted file mode 100644 index bc8a542..0000000 --- a/skills/skeleton-gen/templates/styles-tokens-template.css +++ /dev/null @@ -1,43 +0,0 @@ -/* - * src/styles/tokens.css — Design Tokens - * 命名规范见 docs/04-技术规范.md § 2.5 - * 色值锁定见 docs/06-UI交互规范.md § 四 - * - * 命名格式:--color-<scope>-<role>-<state> - * <scope> 组件域:form / table-row / table-header / ... - * <role> 作用:bg(背景)/ fg(前景/字体)/ border - * <state> 状态:edit / readonly / hover / selected(无状态时省略) - * - * 约束: - * - 组件样式中只用 var(--color-xxx),禁止硬编码 hex / rgba - * - 修改色值只改本文件,不允许在组件级覆盖 - * - 新增 token 须先登记到 docs/06 § 4.1 / 4.2,再补到此处 - */ - -:root { - /* === 1. 全局调色板(与 Ant Design 主题对齐) === */ - --color-primary: #1890ff; - --color-success: #52c41a; - --color-warning: #faad14; - --color-error: #ff4d4f; - --color-text: rgba(0, 0, 0, 0.85); - --color-text-secondary: rgba(0, 0, 0, 0.45); - --color-border: #d9d9d9; - --color-bg-base: #f0f2f5; - - /* === 2. 组件级状态色(与 docs/06 § 4.2 一一对应) === */ - - /* form:输入框 / 备注框 / 时间框 / 下拉框共用 */ - --color-form-bg-edit: #ffffff; - --color-form-bg-readonly: #f1f2f8; - --color-form-bg-hover: #f5f5f5; /* 仅下拉框使用 */ - --color-form-fg: #000000; - - /* table */ - --color-table-row-bg-selected: #86d5fb; - --color-table-row-bg-hover: #fff7e6; - --color-table-row-bg-readonly: #f1f2f8; /* = rgb(241, 242, 248) */ - --color-table-row-fg: #000000; - --color-table-header-bg: #f5f5f5; - --color-table-header-fg: rgba(0, 0, 0, 0.85); /* = #000000D9 */ -} -- libgit2 0.22.2