diff --git a/README.md b/README.md index c8b059b..dd6759b 100644 --- a/README.md +++ b/README.md @@ -135,7 +135,7 @@ erp-workflow-plugin/ | 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`、`iIncrement` 主键、`sBrandsId`/`sSubsidiaryId` 租户列)+ 每表自动补标准列(9 列基础:`iIncrement`/`sId`/`sBrandsId`/`sSubsidiaryId`/`sMakePerson`/`tCreateDate`/`tUpdateDate`/`iOrder`/`sMemo`;主表额外加 6 审核列 `bInvalid`/`bCheck`/`tCheckDate`/`sCheckPerson`/`sStatus`/`sFormId`(共 15 列),从表额外加 `sParentId` 紧随 `sId`(共 10 列);其中 `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 | +| A3 | `db-design-gen` | • 套用固定 ERP 约定(列前缀 `i/s/t/b`、`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 | diff --git a/skills/plan/db-design-gen/SKILL.md b/skills/plan/db-design-gen/SKILL.md index 283294b..cc2f64d 100644 --- a/skills/plan/db-design-gen/SKILL.md +++ b/skills/plan/db-design-gen/SKILL.md @@ -26,7 +26,7 @@ allowed-tools: Read Write Edit Grep Glob 基于步骤 A 读到的 REQ + 命名规范,**正向推导**业务实体 → 表 + 字段 + 索引 + 语义引用关系。要求: -1. 严格套用 `docs/04` 命名规范 + 匈牙利列前缀(`i`=int / `s`=varchar / `t`=datetime / `b`=bit) +1. 严格套用 `docs/04` 命名规范 + 匈牙利列前缀(`i`=int / `s`=varchar / `t`=datetime / `b`=bit);金额 / 数量等小数列统一用 `decimal(18,6)`(固定精度 18、标度 6),除非某 REQ 明确要求其他精度/标度(按 REQ 并在该列业务含义注明偏离) 2. **主键**:标准列 `iIncrement` int 主键。REQ 明确要求不同主键(复合主键 / UUID / 业务主键)时按 REQ,并在该表业务注记里注明偏离原因 3. **语义引用关系**:依据 REQ 中的引用关系(如「订单引用客户」),列出 `from→to`(如 `sCustomerId → 客户表.sId`);仅语义、不建 FK 约束、不写 `ON DELETE` / `ON UPDATE`,应用层维护一致性 4. **索引**:根据 REQ 的查询模式推导业务索引;语义引用列默认建索引;租户隔离列 `sBrandsId` / `sSubsidiaryId`(标准列)按业务查询模式建组合索引。 @@ -39,12 +39,12 @@ allowed-tools: Read Write Edit Grep Glob ### C. 渲染 docs/03 -1. 读取 `${CLAUDE_SKILL_DIR}/templates/docs-03-header-template.md`,填充 `schema_name`(从 `config-vars.yaml` 读 `database.schema`,无则填 `【人工填写:database.schema】`)、`er_overview`(纯文本 ER 概览)。「项目标准列约定」是固定 9 列基础标准列,主表(表清单第一张)额外含 6 列审核标准列(共 15 列)、从表额外含 `sParentId`(共 10 列),无占位、原样保留。 -2. 渲染「表清单」:对每张表读取并填充 `${CLAUDE_SKILL_DIR}/templates/docs-03-table-template.md`——9 个基础标准列已内置原样输出,只需填业务字段(`{{#each columns}}`)/ 索引 / 引用关系 / 业务注记,并按表位补齐专属标准列: - - **基础标准列(9 列,所有表)**:`iIncrement` / `sId` / `sBrandsId` / `sSubsidiaryId` / `sMakePerson` / `tCreateDate` / `tUpdateDate` / `iOrder` / `sMemo`。其中 `sId` / `sBrandsId` / `sSubsidiaryId` / `sMakePerson` 均为 varchar(50) NOT NULL;`sBrandsId` / `sSubsidiaryId` 默认 `1111111111`;`sMakePerson`(制单人)默认当前登录用户名、由应用 insert 时写入(非 SQL 默认,app-assigned);`tCreateDate` 默认当前时间;`tUpdateDate`(更新时间)默认当前时间戳且行更新自动刷新;`iOrder`(int NOT NULL,排序号)默认数据行条数+1、由应用 insert 时算 count+1 赋值(非 SQL 默认);`sMemo`(LONGTEXT,可空)备注。 - - **主表**(表清单第一张表):在 `iOrder` 之后、`sMemo` 之前额外加入 6 列审核标准列 `bInvalid` / `bCheck` / `tCheckDate` / `sCheckPerson` / `sStatus` / `sFormId`(所有主表无条件加,共 15 列)。`bInvalid` / `bCheck` 为 bit NOT NULL;`tCheckDate` 为 datetime NOT NULL;`sCheckPerson`(审核人)/ `sStatus`(审核状态)/ `sFormId`(界面 ID)为 varchar(50) NOT NULL。6 列均无 SQL 默认,由应用在 insert / 审核时赋值(app-assigned)。 - - **从表**(第二张起的其余表):额外加入 `sParentId`(varchar(50) NOT NULL,业务父级ID)且**位置紧随 `sId` 之后**(共 10 列,不含主表审核列)。 - 这些列的『当前时间 → CURRENT_TIMESTAMP』『当前时间戳 → CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP』『1111111111 → DEFAULT '1111111111'』『sMakePerson / iOrder / 主表审核列 不写 SQL 默认(app-assigned)』等 DDL 默认值翻译由下游 A.1 db-init 处理,docs/03 只记录业务语义。 +1. 读取 `${CLAUDE_SKILL_DIR}/templates/docs-03-header-template.md`,填充 `schema_name`(从 `config-vars.yaml` 读 `database.schema`,无则填 `【人工填写:database.schema】`)、`er_overview`(纯文本 ER 概览)。「项目标准列约定」是固定 11 列基础标准列,主表(表清单第一张)额外含 4 列审核标准列(共 15 列)、从表额外含 `sParentId`(共 12 列),无占位、原样保留。 +2. 渲染「表清单」:对每张表读取并填充 `${CLAUDE_SKILL_DIR}/templates/docs-03-table-template.md`——11 个基础标准列已内置原样输出,只需填业务字段(`{{#each columns}}`)/ 索引 / 引用关系 / 业务注记,并按表位补齐专属标准列: + - **基础标准列(11 列,所有表)**:`iIncrement` / `sId` / `sBrandsId` / `sSubsidiaryId` / `sMakePerson` / `tCreateDate` / `tUpdateDate` / `iOrder` / `bInvalid` / `sFormId` / `sMemo`。其中 `sId` / `sBrandsId` / `sSubsidiaryId` / `sMakePerson` 均为 varchar(50) NOT NULL;`sBrandsId` / `sSubsidiaryId` 默认 `1111111111`;`sMakePerson`(制单人)默认当前登录用户名、由应用 insert 时写入(非 SQL 默认,app-assigned);`tCreateDate` 默认当前时间;`tUpdateDate`(更新时间)默认当前时间戳且行更新自动刷新;`iOrder`(int NOT NULL,排序号)默认数据行条数+1、由应用 insert 时算 count+1 赋值(非 SQL 默认);`bInvalid`(是否作废,bit NOT NULL)/ `sFormId`(界面 ID,varchar(50) NOT NULL)均无 SQL 默认、由应用赋值(app-assigned);`sMemo`(LONGTEXT,可空)备注。 + - **主表**(表清单第一张表):在 `bInvalid` 之后(即 `bInvalid` 与 `sFormId` 之间)额外加入 4 列审核标准列 `bCheck` / `tCheckDate` / `sCheckPerson` / `sStatus`(所有主表无条件加,共 15 列)。`bCheck` 为 bit NOT NULL;`tCheckDate` 为 datetime NOT NULL;`sCheckPerson`(审核人)/ `sStatus`(审核状态)为 varchar(50) NOT NULL。4 列均无 SQL 默认,由应用在 insert / 审核时赋值(app-assigned)。 + - **从表**(第二张起的其余表):额外加入 `sParentId`(varchar(50) NOT NULL,业务父级ID)且**位置紧随 `sId` 之后**(共 12 列,不含主表审核列)。 + 这些列的『当前时间 → CURRENT_TIMESTAMP』『当前时间戳 → CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP』『1111111111 → DEFAULT '1111111111'』『sMakePerson / iOrder / bInvalid / sFormId / 主表审核列 不写 SQL 默认(app-assigned)』等 DDL 默认值翻译由下游 A.1 db-init 处理,docs/03 只记录业务语义。 3. 写入 `docs/03-数据库设计文档.md`。 勾选:` - [ ] docs/03-数据库设计文档.md 已生成` diff --git a/skills/plan/db-design-gen/templates/docs-03-header-template.md b/skills/plan/db-design-gen/templates/docs-03-header-template.md index 1e66a8e..49d4fe6 100644 --- a/skills/plan/db-design-gen/templates/docs-03-header-template.md +++ b/skills/plan/db-design-gen/templates/docs-03-header-template.md @@ -6,11 +6,11 @@ ## 项目标准列约定 -下文每张业务表的字段清单都自动包含以下 **9 个基础标准列**(匈牙利前缀 `i` int / `s` varchar / `t` datetime / `b` bit),所有表通用;在此之上按表位追加专属标准列:**主表**额外加 **6 个审核标准列**(共 15 列),**从表**额外加 **1 个标准列 `sParentId`**(共 10 列)。渲染时由 `docs-03-table-template.md` 模板内置原样输出。 +下文每张业务表的字段清单都自动包含以下 **11 个基础标准列**(匈牙利前缀 `i` int / `s` varchar / `t` datetime / `b` bit),所有表通用;在此之上按表位追加专属标准列:**主表**额外加 **4 个审核标准列**(共 15 列),**从表**额外加 **1 个标准列 `sParentId`**(共 12 列)。渲染时由 `docs-03-table-template.md` 模板内置原样输出。 主表 = 「表清单」中的**第一张表**;从表 = 其余各表。 -**基础标准列(9 列,所有表)**: +**基础标准列(11 列,所有表)**: | 列名 | 类型 | 可空 | 主键 | 默认 | 说明 | |---|---|---|---|---|---| @@ -22,6 +22,8 @@ | `tCreateDate` | datetime | 否 | — | 当前时间 | 记录创建时间(标准列);DDL 译为 `DEFAULT CURRENT_TIMESTAMP` | | `tUpdateDate` | datetime | 否 | — | 当前时间戳 | 记录更新时间(标准列);DDL 译为 `DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP`(行更新自动刷新) | | `iOrder` | int | 否 | — | 数据行条数+1 | 排序号;**非 SQL 默认**——应用在 insert 时按 count+1 赋值,DDL 仅写 `int NOT NULL`(不写 DEFAULT 表达式,在该列 COMMENT / 表业务注记里注明 app-assigned) | +| `bInvalid` | bit | 否 | — | — | 是否作废(标准列);**非 SQL 默认**——应用 insert 时赋值(如 `0`),DDL 仅写 `bit NOT NULL` | +| `sFormId` | varchar(50) | 否 | — | — | 界面 ID(标准列);**非 SQL 默认**——应用维护,DDL 仅写 `varchar(50) NOT NULL` | | `sMemo` | LONGTEXT | 是 | — | — | 备注(标准列) | **从表专属标准列**(从「表清单」第二张表起,即除第一张主表外的所有表都加,插入位置紧随 `sId` 之后): @@ -30,16 +32,14 @@ |---|---|---|---|---|---| | `sParentId` | varchar(50) | 否 | — | — | 业务父级 ID(标准列);仅从表有,紧随 `sId` 之后 | -**主表专属标准列**(仅「表清单」第一张主表加,所有主表无条件包含,共 6 列;插入位置在 `iOrder` 之后、`sMemo` 之前): +**主表专属标准列**(仅「表清单」第一张主表加,所有主表无条件包含,共 4 列;插入位置紧随 `bInvalid` 之后,即在 `bInvalid` 与 `sFormId` 之间): | 列名 | 类型 | 可空 | 主键 | 默认 | 说明 | |---|---|---|---|---|---| -| `bInvalid` | bit | 否 | — | — | 是否作废(标准列);**非 SQL 默认**——应用 insert 时赋值(如 `0`),DDL 仅写 `bit NOT NULL` | | `bCheck` | bit | 否 | — | — | 是否审核(标准列);**非 SQL 默认**——应用 insert 时赋值(如 `0`),DDL 仅写 `bit NOT NULL` | | `tCheckDate` | datetime | 否 | — | — | 审核时间(标准列);**非 SQL 默认**——审核时由应用写入,DDL 仅写 `datetime NOT NULL` | | `sCheckPerson` | varchar(50) | 否 | — | — | 审核人(标准列);**非 SQL 默认**——审核时由应用写入,DDL 仅写 `varchar(50) NOT NULL` | | `sStatus` | varchar(50) | 否 | — | — | 审核状态(标准列);**非 SQL 默认**——应用维护,DDL 仅写 `varchar(50) NOT NULL` | -| `sFormId` | varchar(50) | 否 | — | — | 界面 ID(标准列);**非 SQL 默认**——应用维护,DDL 仅写 `varchar(50) NOT NULL` | 字典 / 辅助表如有豁免,在该表业务注记里注明豁免原因。 diff --git a/skills/plan/db-design-gen/templates/docs-03-table-template.md b/skills/plan/db-design-gen/templates/docs-03-table-template.md index 65cbacc..c2a129c 100644 --- a/skills/plan/db-design-gen/templates/docs-03-table-template.md +++ b/skills/plan/db-design-gen/templates/docs-03-table-template.md @@ -12,6 +12,8 @@ | `tCreateDate` | datetime | 否 | 当前时间 | 创建时间(标准列) | | `tUpdateDate` | datetime | 否 | 当前时间戳 | 更新时间(标准列,ON UPDATE 刷新) | | `iOrder` | int | 否 | 数据行条数+1 | 排序号(标准列) | +| `bInvalid` | bit | 否 | — | 是否作废(标准列,app-assigned) | +| `sFormId` | varchar(50) | 否 | — | 界面 ID(标准列,app-assigned) | | `sMemo` | LONGTEXT | 是 | — | 备注(标准列) | {{#each columns}} | {{name}} | {{type}} | {{nullable}} | {{default}} | {{business_meaning}} | diff --git a/skills/plan/db-init/SKILL.md b/skills/plan/db-init/SKILL.md index 789dfcc..3d221d6 100644 --- a/skills/plan/db-init/SKILL.md +++ b/skills/plan/db-init/SKILL.md @@ -26,7 +26,8 @@ allowed-tools: Read Write Edit Skill Bash(node *) Bash(npm i mysql2) Bash(npm in > - `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)。 -> - **主表专属审核列**(仅表清单第一张主表,6 列)`bInvalid` / `bCheck` / `tCheckDate` / `sCheckPerson` / `sStatus` / `sFormId` → 均 `NOT NULL` 且**无 SQL DEFAULT**,由应用在 insert / 审核时赋值(app-assigned):`bInvalid` / `bCheck` → `bit NOT NULL`(逐字写裸 `bit`,**不得写 `bit(1)`**:docs/03 模板写裸 `bit`,而 validate-ddl 对 BIT 长度不归一化,写 `bit(1)` 会令维度 3 列类型比对判为不一致而 fail-closed);`tCheckDate` → `datetime NOT NULL`;`sCheckPerson` / `sStatus` / `sFormId` → `varchar(50) NOT NULL`。 +> - `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 文件