SKILL.md 8.25 KB

name: db-init description: A4 DB 初始化——LLM 解析 docs/03-数据库设计文档.md → 生成 sql/migrations/V1__initial_schema.sql(DDL only,Flyway 初始 migration)→ 用 lib/validate-ddl.mjs 做 4 维校验(表/列/类型/索引)DDL ↔ docs/03 一致性 → 调 scripts/setup-test-db.mjs DROP+CREATE 空库 → 用 lib/apply-ddl.mjs apply V1。 user-invocable: false

allowed-tools: Read Write Edit Skill Bash(node *) Bash(npm i mysql2) Bash(npm install mysql2)

所有输出必须使用中文。

db-init

每步骤完成后用 Editdocs/08-模块任务管理.md § 一 勾选对应子项。

执行步骤

A. DDL 生成(不依赖数据库连接)

A.1 读 docs/03 并翻译为 DDL

读取 docs/03-数据库设计文档.md,对每张表生成一段 CREATE TABLE(字段顺序/可空/默认/列注释严格对齐 docs/03 行序),随后按顺序追加 CREATE INDEX(含语义引用列上的索引)。不生成任何 ALTER TABLE ... ADD FOREIGN KEY 或内联 FOREIGN KEY 约束——表间关系靠语义判断(列命名约定 + 应用层一致性)维护,docs/03 的引用关系仅作语义记录。严禁臆造或省略 docs/03 中的任何表/字段/索引。字符集 utf8mb4 + utf8mb4_unicode_ci、引擎 InnoDB,除非 docs/03 业务注记另有说明。

标准列默认值的 DDL 翻译规则(docs/03「默认」列是人话,翻进 DDL 时按下表落成 SQL,仍以 docs/03 行内容为准,不臆造):

  • iIncrement(整数主键)→ PRIMARY KEY + AUTO_INCREMENT
  • tCreateDate「当前时间」→ DEFAULT CURRENT_TIMESTAMP
  • tUpdateDate「当前时间戳」→ DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP(行更新时自动刷新)。
  • sBrandsId / sSubsidiaryId「1111111111」→ DEFAULT '1111111111'
  • sMakePerson(制单人,「当前登录用户名」)→ 不可作为 SQL DEFAULT(登录用户名由应用提供),DDL 只写 varchar(50) NOT NULL,由应用在 insert 时写入当前登录用户名(在该列 COMMENT 或表业务注记里注明 app-assigned)。
  • iOrder「数据行条数+1」→ 不可作为 SQL DEFAULT(MySQL 无法 default 成 count+1),DDL 只写 int NOT NULL,count+1 由应用在 insert 时算好赋值(在该列 COMMENT 或表业务注记里注明 app-assigned)。
  • bInvalid(是否作废,基础列)/ sFormId(界面 ID,基础列)→ 均 NOT NULL无 SQL DEFAULT(app-assigned,应用 insert 时赋值):bInvalidbit NOT NULL(逐字写裸 bit不得写 bit(1):docs/03 模板写裸 bit,而 validate-ddl 对 BIT 长度不归一化,写 bit(1) 会令维度 3 列类型比对判为不一致而 fail-closed);sFormIdvarchar(50) NOT NULL
  • 主表专属审核列(仅表清单第一张主表,4 列)bCheck / tCheckDate / sCheckPerson / sStatus → 均 NOT NULL无 SQL DEFAULT,由应用在 insert / 审核时赋值(app-assigned):bCheckbit NOT NULL(同样逐字写裸 bit,不得写 bit(1));tCheckDatedatetime NOT NULLsCheckPerson / sStatusvarchar(50) NOT NULL
  • sId / sParentId(从表才有,紧随 sId)/ sMemo → 无 DEFAULTsMemo 可空 LONGTEXT,其余 NOT NULL)。

A.2 落盘 V1 文件

Writesql/migrations/V1__initial_schema.sqlWrite 自动创建父目录)。文件开头是以下 6 行注释,其后接 A.1 的 DDL 主体(CREATE TABLECREATE INDEX):

-- Flyway migration V1 — initial schema for <project_name>   -- 从 CLAUDE.md § 🎯 项目概述 读
-- Generated: <YYYY-MM-DDTHH:MM:SSZ>                          -- 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__<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.

A.3 校验 V1 ↔ docs/03 4 维一致性 + 自主修正

