# erp-workflow Claude Code 插件:ERP / 后端管理系统全流程开发框架。 从零到 N 模块上线的 ERP 全流程开发框架:Plan 阶段交互、Coding 阶段静默 Workflow。 ## 这个插件做什么 ``` 📋 阶段 A:规划(一次性,交互式;入口 /erp-workflow:plan-start 派发 A0~A5 共 6 个 skill) A0 project-init → A1 scope-lock(结构化 REQ 卡片 + secrets/commands 锁) ↓ ⏸ 审阅 REQ → 重新运行 /plan-start ↓ A2 skeleton-gen → A3 db-design-gen(REQ → docs/03 + 回填依赖表,ERP 约定可确认) ↓ ⏸ 审阅 docs/03 → 重新运行 /plan-start ↓ A4 db-init(docs/03 → V1 migration → 自动 apply 到本地 MySQL) ↓ A5 downstream-gen(docs/02 / docs/05 / docs/08 § 三 FE 清单;prototype/ 门禁) ↓ ⛔ docs/05 + docs/02 评审闸(必须确认) ⛔ Plan 终结硬闸(全部前移闸门通过才放行) ↓ 用户显式 /erp-workflow:coding-start 🔁 阶段 B:编码(单个 Workflow 脚本 workflows/coding.mjs,全自动静默) coding-start(瘦入口 skill)校验 Plan 终结闸 → 启动 Workflow coding.mjs Router → 解析 docs/08 § 二/§ 三 + milestone/* / req-done/* git tag,列出待跑模块 │ ├─ B-后端(按模块循环,每模块一个里程碑 tag;功能链顺序 for-await,单工作树串行 commit) │ runBranchSetup(module-) ← JS 编排:detect default → wt clean → exists? → │ checkout/create → confirm HEAD(5 微 agent) │ → featureLoop(后端):spec → plan → tdd → verify → review(有界 5 轮修复, │ throw 自然冒泡到模块主循环 try → fail-fast) │ → testGate(backend) │ → Seed stage(testGate green 后:生成 sql/seed/NN__.sql 演示种子 │ + 冷起栈真跑验证:空库→Flyway→seed-demo-data.mjs 注入→按 -- expect: 行对账) │ → runCrossModule(JS 编排:diff → 分类 → 写日志) │ → reportPrompt(LLM 12 节叙述) │ → runMilestone(JS 编排:wt → default → 已合入? → merge → 字段当前值? │ → 写字段 → tag 已存在? → 打 tag → 报告 § ⑫ 当前值? → 替换占位; │ 10+ 微 agent,全部跳过/分支条件由 JS 判定,幂等) │ └─ B-前端(后端全部打里程碑后,整体 1 个里程碑 tag) runBranchSetup(frontend-phase) → 前端骨架占位阶段(router 全量 lazy 路由表 + FeStub 占位,保证中途任意时刻可构建可起; 含 e2e 基线脚手架:Playwright globalSetup 按注入时序注种子 + admin 登录 storageState; 含单测基线:vitest include 限定 tests/**/*.test.*——单测一律 frontend/tests/ 镜像 src/, 交付源码 frontend/src/ 内禁测试文件,同后端 src/main↔src/test 物理分离) → featureLoop(前端,FE-NN,路径限 frontend/):spec → plan → tdd → verify → review 循环(静态验收,approve 即打 req-done/) → 阶段级行为门 behavior(整个前端阶段只跑一次:起全栈+演示种子+sentinel, 按全部 FE spec 聚合的作用域并集枚举路由,交互/文字/样式三层断言;交互失效 /sentinel 错/样式违规(非 token 色、横向溢出、控件重叠等)转可 fix must-fix →fix→单测复验→重跑门(≤3 轮),软文字按来源仲裁,green 才放行) → testGate(frontend,全量回归 vitest+playwright,兜底行为 fix 引入的回归) → runMilestone(milestone/frontend-phase) 子代理无法弹窗 → 缺值即写阻塞点并 halt(终止态,非对话框);fail-fast 后等人工修复重跑 coding-start ``` ## 首次使用 1. **进入空项目目录并启动 Claude Code**: ```bash mkdir my-erp && cd my-erp claude --plugin-dir /path/to/erp-workflow-plugin ``` 2. **Plan 阶段入口**(一次性规划): ``` /erp-workflow:plan-start ``` Plan 阶段**两段式**执行,中间有一个人工审阅断点(docs/03 数据库 schema): - **第一段(首次运行)**:执行 **A0 → A1 → A2 → A3**(创建骨架 / 锁技术栈 / 填需求 / 生成 REQ 卡片 / 生成项目骨架 / 从 REQ 正向设计 `docs/03-数据库设计文档.md` 并回填 REQ 依赖表)后**停下**,等你审阅 docs/03 的表 / 字段 / 索引 / 语义引用关系(人工关口:数据库 schema —— A4 会基于它翻译 DDL 并 apply 到 MySQL)。A1 的 REQ 卡片由 CC 据 index.md 填 6 个占位、字段表按模板原样复制,**不再单独停下审阅** - **第二段(docs/03 审阅完重新运行)**:执行 **A4 → A5**(解析 docs/03 → 生成 V1 migration → 自动 `DROP+CREATE` 本地 schema 并 apply → 生成下游文档 → **docs/05 + docs/02 评审闸** → prototype/ 门禁 + 推导 FE 清单写 docs/08 § 三),通过 **Plan 终结硬闸** 后再次**停下**(前端布局/交互以 `prototype/` 为权威,不另设 UI 规范文档) Plan 完成后不会自动进入编码,需手动 /erp-workflow:coding-start。 3. **Coding 阶段入口**(单个 Workflow,后端模块循环 → 前端整体阶段,全自动静默): ``` /erp-workflow:coding-start ``` Plan 全部完成后由你显式触发;详细职责见下方 Skill 清单。详细流程见上方阶段 B 流程图。 4. **中途恢复**:任何时候重跑 `/erp-workflow:coding-start`——`coding.mjs` 的 Router 根据 docs/08 § 二/§ 三 里程碑字段 + 本地 `milestone/*` / `req-done/*` tag 跳到当前该做的模块/阶段。 ## 目录结构 ``` erp-workflow-plugin/ ├── .claude-plugin/ │ └── plugin.json # 插件清单,显式列出 8 个 skill 路径 ├── README.md # 本文档 ├── workflows/ │ └── coding.mjs # 阶段 B:整个编码阶段编排为单个静默 Workflow ├── lib/ # 跨平台 Node 助手(ESM,node:test 单测) │ ├── validate-ddl.mjs # docs/03 ↔ DDL 4 维校验(替代 validate.sh) │ ├── yaml-config.mjs # config-vars.yaml 极简 YAML 读取(2 层 map + 标量) │ ├── apply-ddl.mjs # 解析 config-vars.yaml database: 段 + mysql2 apply │ └── *.test.mjs # 各助手的 node:test 单测 ├── agents/ │ └── code-reviewer.md # 统一 reviewer(coding.mjs review stage 调用,phase 选维度集) └── skills/ # 按阶段分组(slug 不变,由 SKILL.md frontmatter name 决定) ├── plan/ # 阶段 A:7 个 skill(入口 + A0~A5) │ ├── plan-start/ # A 阶段入口 + Plan 终结硬闸 │ ├── project-init/ # A0 │ ├── scope-lock/ # A1 │ ├── skeleton-gen/ # A2 │ ├── db-design-gen/ # A3 │ ├── db-init/ # A4 │ └── downstream-gen/ # A5(含前端 FE 清单推导,原 A6 已并入) └── coding/ # 阶段 B:1 个 skill(瘦入口) └── coding-start/ # 启动 workflows/coding.mjs ``` ## Skill 清单(8 个) ### 入口(2 个) | Skill | 作用 | 谁调用 | |---|---|---| | `plan-start` | **A 阶段入口 + Plan 终结硬闸**。读 docs/08 § 一 找第一个未勾 A 子项 → 派发对应 A skill;A 全部完成时校验 4 项前移闸门(REQ 真实数据、`config-vars.yaml` 全部配置(含 DB 凭据 / 密钥)全锁、docs/04 § 零 命令齐、docs/05+02 已评审),全过才提示运行 `/erp-workflow:coding-start`,否则指出缺口不放行 | **用户手动** `/erp-workflow:plan-start` | | `coding-start` | **B 阶段瘦入口**(`allowed-tools: Read Glob Workflow Bash(git ...)`)。校验 Plan 完成态(docs/08 § 一 全勾)+ 取得 projectRoot(git 就绪由 coding.mjs runBranchSetup 在运行时把守)→ 读 docs/08 § 二/§ 三 + `git tag -l 'milestone/*'` 概述阶段进度(Workflow Router 再用 `req-done/*` 判定功能级 resume)→ 调用 `Workflow({scriptPath:"${CLAUDE_PLUGIN_ROOT}/workflows/coding.mjs", args:{projectRoot}})` 启动整个编码阶段 → 告知"已在后台启动" | **用户手动** `/erp-workflow:coding-start` | ### Plan 阶段 A skill(A0~A5,共 6 个) | # | Skill | 作用 | 流程中谁调用 | |---|---|---|---| | A0 | `project-init` | • **依赖检查**:检测 git / mysql / node 是否在 PATH,缺失则按 OS 自动安装,装不上再停下提示用户
• 空目录初始化:用 Read/Write/Glob 工具拷模板创建 CLAUDE.md / docs/01/index.md / docs/08
• `git init` | `plan-start` | | A1 | `scope-lock` | • 引导填项目概述 / 技术栈 / 需求索引
• 按 `docs/01-需求清单//{_module.md, .md}` 子目录结构生成 REQ 卡片(req_id = `<模块代码>-<子模块代码>-<功能名>`,如 `USR-UserInfo-Login`;CC 据 index.md 填 `{{req_id/title/goal/rules/constraints/acceptance}}` 6 个占位,模板其余内容含输入/输出示例字段表原样复制)
• **A1 终结校验**:REQ 6 个占位均填真实数据、无 `{{` 残留、`config-vars.yaml` **全部配置**(包名 / 端口 / 初始账号 + DB 凭据 / 密钥占位)已锁、各 stack 的 build/lint/unit/e2e 命令写入 docs/04 § 零;缺失则在此(Plan 期)用 `AskUserQuestion` 问清(敏感凭据由用户自填,不进会话)
• 据模板直接 `Write` 生成 `_module.md` / `.md`
• 终结校验通过后**自动**调用 `Skill(skeleton-gen)` 进入 A2(不停下) | A0 | | A2 | `skeleton-gen` | • 生成架构文档:docs/04 § 一+
• 生成跨平台工具脚本:`scripts/*.mjs`(**无 chmod**;凭据 / 配置统一在 A1 产出的 config-vars.yaml)
• 据 `gitignore-append-template` 用 Read/Write 并入项目 .gitignore | `plan-start` | | A3 | `db-design-gen` | • 套用固定 ERP 约定(列前缀 `i/s/t/b/d`、`iIncrement` 主键、`sBrandsId`/`sSubsidiaryId` 租户列)+ 每表自动补标准列(11 列基础:`iIncrement`/`sId`/`sBrandsId`/`sSubsidiaryId`/`sMakePerson`/`tCreateDate`/`tUpdateDate`/`iOrder`/`bInvalid`/`sFormId`/`sMemo`;主表额外加 4 审核列 `bCheck`/`tCheckDate`/`sCheckPerson`/`sStatus`(共 15 列),从表额外加 `sParentId` 紧随 `sId`(共 12 列);其中 `sId`/`sBrandsId`/`sSubsidiaryId`/`sMakePerson`/`sCheckPerson` 为 varchar(50) NOT NULL)从 docs/01 REQ 卡片正向设计 `docs/03-数据库设计文档.md`(schema SSoT)
• 回填 REQ 卡片依赖表(`TBD(A3 自动补)` → 实际表名)
• **停下**等人工审阅 docs/03,审阅完毕用 `/plan-start` 续进 A4 | A2 | | A4 | `db-init` | • LLM 解析 docs/03 → `sql/migrations/V1__initial_schema.sql`(DDL only)
• `node ${CLAUDE_PLUGIN_ROOT}/lib/validate-ddl.mjs` 校验 DDL ↔ docs/03(4 维:表/列名/列类型/索引),fail-closed
• `node ${CLAUDE_PLUGIN_ROOT}/lib/apply-ddl.mjs config-vars.yaml V1.sql`(读取 config-vars.yaml database: 段 + mysql2 apply) | A3 | | A5 | `downstream-gen` | • 一次性生成 docs/02 / docs/05
• 回填 REQ 卡片依赖接口(`TBD(A5 自动补)` → 实际 endpoint)
• 追加模块清单到 docs/08 § 二
• **docs/05 + docs/02 评审闸**:用 `AskUserQuestion` 让用户确认 API 端点/字段无误 + 构建顺序可接受,未确认不勾 A5
• **prototype/ 门禁 + 推导 FE 清单写 docs/08 § 三**(原 A6 已并入;无 prototype 则问「无前端」→ § 三 留空)
• 最终占位符 + 结构残留扫描 | A4 | ### Coding 阶段(1 个 Workflow,非 skill) 整个编码阶段不再是 skill 链,而是单个 Workflow 脚本 **`workflows/coding.mjs`**(由瘦入口 skill `coding-start` 启动)。子代理无法弹窗 → 缺值即写阻塞点并 halt(结构性静默)。完整流程见本文档顶部「阶段 B:编码」流程图。 ## Agent 清单(1 个) | Agent | 用途 | 谁调用 | |---|---|---| | `code-reviewer` | 统一 reviewer。`phase=backend` 跑通用代码审查维度;`phase=frontend` 附加前端 8 维 checklist(prototype 一致性 / design tokens / a11y / 响应式 / 业务校验前端复刻 / API 一致性 / 状态机覆盖 / 测试文件隔离,主观维度仅标记明显问题不触发 request-changes)。非交互,返回结构化 verdict,绝不弹窗 | `workflows/coding.mjs` 的 review stage:`agent(..., {agentType:'erp-workflow:code-reviewer'})`(必须带 `erp-workflow:` 插件命名空间——裸 `code-reviewer` 会与其它插件的同名 agent 歧义) | ## Templates 清单(19 份) | 所属 Skill | 模板文件 | 用途 | |---|---|---| | project-init | `CLAUDE-template.md` | 项目根的 CLAUDE.md(ERP 专属编码约束 + Schema 演化 + Git 提交规范) | | project-init | `docs-01-index-template.md` | 需求清单索引骨架,等用户填子模块索引表(五列,一行一个子模块) | | project-init | `docs-04-stack-template.md` | docs/04 § 零 默认技术栈总览(零槽位,拷即可) | | project-init | `docs-08-initial-template.md` | 工作流进度文件骨架(Plan A0~A5 checkbox) | | scope-lock | `req-card-template.md` | 单张 REQ 卡片模板(文件名 == req_id `<模块代码>-<子模块代码>-<功能名>`;`{{req_id/title/goal/rules/constraints/acceptance}}` 占位 + 输入/输出示例字段表;A1 原样复制,只填这 6 个占位) | | scope-lock | `_module-template.md` | 模块子目录的 `_module.md` 模块头(模块代码-名 / 简述 / 依赖模块 TBD / 涉及表 TBD) | | scope-lock | `config-vars-template.yaml` | 仓库根 `config-vars.yaml` 骨架(跨栈中立):项目**全部配置**——非敏感(包名/端口/前端包名/初始账号)+ 敏感凭据(database / admin_init.password / secrets);A1 E.2 锁定,随项目提交 | | skeleton-gen | `docs-04-skeleton-template.md` | docs/04 § 一+ 编码规范大纲(HTML 注释引导 LLM) | | skeleton-gen | `scripts-setup-test-db-template.mjs` | 跨平台 drop + create 空库脚本(内联极简 YAML 读 config-vars.yaml database: 段);schema apply 交给 Flyway | | skeleton-gen | `scripts-seed-demo-data-template.mjs` | 演示种子注入脚本(schema 建好后按 `sql/seed/__.sql` 文件名升序幂等注入;`_demo_seed_history` 账本表记已应用文件跳过;同走 mysql;调用方 = 前端 e2e globalSetup / 行为门 / 里程碑后人工验收) | | skeleton-gen | `scripts-test-template.mjs` | test.mjs 骨架(命令槽位按后端/前端/build/lint/test/e2e 分开,`spawnSync(shell:true)` 跨平台执行) | | skeleton-gen | `gitignore-append-template` | 插件推荐忽略项(`.tmp/`、构建产物等;config-vars.yaml 随项目提交,不忽略) | | skeleton-gen | `styles-tokens-template.css` | 前端 design tokens CSS 变量骨架 | | db-design-gen | `docs-03-header-template.md` | docs/03 数据库设计头部 | | db-design-gen | `docs-03-table-template.md` | docs/03 单表小节模板 | | downstream-gen | `docs-02-template.md` | docs/02 开发计划 | | downstream-gen | `docs-05-header-template.md` | docs/05 API 契约头部 | | downstream-gen | `docs-05-endpoint-template.md` | docs/05 单接口小节 | | downstream-gen | `docs-08-module-row-template.md` | docs/08 § 二 单模块 bullet 行 | ## 前置依赖 - **Node.js ≥ 18**:`lib/*.mjs` 助手 + 生成进目标项目的 `scripts/*.mjs` 为 Node ESM;`workflows/coding.mjs` 是 Claude Workflow 运行时脚本(由 `Workflow` 工具执行,不作为普通 `node` CLI 入口)。A0 `project-init` 检测 git / mysql / node 在 PATH,缺失则按 OS 自动安装,装不上再停下提示用户 - **MySQL 8.x** 实例已就绪(host / 库名 / 凭据取自 `config-vars.yaml` 的 `database:` 段,由你填写并完全信任;本项目只面向开发/沙盒环境,`setup-test-db.mjs` 会按该值 DROP+CREATE)。生成的 `scripts/seed-demo-data.mjs`(演示种子注入)同走 `mysql` CLI、同读该 `database:` 段,故 `mysql` 客户端须在 PATH - **`mysql2`(目标项目侧)**:A4 `db-init` 经 `lib/apply-ddl.mjs` 用 mysql2 连接 + 解析 config-vars.yaml `database:` 段 apply V1;生成的 `scripts/setup-test-db.mjs` 在测试闸门前后 drop+create 空库 - **Spring Boot + Flyway**(**必需**):build.gradle 声明 `flyway-core` + `flyway-mysql`;Spring 启动时自动 apply `sql/migrations/V*.sql`。本插件生成的 `setup-test-db.mjs` 只清库,schema 必须由 Flyway 应用 - **本地 git 仓库**(纯本地,无需远程):A0 `project-init` 执行 `git init`;B 阶段每模块由 `coding.mjs` 的 milestone stage 本地 `git merge --no-ff` 进默认分支并 `git tag -a milestone/`,完成信号由 `git tag -l` 判定。**不依赖任何远程仓库 / push / GitLab** - **本地可运行 `./gradlew test` / `pnpm test`**:测试命令由 A1 写入 docs/04 § 零,生成的 `scripts/test.mjs` 由 `skeleton-gen` 产出,`coding.mjs` 的 testGate stage 调用 ## 设计原则 参见 `skills/plan/project-init/templates/CLAUDE-template.md` 的「📐 编码行为约束」。