From 3e384febf3fc2c9c57d17fd02d7873224cb55341 Mon Sep 17 00:00:00 2001 From: Stev_Wang <304865932@qq.com> Date: Tue, 3 Nov 2026 15:16:52 +0800 Subject: [PATCH] =?UTF-8?q?fix(tooling):=20=E7=BB=99=20db:reset=20?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E6=98=BE=E5=BC=8F=E7=A1=AE=E8=AE=A4=EF=BC=8C?= =?UTF-8?q?=E9=81=BF=E5=85=8D=E8=AF=AF=E6=B8=85=E6=9C=AC=E5=9C=B0=E5=AF=86?= =?UTF-8?q?=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 背景: - 本轮部门管理联调后执行了 pnpm db:reset 清理测试数据,清空本地库, 导致用户手工改过的登录密码被重置回 lingxi2026; - 之前只保证了 ./dev.sh / pnpm dev / pnpm db:init 不会重置数据, db:reset 本身仍可被脚本或助手无提示执行,问题没有真正兜住。 改动: - 新增 scripts/db-reset.mjs:默认拒绝执行并打印影响;只有显式 ALLOW_DB_RESET=1 才调用 prisma migrate reset --force; - package.json 的 db:reset 指向该脚本; - README / AGENTS §6 §11 / e2e README / A1 实施报告同步: 日常迁移补种子只用 pnpm db:init,验证/联调中禁止 db:reset; e2e 会改写 actor 密码,需使用专用账号或独立测试库。 影响面: - 确需清库时多一步显式确认;迁移、启动、单测、int 测试不受影响。 回滚方式: - 回滚本提交即恢复 db:reset 直接执行 prisma migrate reset --force。 验证证据: - pnpm db:reset 无 ALLOW_DB_RESET 时退出码 1,并打印拦截说明; - pnpm format:check / lint 通过;node --check scripts/db-reset.mjs 通过。 --- AGENTS.md | 3 +- README.md | 8 +++- ...灵犀_A1身份认证与用户管理_实施报告_V0.1.md | 2 +- e2e/README.md | 5 ++- package.json | 2 +- scripts/db-reset.mjs | 39 +++++++++++++++++++ 6 files changed, 53 insertions(+), 6 deletions(-) create mode 100644 scripts/db-reset.mjs diff --git a/AGENTS.md b/AGENTS.md index 3dfa64e..bbf5b50 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -115,7 +115,7 @@ docs/ PRD / 技术架构 / 立项建议 / 工程规范 | 构建 | `pnpm build` | | 质量 | `pnpm lint` · `pnpm lint:fix` · `pnpm format` · `pnpm format:check` · `pnpm typecheck` | | 测试 | `pnpm test` · `pnpm test:int` · `pnpm test:e2e` · `pnpm ci:local` | -| 数据库 | `pnpm db:init`(迁移 + 幂等种子,不重置数据)· `pnpm db:migrate` · `pnpm db:reset`(清库重建,慎用;禁止手工删库 / 删数据卷) | +| 数据库 | `pnpm db:init`(迁移 + 幂等种子,不重置数据)· `pnpm db:migrate` · `pnpm db:reset`(清库重建;默认被拦截,必须 `ALLOW_DB_RESET=1` 显式确认;禁止手工删库 / 删数据卷) | | 契约 | `pnpm openapi:diff` | > 文档、脚本、CI 中出现的命令必须与上表一致,禁止自造别名。 @@ -180,6 +180,7 @@ docs/ PRD / 技术架构 / 立项建议 / 工程规范 3. 禁止修改已合并的 `prisma/migrations/`;禁止 `--no-verify` 提交。 4. 涉及业务口径不确定时,输出 `【待确认 Q-xx】` 并说明影响面,**不要编造**。 5. 改动跨 >3 个模块或触及 §10 清单时,先给出方案与影响面,等确认后再动手。 +6. **禁止在验证 / 联调中执行 `pnpm db:reset`**:它会清空本地库并重置所有账号密码;日常初始化只用 `pnpm db:init`。确需清库须先获得用户明确同意,并显式 `ALLOW_DB_RESET=1`。 --- diff --git a/README.md b/README.md index 0487c20..06fa17b 100644 --- a/README.md +++ b/README.md @@ -82,7 +82,13 @@ pnpm dev # 并行启动 api(3000) / web(5173) / worker ``` > **日常启动不需要执行任何数据库命令**。`pnpm dev` / `./dev.sh` 都不会迁移、播种或重置数据库,已有账号密码保持不变。 -> **只有需要清空本地库时才用 `pnpm db:reset`**:它会执行 `prisma migrate reset --force`,重建全部表并重新 seed,admin 等种子账号会回到初始密码 `lingxi2026` 且 `must_change_password=true`(这是“清库”的预期结果,不是启动行为)。 +> **只有需要清空本地库时才用 `pnpm db:reset`**:它会清空全部表并重新 seed,admin 等种子账号会回到初始密码 `lingxi2026` 且 `must_change_password=true`。为避免误清本地改过的密码/数据,该命令默认被拦截,必须显式执行: +> +> ```bash +> ALLOW_DB_RESET=1 pnpm db:reset # 确认清库才执行 +> ``` +> +> 日常迁移 / 补种子请用 `pnpm db:init`(幂等,不改已有密码)。 > 生产环境部署只用 `prisma migrate deploy`(`db:init` 的第一步),**不执行 seed / reset**;用户密码不会因重启或发布被重置。 也可以使用一键脚本(自动检测并释放端口、带健康检查,启动后默认跟随日志): diff --git a/docs/开发计划/灵犀_A1身份认证与用户管理_实施报告_V0.1.md b/docs/开发计划/灵犀_A1身份认证与用户管理_实施报告_V0.1.md index a855a22..daeee7e 100644 --- a/docs/开发计划/灵犀_A1身份认证与用户管理_实施报告_V0.1.md +++ b/docs/开发计划/灵犀_A1身份认证与用户管理_实施报告_V0.1.md @@ -105,7 +105,7 @@ pnpm dev # API :3000 + Web :5173(日常启动不需要任何 DB 种子账号:`admin`(超级管理员);示例成员 `chen.mo` / `lin.qing` / `zhou.an` / `zhao.yinuo` / `gao.cen` / `su.he` / `shen.zhiyuan` / `jiang.lan`;停用示例 `tang.jia` / `he.an`。初始密码统一 `lingxi2026`,首次登录强制修改。 -> 只有需要清空本地库时才执行 `pnpm db:reset`(会重建并恢复种子密码);`./dev.sh` / `pnpm dev` / `pnpm db:init` 不会重置已有账号密码。 +> 只有需要清空本地库时才执行 `ALLOW_DB_RESET=1 pnpm db:reset`(默认被拦截;会重建并恢复种子密码)。`./dev.sh` / `pnpm dev` / `pnpm db:init` 不会重置已有账号密码;e2e 会改写 actor 密码,请使用专用账号/测试库。 --- diff --git a/e2e/README.md b/e2e/README.md index 06afc74..b6adbad 100644 --- a/e2e/README.md +++ b/e2e/README.md @@ -14,11 +14,12 @@ ### 前置 -1. API:`pnpm --filter @lingxi/api dev`(`http://127.0.0.1:3000/api/v1`,真实 PG + Redis,已 `db:reset` + seed)。 +1. API:`pnpm --filter @lingxi/api dev`(`http://127.0.0.1:3000/api/v1`,真实 PG + Redis,已 `pnpm db:init`;**不要执行 `db:reset`**,会清空本地账号密码)。 2. Web:`pnpm --filter @lingxi/web dev`(`http://127.0.0.1:5173`,需 `VITE_PUBLIC_DEMO_SESSION=false`,否则登录走演示会话)。 3. 管理员 actor:默认用种子超管 `jiang.lan`(首登会把初始密码 `lingxi2026` 改成 `QaE2eAdmin2026`,之后复用)。 若本地已改密或想换账号,覆盖:`A1_E2E_ACTOR_ACCOUNT` / `A1_E2E_ACTOR_PASSWORD`。 ⚠️ 不要用 `admin`:本地 `admin` 密码可能已被人工修改或触发登录锁定。 + ⚠️ e2e 会把 actor 密码改成 `QaE2eAdmin2026`(之后复用),请用专用测试账号/测试库,不要指向日常在用的账号。 ### 运行 @@ -49,7 +50,7 @@ A1_E2E=1 pnpm exec playwright test e2e/a1-identity.spec.ts --reporter=list ### 前置与运行 -前置与 A1 相同(API `http://127.0.0.1:3000/api/v1`、Web `http://127.0.0.1:5173` 非 demo 会话、已 `db:reset` + seed): +前置与 A1 相同(API `http://127.0.0.1:3000/api/v1`、Web `http://127.0.0.1:5173` 非 demo 会话、已 `pnpm db:init`): ```bash A2_E2E=1 pnpm exec playwright test e2e/a2-roles.spec.ts --reporter=list diff --git a/package.json b/package.json index 5b6b949..1b58935 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,7 @@ "db:generate": "prisma generate", "db:migrate": "prisma migrate dev", "db:init": "prisma migrate deploy && pnpm db:seed", - "db:reset": "prisma migrate reset --force", + "db:reset": "node scripts/db-reset.mjs", "db:seed": "tsx prisma/seed.ts", "openapi:export": "tsx --tsconfig apps/api/tsconfig.json apps/api/src/scripts/export-openapi.ts && openapi-typescript openapi/lingxi.openapi.json -o apps/web/src/api/generated/openapi.d.ts && prettier --write apps/web/src/api/generated/openapi.d.ts", "openapi:diff": "node scripts/openapi-diff.mjs", diff --git a/scripts/db-reset.mjs b/scripts/db-reset.mjs new file mode 100644 index 0000000..c25f388 --- /dev/null +++ b/scripts/db-reset.mjs @@ -0,0 +1,39 @@ +#!/usr/bin/env node +/** + * 清库重建的显式闸门。 + * + * `prisma migrate reset --force` 会清空全部表并重新 seed,所有账号密码都会 + * 回到初始值;开发/联调中误执行会直接丢掉本地改过的密码与业务数据。 + * 因此必须显式设置 ALLOW_DB_RESET=1 才放行,日常初始化请用 `pnpm db:init`。 + */ +import { spawnSync } from 'node:child_process'; + +const allowed = process.env.ALLOW_DB_RESET === '1'; + +if (!allowed) { + console.error(` +⛔ 已阻止 pnpm db:reset。 + +该命令会清空本地数据库并重新 seed,所有账号密码都会回到初始密码 +(admin / jiang.lan 等种子账号 → lingxi2026,且 must_change_password=true)。 + +- 日常迁移 + 幂等种子(不改已有密码):pnpm db:init +- 确实需要清库时,显式执行: + ALLOW_DB_RESET=1 pnpm db:reset +`); + process.exit(1); +} + +console.warn('⚠️ ALLOW_DB_RESET=1:即将清空数据库并重新 seed,所有账号密码会重置为初始值。'); + +const command = process.platform === 'win32' ? 'pnpm.cmd' : 'pnpm'; +const result = spawnSync(command, ['exec', 'prisma', 'migrate', 'reset', '--force'], { + stdio: 'inherit', +}); + +if (result.error) { + console.error('执行 prisma migrate reset 失败:', result.error.message); + process.exit(1); +} + +process.exit(result.status ?? 1);