${CLAUDE_PLUGIN_ROOT}/lib/validate-ddl.mjs 做跨平台、纯 Node 的 4 维校验(表集合 / 列名 / 列类型 / 索引)。注意参数顺序:docs/03 在前,V1.sql 在后。

机检边界(勿误解):4 维 = 表集合 / 列名 / 列类型 / 索引(名 + UNIQUE|INDEX 类别 + 列);表体内联与独立 CREATE INDEX 两种形态都识别。A.1 要求的「字段顺序 / 可空 / 默认 / 列注释对齐」不在机检范围内——这几项靠 A.1 翻译时忠实对齐 docs/03(docs/03 已在 A3 人工审阅过),validate-ddl 不会代为兜底,勿因校验通过就认定它们也一致。

node "${CLAUDE_PLUGIN_ROOT}/lib/validate-ddl.mjs" \
  docs/03-数据库设计文档.md \
  sql/migrations/V1__initial_schema.sql

退出码与处理:

  • 0 → 通过,进入步骤 B
  • 1 → 存在差异(4 维 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 校验),勾选:

  • - [ ] sql/migrations/V1__initial_schema.sql 已生成
  • - [ ] DDL ↔ docs/03 4 维一致(validate-ddl.mjs)

B. 自动导入 MySQL

不做测试库命名预检:本项目只作用于开发或沙盒环境,setup-test-db.mjs / apply-ddl.mjs 会用同一份 config-vars.yaml 直接执行。若 DB 配置仍含 【人工填写】 占位则命令直接失败;缺 mysql 客户端、mysql2、凭据或连通性问题由实际命令报错后停下。

B.1 DROP+CREATE 空库

node scripts/setup-test-db.mjs

B.2 把 V1 灌入已清空的 schema

${CLAUDE_PLUGIN_ROOT}/lib/apply-ddl.mjs:它读取 config-vars.yamldatabase: 段,再经 mysql2 把 DDL 灌入 schema。

node "${CLAUDE_PLUGIN_ROOT}/lib/apply-ddl.mjs" config-vars.yaml sql/migrations/V1__initial_schema.sql

退出码与处理:

  • 0 → 成功,进入步骤 B.3
  • 1 → 失败:打印 stderr 并停下
  • 2 → 用法错(路径找不到),打印路径并停下

勾选:- [ ] setup-test-db.mjs DROP+CREATE + apply V1 已执行

B.3 清库交还 Flyway

B.1 → B.2 是脱离 Flyway 的 DDL 烟测(直接 mysql2 灌入 V1,绕过 Flyway,库里没有 flyway_schema_history 表)。这种状态会卡住后端首次启动:若后端集成测试连真库,Spring Boot 启动时 Flyway 会对一个非空且无 schema 历史表的库报 Found non-empty schema "<db>" without schema history table。所以烟测做完要把产物清掉、把 schema 交还 Flyway,让它在后端启动时自行重放 migration。

再跑一次 setup-test-db.mjs(DROP+CREATE,把 B.2 灌入的烟测产物连同 schema 一并清空):

node scripts/setup-test-db.mjs

B.2 的 DDL 烟测语义不变——它仍是「V1 能否被真库接受」的一次性验证;B.3 只是把烟测留下的非 Flyway 状态清掉,schema 由后端启动时的 Flyway 重新建立。

C. 勾选 docs/08 进度 + 进入 A5

  1. 勾选 A4 顶层(4 维一致已由 A.3 的 validate-ddl.mjs 校验过,apply 不改 V1,无需复校):

    • - [ ] A4 DB 初始化 — db-init
  2. 立即调用 Skill(downstream-gen) 进入 A5,不等用户手动输入。

参考

  • ${CLAUDE_PLUGIN_ROOT}/lib/validate-ddl.mjs(A.3 docs/03 ↔ V1.sql 4 维一致性校验,跨平台纯 Node)
  • ${CLAUDE_PLUGIN_ROOT}/lib/apply-ddl.mjs(B.2 读取 config-vars.yaml 的 database: 段 + mysql2 灌入 DDL)
  • ${CLAUDE_PLUGIN_ROOT}/lib/yaml-config.mjs(apply-ddl 依赖的极简 YAML 读取)
  • docs/03-数据库设计文档.md(DDL 翻译输入,SSoT)
  • config-vars.yaml(DB 凭据,A1 产出)
  • 产物:sql/migrations/V1__initial_schema.sql(由 Flyway 在 Spring Boot 启动时验证 / apply)