fix(tooling): 给 db:reset 增加显式确认,避免误清本地密码
ci / 质量门禁 (push) Canceled after 0s

背景:
- 本轮部门管理联调后执行了 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 通过。
This commit is contained in:
Stev_Wang committed 2026-11-03 15:16:52 +08:00
1 parent 981757b76c
commit 3e384febf3
6 files changed
+53 -6

No files matched your search

+2 -1
View File
@@ -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`。
---
+7 -1
View File
@@ -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**;用户密码不会因重启或发布被重置。
也可以使用一键脚本(自动检测并释放端口、带健康检查,启动后默认跟随日志):
@@ -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 密码,请使用专用账号/测试库。
---
+3 -2
View File
@@ -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
+1 -1
View File
@@ -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",
+39
View File
@@ -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);