--- 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 一致性 → 调 lib/bootstrap-source-flyway.mjs 把源库建立成 Flyway 托管态(建库 + apply V1 烟测 + 写 flyway 历史)。 user-invocable: false allowed-tools: Read Write Edit Skill Bash(node *) Bash(npm i mysql2) Bash(npm install mysql2) --- **所有输出必须使用中文。** # db-init 每步骤完成后用 `Edit` 在 `docs/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 中的任何表/字段/索引。字符集 `utf8` + `utf8_general_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 时赋值):`bInvalid` → `bit NOT NULL`(逐字写裸 `bit`,**不得写 `bit(1)`**:docs/03 模板写裸 `bit`,而 validate-ddl 对 BIT 长度不归一化,写 `bit(1)` 会令维度 3 列类型比对判为不一致而 fail-closed);`sFormId` → `varchar(50) NOT NULL`。 > - **主表专属审核列**(仅表清单第一张主表,4 列)`bCheck` / `tCheckDate` / `sCheckPerson` / `sStatus` → 均 `NOT NULL` 且**无 SQL DEFAULT**,由应用在 insert / 审核时赋值(app-assigned):`bCheck` → `bit NOT NULL`(同样逐字写裸 `bit`,不得写 `bit(1)`);`tCheckDate` → `datetime NOT NULL`;`sCheckPerson` / `sStatus` → `varchar(50) NOT NULL`。 > - `sId` / `sParentId`(从表才有,紧随 `sId`)/ `sMemo` → 无 `DEFAULT`(`sMemo` 可空 `LONGTEXT`,其余 `NOT NULL`)。 #### A.2 落盘 V1 文件 用 `Write` 写 `sql/migrations/V1__initial_schema.sql`(`Write` 自动创建父目录)。文件开头是以下 6 行注释,其后接 A.1 的 DDL 主体(`CREATE TABLE` → `CREATE INDEX`): ```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. ``` #### 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 不会代为兜底,勿因校验通过就认定它们也一致。 ```bash 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. 把源库建立成 Flyway 托管态(一步 bootstrap) 不做测试库命名预检:本项目只作用于开发或沙盒环境,命令用同一份 `config-vars.yaml` 直接执行。若 DB 配置仍含 `【人工填写】` 占位则命令直接失败;缺 mysql 客户端、mysql2、凭据或连通性问题由实际命令报错后停下。 **测试模型(源库永不被测试 drop)**:Coding 阶段每次测试从**源库**(`config-vars.yaml` 的 `database.schema`)复制一份一次性副本、在副本上跑、跑完删副本;源库只被复制、绝不被 drop。这要求源库先存在且**被 Flyway 托管**(有 `flyway_schema_history`)。本步骤负责源库的**首次建立**:建库 + apply V1 + 写入正确 checksum 的 Flyway 历史,使源库自此成为 Flyway 托管的持久库。 > **注意**:不再用 `scripts/setup-test-db.mjs` 建库——新模型下它是「复制源库→副本」而非「DROP+CREATE 源库」,不适合 Plan 期建源库。 调 `${CLAUDE_PLUGIN_ROOT}/lib/bootstrap-source-flyway.mjs`:它读 `config-vars.yaml` 的 `database:` 段,用 mysql2 建源库、按版本序 apply `sql/migrations/V*.sql`(apply V1 本身即「V1 DDL 能否被真库接受」的烟测)、并为每个迁移写一条 checksum 与 Flyway 完全一致的历史行(首次起后端时 Flyway 校验通过、不会报 checksum mismatch,只 apply 之后新增的迁移)。 ```bash node "${CLAUDE_PLUGIN_ROOT}/lib/bootstrap-source-flyway.mjs" config-vars.yaml sql/migrations ``` 退出码与处理: - `0` → 成功(含「源库已有 flyway_schema_history → 幂等跳过」) - `1` → 失败:打印 stderr 并停下(如 V1 DDL 错、或源库「有表但无 flyway 历史」的非托管既有库需人工处置) - `2` → 用法错(路径找不到),打印路径并停下 > **幂等 / 安全**:源库已被 Flyway 托管即跳过、绝不重灌或 drop 源库数据;源库有表但无 `flyway_schema_history`(疑为非 Flyway 托管的既有库)→ 拒绝自动 bootstrap 并提示人工确认(避免 apply V1 撞已存在的表)。 勾选:` - [ ] 源库已 Flyway 托管化(bootstrap-source-flyway:建库 + apply V1 + 写 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/bootstrap-source-flyway.mjs`(B 把源库建立成 Flyway 托管态:建库 + apply V*.sql + 写 checksum 一致的 flyway 历史) - `${CLAUDE_PLUGIN_ROOT}/lib/apply-ddl.mjs`(bootstrap 复用其 mysql2 解析与 database 配置读取) - `${CLAUDE_PLUGIN_ROOT}/lib/yaml-config.mjs`(极简 YAML 读取) - `docs/03-数据库设计文档.md`(DDL 翻译输入,SSoT) - `config-vars.yaml`(DB 凭据,A1 产出) - 产物:`sql/migrations/V1__initial_schema.sql`(由 Flyway 在 Spring Boot 启动时验证 / apply)