#!/usr/bin/env node /** * backfill-company-owner.js —— 存量公司补 ownerId * * 依据: docs/todo/system-design/38-auth-multi-tenant-isolation.md §3.5 / Phase 2 * * `data/companies/{id}/company.json` 在加公司归属隔离之前建的公司都没有 ownerId 字段—— * 统一划给种子账号 admin(用户已明确拍板,见文档 §一)。 * * 幂等: 已经有 ownerId 的行跳过,可重复执行。 * * 用法: * node scripts/backfill-company-owner.js */ const fs = require('fs'); const path = require('path'); const DATA_DIR = path.resolve(__dirname, '../data/companies'); const SEED_EMAIL = 'admin'; function main() { const userDb = require('../server/services/user-db'); const admin = userDb.findByEmail(SEED_EMAIL); if (!admin) { console.error(`[backfill-company-owner] 找不到种子账号 "${SEED_EMAIL}",先跑 npm run seed:admin`); process.exit(1); } if (!fs.existsSync(DATA_DIR)) { console.log('[backfill-company-owner] data/companies/ 不存在,无需处理'); return; } const dirs = fs.readdirSync(DATA_DIR, { withFileTypes: true }).filter((d) => d.isDirectory()); let migrated = 0; let skipped = 0; for (const d of dirs) { const fp = path.join(DATA_DIR, d.name, 'company.json'); if (!fs.existsSync(fp)) continue; const company = JSON.parse(fs.readFileSync(fp, 'utf-8')); if (company.ownerId != null) { skipped += 1; continue; } company.ownerId = admin.id; company.updatedAt = new Date().toISOString(); // 跟 company-service.js 的 _saveCompany 保持同一种写法(无结尾换行),别引入格式差异。 fs.writeFileSync(fp, JSON.stringify(company, null, 2), 'utf-8'); console.log(`[backfill-company-owner] ${d.name} → ownerId=${admin.id}`); migrated += 1; } console.log(`[backfill-company-owner] 完成:迁移 ${migrated} 家,跳过(已有 ownerId)${skipped} 家`); } main();