README.md
22.8 KB
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)
│ · 调度:LLM 只输出模块间依赖边(fk/api/seed/order…,宁串勿并、证据可查),
│ JS 做确定性拓扑波次(Kahn);同波次 ≥2 模块才启用并行机器,宽 1 波次走现行主根路径
│ · lane 隔离:并行模块各占 lane worktree(独立 index,commit 不争锁)+ lane 测试库
│ (ERP_TEST_DB_SCHEMA 打穿到 Spring)+ 专属 migration 版本段(版本号只保唯一、
│ 不保连续不保合并序,Flyway 须 out-of-order: true);milestone/RESUME 与起栈类 stage 全局互斥
│ · 降级:任何并行机制失败(调度违例/环/lane DB 不支持/worktree 建失败)一律 fail-open
│ 回现行串行路径,绝不因并行机制 halt;args.parallel 缺省或 modules:false 即全串行
│ runBranchSetup(module-<id>) ← 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__<module>.sql 演示种子
│ + 冷起栈真跑验证:复制源库→副本→Flyway apply 新迁移→seed-demo-data.mjs 注入
│ →按 -- expect: 行对账→drop-test-db.mjs 删副本)
│ → runCrossModule(JS 编排:diff → 分类 → 写日志)
│ → reportPrompt(LLM 12 节叙述)
│ → runMilestone(JS 编排:wt → default → 已合入? → merge → 字段当前值?
│ → 写字段 → tag 已存在? → 打 tag → 报告 § ⑫ 当前值? → 替换占位;
│ 10+ 微 agent,全部跳过/分支条件由 JS 判定,幂等)
│
└─ B-前端(后端全部打里程碑后,整体 1 个里程碑 tag)
runBranchSetup(frontend-phase)
→ 静态原型渲染门 preview(前端段开头:Playwright headless 逐页渲染 prototype/**/*.html 本身
→ 截图归档为可视化基线 + 跑原型自带交互点击冒烟 + 捕获 JS/console 错误。与行为门正交——
前者测静态原型、后者测实现。硬门:原型渲染失败 / 脚本未捕获异常(jsErrors)→仲裁(只许 retry/halt),
halt 即停下等人工回 plan/add-req 修原型后重跑(coding 不改原型源码);console.error 仅 advisory;
唯环境未就绪(Playwright/浏览器缺失)才 retry→仲裁降级。无 prototype/ 则跳过)
→ 前端骨架占位阶段(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/<FE>)
→ 阶段级行为门 behavior(整个前端阶段只跑一次:起全栈+演示种子+sentinel,
按全部 FE spec 聚合的作用域并集枚举路由,交互/文字/样式三层断言;交互失效
/sentinel 错/样式违规(非 token 色、横向溢出、控件重叠等)转可 fix must-fix
→fix→单测复验→重跑门(≤3 轮),软文字按来源仲裁,green 才放行)
→ testGate(frontend,全量回归 vitest+playwright,兜底行为 fix 引入的回归)
→ runMilestone(milestone/frontend-phase)
· 前端 jsdom-only 重叠(可选,parallel.frontendOverlap,缺省关):前端**不依赖后端**的部分
(骨架 + spec/plan + tdd 的 jsdom 任务 + vitest verify)在独立前端 worktree 与后端波次**并发**,
打中间 tag fe-code-done/<FE>;后端全部 done 后 reconcile(合 default→frontend-phase)+ phase2
(e2e 任务 + review + req-done + 行为门 + 测试闸 + 里程碑,主根全栈)。重叠期前端无栈/无固定
端口/无 DB,端口与 lane 不变量全保住;缺省关 / phase1 失败 / 后端未全 done 回退现行终波路径。
设计:docs/superpowers/plans/2026-06-15-frontend-overlap-jsdom.md
子代理无法弹窗 → 缺值即写阻塞点并 halt(终止态,非对话框);fail-fast 后等人工修复重跑 coding-start
续跑 handoff:主循环结束(halt 或全完成)时 best-effort 追加 docs/superpowers/RESUME.md
(上次 halt 原因 + 本次自主默认假设 + 待跑模块),供下次 coding-start 步骤 3.5 复盘;
进度真值仍是 git tag,RESUME.md 仅定向,写失败绝不阻断主流程
首次使用
-
进入空项目目录并启动 Claude Code:
mkdir my-erp && cd my-erp claude --plugin-dir /path/to/erp-workflow-plugin -
Plan 阶段入口(一次性规划):
/erp-workflow:plan-startPlan 阶段两段式执行,中间有一个人工审阅断点(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 →
bootstrap-source-flyway把源库建立成 Flyway 托管态(建库 + apply V1 + 写 flyway 历史;已托管则幂等跳过)→ 生成下游文档 → docs/05 + docs/02 评审闸 → prototype/ 门禁 + 推导 FE 清单写 docs/08 § 三),通过 Plan 终结硬闸 后再次停下(前端布局/交互以prototype/为权威,不另设 UI 规范文档)
Plan 完成后不会自动进入编码,需手动 /erp-workflow:coding-start。
-
Coding 阶段入口(单个 Workflow,后端模块循环 → 前端整体阶段,全自动静默):
/erp-workflow:coding-startPlan 全部完成后由你显式触发;详细职责见下方 Skill 清单。详细流程见上方阶段 B 流程图。
中途恢复:任何时候重跑
/erp-workflow:coding-start——coding.mjs的 Router 根据 docs/08 § 二/§ 三 里程碑字段 + 本地milestone/*/req-done/*tag 跳到当前该做的模块/阶段。
目录结构
erp-workflow-plugin/
├── .claude-plugin/
│ └── plugin.json # 插件清单,显式列出 10 个 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
│ ├── req-ledger.mjs # 需求台账:docs/01 REQ + docs/08 §三 FE + prototype/ 原型快照 内容哈希,scan/commit 识别新增/变更(add-req 用)
│ └── *.test.mjs # 各助手的 node:test 单测
├── agents/
│ └── code-reviewer.md # 统一 reviewer(coding.mjs review stage 调用,phase 选维度集)
└── skills/ # 按阶段分组(slug 不变,由 SKILL.md frontmatter name 决定)
├── plan/ # 阶段 A:9 个 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 已并入)
│ ├── add-req/ # 增量需求入口(Plan 完结后追加/修改需求,经 req-ledger 哈希台账只跑增量)
│ └── quick-field/ # 字段微改快速通道(加列 + 界面呈现:保 SSoT 跳流程,不作废 tag、不重跑 coding)
└── coding/ # 阶段 B:1 个 skill(瘦入口)
└── coding-start/ # 启动 workflows/coding.mjs
Skill 清单(10 个)
入口(4 个)
| 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)→ 若有 docs/superpowers/RESUME.md 则读末尾条目复盘上次 halt 原因/待跑模块 → 调用 Workflow({scriptPath:"${CLAUDE_PLUGIN_ROOT}/workflows/coding.mjs", args:{projectRoot}}) 启动整个编码阶段 → 告知"已在后台启动" |
用户手动 /erp-workflow:coding-start
|
add-req |
增量需求入口(Plan 完结后追加 / 修改需求时用)。node lib/req-ledger.mjs scan 用内容哈希台账(.req-ledger.json)识别 docs/01 REQ 卡片 + docs/08 §三 FE 行的新增 / 变更;只对增量做 A3-delta(写新 V_n migration + 同步 docs/03,绝不改 V1)+ A5-delta(补 docs/05 端点 / docs/02 顺序 / docs/08 模块行 / FE 行),并 git tag -d 作废变更单元已有的 req-done/*(及所属 milestone/*,复位 docs/08 里程碑字段),使 coding.mjs Router 只重跑增量。首跑无台账则先建基线。 |
用户手动 /erp-workflow:add-req
|
quick-field |
字段微改快速通道(已完成需求追加纯展示/录入字段时替代 add-req 全流程)。保 schema SSoT 不缩水(V_n ALTER + docs/03 同步 + validate-ddl fail-closed),后端/前端代码由主会话直改(grep 清单 + 轻量编译/lint 自检),台账 req-ledger commit 重基线但绝不作废任何 req-done/milestone tag——Router 视一切已完成,不重跑 coding.mjs(不冷起栈、不跑测试门/行为门)。代价是字段未过行为验收:登记到 docs/08 §四 待验清单,攒批人工验收。仅限追加式 ADD COLUMN(可空/带 DEFAULT)+ 既有链路多带一个字段;超界即停下回落 /add-req。 |
用户手动 /erp-workflow:quick-field
|
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>/{_module.md, <req_id>.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 / <req_id>.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 |
跨平台"复制源库→一次性测试副本"脚本(mysqldump 管道;内联极简 YAML 读 config-vars.yaml database: 段;COPY≠SOURCE 守卫,源库绝不被 drop);本轮新迁移的 apply 交给起后端时的 Flyway |
| skeleton-gen | scripts-drop-test-db-template.mjs |
测试收尾删副本脚本(幂等 DROP IF EXISTS;硬拒删源库) |
| skeleton-gen | scripts-promote-to-source-template.mjs |
测试绿后把副本上已验证的新迁移晋升到源库(移植 flyway 历史行 + 重放迁移 SQL;幂等;跨 lane 由编排层起栈互斥串行) |
| skeleton-gen | scripts-seed-demo-data-template.mjs |
演示种子注入脚本(schema 建好后按 sql/seed/<NN>__<module>.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工具执行,不作为普通nodeCLI 入口)。A0project-init检测 git / mysql / node 在 PATH,缺失则按 OS 自动安装,装不上再停下提示用户 -
MySQL 8.x 实例已就绪(host / 库名 / 凭据取自
config-vars.yaml的database:段,由你填写并完全信任)。database.schema= 源库(真实持久库):测试永不 drop 它,每次测试由setup-test-db.mjs把它mysqldump复制成一次性副本(<schema>__test/ lane 副本),跑完drop-test-db.mjs删副本,绿后promote-to-source.mjs把新迁移晋升回源库。这些脚本与seed-demo-data.mjs同走mysql/mysqldumpCLI,故两者须在 PATH -
mysql2(目标项目侧):A4db-init经lib/bootstrap-source-flyway.mjs用 mysql2 建源库 + apply V1 + 写 checksum 一致的 flyway 历史(源库首次 Flyway 托管化;已托管则幂等跳过) -
Spring Boot + Flyway(必需):build.gradle 声明
flyway-core+flyway-mysql;Spring 启动时自动 applysql/migrations/V*.sql。副本自带源库 flyway 历史,起后端时 Flyway 只 apply 本轮新迁移到副本 -
本地 git 仓库(纯本地,无需远程):A0
project-init执行git init;B 阶段每模块由coding.mjs的 milestone stage 本地git merge --no-ff进默认分支并git tag -a milestone/<id>,完成信号由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 的「📐 编码行为约束」。