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);