name: build-db description: 计划第 3 段——解析 docs/03 → V1 migration + validate.sh 校验 + apply 到本地 MySQL;生成 docs/05 API 契约 + 回填 REQ 依赖接口;计算模块/REQ 依赖顺序写入 docs/08 § 二(排序权威);最终占位符扫描后停下(计划完成)。 user-invocable: false
allowed-tools: Read Write Edit Glob Grep Skill AskUserQuestion Bash(mkdir *) Bash(mysql *) Bash(set *) Bash(. .env.local) Bash(grep *) Bash(bash *) Bash(./scripts/setup-test-db.sh) Bash(cat *) Bash(cp *)
所有输出必须使用中文。
build-db
执行步骤
步骤 0:打印当前位置流程图
用 Bash 执行以下命令(文件不存在时静默忽略,不报错):
cat "${CLAUDE_PLUGIN_ROOT}/skills/crosscut/plan-start/banners/flow.txt" 2>/dev/null || true
打印横幅:▶ 计划阶段 ③ — build-db。
A. DDL 生成(不依赖数据库连接)
A.1 读 docs/03 并翻译为 DDL
读取 docs/03-数据库设计文档.md,按字段 / 索引 / 外键 / 业务注记严格翻译为:
- 每张表一段
CREATE TABLE - 字段顺序与 docs/03 表格行序一致;
Nullable列直接映射NOT NULL/NULL;默认列映射DEFAULT <value>;列尾用COMMENT '<业务含义>'写注释 - 索引
- 外键:在所有表创建完成后统一追加
要求:
- 严禁臆造 docs/03 中没有的表 / 字段 / 索引 / 外键
- 严禁省略 docs/03 中已有的列、注释或约束
- 字符集统一
utf8mb4+utf8mb4_unicode_ci,引擎统一InnoDB,除非 docs/03 业务注记明确要求其他设置
A.2 落盘 V1 文件
Bash: mkdir -p sql/migrations。
用 Write 写 sql/migrations/V1__initial_schema.sql,内容 = 头部注释 + DDL 主体:
-
头部注释(6 行 SQL 注释):
-
-- Flyway migration V1 — initial schema for <project_name>(从CLAUDE.md § 🎯 项目概述读) -
-- Generated: <YYYY-MM-DDTHH:MM:SSZ>(UTC ISO 8601 时间戳) -- Source: 由计划 ③ build-db 从 docs/03-数据库设计文档.md 翻译生成(schema SSoT 是 docs/03)-- This is the FIRST migration; subsequent schema changes must be written as new files sql/migrations/V2__<desc>.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.
-
DDL 主体:A.1 推导出的所有
CREATE TABLE→CREATE INDEX→ALTER TABLE ... ADD CONSTRAINT ... FOREIGN KEY,按此顺序拼接。
A.3 校验 V1 ↔ docs/03 集合一致性 + 自主修正
调 ${CLAUDE_SKILL_DIR}/scripts/validate.sh 做脚本化的校验:
bash "${CLAUDE_SKILL_DIR}/scripts/validate.sh" \
sql/migrations/V1__initial_schema.sql \
docs/03-数据库设计文档.md
退出码与处理:
-
0→ 通过,进入步骤 B -
1→ 自主修正循环(最多 3 轮,docs/03 是 SSoT 不动):- 解析 stderr 差异清单,修正 V1.sql
- 重跑 validate.sh
- 退出 0 → 进入 B;退出 1 且本轮 < 3 → 回步骤 1;本轮 ≥ 3 仍失败 → 停下,打印最终残留差异 + 已尝试的 3 轮修正摘要,让用户介入
-
2→ 用法错(V1 / docs 路径找不到),打印路径并停下
完成后(V1 写入并通过 validate.sh 校验),用 Edit 在 docs/08-模块任务管理.md 中勾选:
-
- [ ] V1 migration 已生成并校验 + apply 到本地 MySQL(步骤 C 完成后一并勾选)
B. 数据库环境检查
B.1 检查 .env.local 凭据
用 Glob 检查 .env.local 是否存在;不存在 → 提示用户重新运行计划 ② design 重建并停下。
用 Bash 加载并校验 5 个必填字段非空:
set -a; . .env.local; set +a
for v in DB_HOST DB_PORT DB_USER DB_PASSWORD DB_SCHEMA; do
eval val=\${$v:-}
[ -z "$val" ] && echo "MISSING: $v"
done
任一缺失 → 打印缺失字段名并停下,提示用户编辑 .env.local 后重跑。
B.2 验证 MySQL 连接
set -a; . .env.local; set +a
mysql -h"$DB_HOST" -P"$DB_PORT" -u"$DB_USER" -p"$DB_PASSWORD" -e "SELECT 1;"
- 成功 → 进入步骤 C
-
失败 → 打印具体错误(认证 / 主机不可达 / 端口拒接等),提示检查
.env.local,停下。
C. 自动导入 MySQL
C.1 DROP+CREATE 空库
./scripts/setup-test-db.sh
C.2 把 V1 灌入已清空的 schema
set -a; . .env.local; set +a
mysql -h"$DB_HOST" -P"$DB_PORT" -u"$DB_USER" -p"$DB_PASSWORD" "$DB_SCHEMA" \
< sql/migrations/V1__initial_schema.sql
非零退出 → 报错停下,打印 mysql stderr。
完成后,用 Edit 在 docs/08-模块任务管理.md 中勾选:
- [ ] V1 migration 已生成并校验 + apply 到本地 MySQL
C.3 自检 SHOW TABLES
set -a; . .env.local; set +a
ACTUAL=$(mysql -N -B -h"$DB_HOST" -P"$DB_PORT" -u"$DB_USER" -p"$DB_PASSWORD" \
-e "SHOW TABLES;" "$DB_SCHEMA" | wc -l | tr -d ' ')
EXPECTED=$(grep -c '^## `' docs/03-数据库设计文档.md)
[ "$ACTUAL" = "$EXPECTED" ] || { echo "MISMATCH: actual=$ACTUAL expected=$EXPECTED"; exit 1; }
行数不一致 → 报错停下;一致 → 进入步骤 D。
D. 生成 docs/05 API 契约 + 回填 REQ 依赖接口
D.1 渲染 docs/05
- 读取
${CLAUDE_SKILL_DIR}/templates/docs-05-header-template.md,填充base_path(从docs/04 § 一推导 API 前缀,如/api/v1)、auth_note(认证方式说明)、pagination_note(分页参数约定),写入docs/05-API接口契约.md头部。 - 对所有模块的每个 REQ:读取并推断
${CLAUDE_SKILL_DIR}/templates/docs-05-endpoint-template.md,追加到 docs/05。
完成后,用 Edit 在 docs/08-模块任务管理.md 中勾选:
-
- [ ] docs/05 API 契约已生成 + 回填 REQ 依赖接口(步骤 D.2 完成后一并勾选)
D.2 回填模块头 + REQ 卡片的 TBD 字段
- 在
docs/01-需求清单/*/_module.md(模块头)和docs/01-需求清单/*/REQ-*.md(REQ 卡片)中搜索TBD(build-db 自动补)并回填。不动TBD(design 自动补)(应已由 design 回填完毕)。-
_module.md的依赖模块字段:填入该模块所依赖的其他模块 ID(逗号分隔,无则填—) -
REQ-*.md的依赖接口字段:填入该 REQ 依赖的接口路径(逗号分隔,无则填—)
-
- 打印回填统计:
build-db 回填 <M> 处模块"依赖模块" + <N> 处 REQ"依赖接口"。
完成后,用 Edit 在 docs/08-模块任务管理.md 中勾选:
- [ ] docs/05 API 契约已生成 + 回填 REQ 依赖接口
E. 模块/REQ 依赖顺序 → docs/08 § 二
本步骤计算模块/REQ 依赖拓扑顺序,将结果写入 docs/08 § 二(该 § 二 行序是 coding-start 的排序权威,无单独开发计划文件)。
E.1 构建模块依赖 DAG + 拓扑排序
- 读取所有
docs/01-需求清单/*/_module.md,提取每个模块的依赖模块字段(经步骤 D.2 已回填)。 - 构建模块依赖 DAG(有向无环图),节点 = 模块 ID,边 = 「A 依赖 B → B 先于 A」。
- 拓扑排序得到
module_topo_order[]。 -
环依赖打破:若模块 DAG 存在环(module_A ↔ module_B),按启发式(字母序 / 被依赖次数多者先)破环排出
module_topo_order,并在参与环的模块里第一个 REQ 的note字段填入原因(如 "A↔B 互依赖:先做 A 的骨架")。
E.2 模块内 REQ 排序
对每个模块内部:
- 读取该模块所有
REQ-*.md,提取每个 REQ 的依赖接口+依赖表字段,推导 REQ 间依赖关系。 - 拓扑排序得到模块内
req_order[]。 -
REQ 级环依赖打破:若模块内 REQ 互依赖,按字母序 / 被依赖次数多者先破环,
note填原因;非环 REQnote留—。
E.3 渲染 docs/08 § 二
按 module_topo_order[] 依次为每个模块渲染 bullet,追加到 docs/08-模块任务管理.md § 二(追加在 § 二 的注释块之后,保留原有注释格式示例):
读取 ${CLAUDE_SKILL_DIR}/templates/docs-08-module-row-template.md,填充:
-
{{module_id}}:模块 ID -
{{module_name}}:模块中文名 -
{{depends_on}}:依赖模块 ID 列表(逗号分隔,无则填—) -
{{path_scopes}}:backend/module/<id>/ -
{{req_checklist}}:按模块内req_order[]生成,每行- [ ] REQ-XXX-NNN 功能名
每个模块 bullet 间空一行,一次性追加全部模块。
完成后,用 Edit 在 docs/08-模块任务管理.md 中勾选:
- [ ] docs/08 § 二 模块清单(含 REQ 顺序)已生成
F. 一致性检查 + 占位符扫描 + 计划完成
F.1 一致性检查(最多 3 轮自修复)
检查项:
- 每个 docs/01 REQ 都出现在 docs/05(作为接口,如适用)
- docs/08 § 二 的
module_id集合 = docs/01-需求清单/ 的模块目录集合
不一致 → 按差异类型自主修复:
- REQ 缺 docs/05 endpoint → 按步骤 D.1 规则为该 REQ 推测,并追加到 docs/05
- module_id 缺 docs/08 § 二 → 按步骤 E 规则渲染该模块 bullet,按拓扑序插入正确位置
修复后重跑检查;通过 → 进入 F.2;3 轮仍失败 → 停下,打印最终残留差异 + 已尝试的 3 轮修复摘要让用户介入。
F.2 最终占位符扫描
a. TBD → 自动补齐:Grep 搜索 TBD(design 自动补) 和 TBD(build-db 自动补)。有命中则就地补填(design 残留 → 查 docs/03 填 依赖表;build-db 残留 → 查 docs/05 按 REQ-ID 填 依赖接口),再 Grep 确认 0 命中;仍残留报错停下。
b. 【人工填写:...】 → QA 循环等用户补:
循环执行直到搜索不到 【人工填写: 且用户选「继续」:
- 0 命中 → 直接放行进入步骤 F.3
- 有命中 → 打印残留清单(
<文件:行号> — <内容摘要>),用AskUserQuestion弹「继续」/「有疑问想先沟通」二选一;用户回答后重扫验证再决定放行 / 继续循环
每次弹 QA 前都重扫一次——保证用户看到的 N 是最新的,避免「用户以为填完但实际还有残留」直接放行。
F.3 勾选 § 一 ③ 顶层 + 打印计划完成横幅
完成后,用 Edit 在 docs/08-模块任务管理.md 中勾选 ③ 顶层:
- [ ] 计划 ③ DB 初始化 + 下游文档 — build-db
打印计划阶段终止横幅并停下(不自动进入 coding 阶段):
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
[build-db] ✅ 计划阶段(①②③)全部完成
所有规划文档已就绪,docs/08 § 一 全部勾选。
⚠️ 进入 Coding 阶段前必须完成:
1. 审核全部 Plan 产出(docs/01 / 03 / 04 / 05 / 08 + CLAUDE.md + sql/migrations/V1 + scripts/*)
2. 把全部 Plan 产物 commit 到本地默认分支(main / master):
git add -A && git commit -m "chore: plan phase done"
3. 运行 /erp-workflow:coding-start 进入编码阶段
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
停止,不调用任何下游 skill。
参考
-
docs/03-数据库设计文档.md(DDL 翻译输入,SSoT) -
docs/01-需求清单/index.md(模块索引) -
docs/01-需求清单/<module>/_module.md(模块依赖:回填依赖模块;拓扑排序输入) -
docs/01-需求清单/<module>/REQ-*.md(REQ 依赖:回填依赖接口;模块内 REQ 排序输入) -
docs/08-模块任务管理.md§ 二(模块拓扑顺序追加目标;是 coding-start 的排序权威) -
${CLAUDE_SKILL_DIR}/scripts/validate.sh(A.3 表名 + 每表列名集合校验脚本) ${CLAUDE_SKILL_DIR}/templates/docs-05-header-template.md${CLAUDE_SKILL_DIR}/templates/docs-05-endpoint-template.md-
${CLAUDE_SKILL_DIR}/templates/docs-08-module-row-template.md(模块 bullet 行模板) -
.env.local(DB 凭据) - 产物:
sql/migrations/V1__initial_schema.sql(由 Flyway 在 Spring Boot 启动时 apply)