import { randomUUID } from 'node:crypto'; import { createMongoStore } from './db.js'; import { loadConfig } from './config.js'; import { hashPassword, validEmail } from './security.js'; function argument(name) { const prefix = `--${name}=`; const item = process.argv.find((value) => value.startsWith(prefix)); return item ? item.slice(prefix.length) : ''; } const config = await loadConfig(); const email = argument('email').trim().toLowerCase(); const password = argument('password') || config.bootstrap.password || ''; const displayName = (argument('display-name') || email.split('@')[0]).trim(); const promoteExisting = process.argv.includes('--promote-existing'); if (!validEmail(email) || !displayName) throw new Error('사용법: npm run bootstrap-admin -- --email=admin@example.com [--password=긴비밀번호] [--display-name=이름]'); const store = await createMongoStore({ config, uri: config.mongodb.uri, dbName: config.mongodb.db }); try { const existing = await store.users.findOne({ email }); const at = new Date(); if (existing) { if (!promoteExisting) throw new Error('사용자가 이미 존재합니다. 비밀번호를 바꾸지 않고 운영자로 승격하려면 --promote-existing를 사용하세요'); await store.users.updateOne({ id: existing.id }, { $set: { status: 'approved', isOperator: true, updatedAt: at } }); } else { if (password.length < 8) throw new Error('새 운영자 계정은 --password 또는 .config.json의 bootstrap.password에 8자 이상 비밀번호를 지정해야 합니다'); const at = new Date(); await store.users.insertOne({ id: randomUUID(), email, displayName, passwordHash: await hashPassword(password), status: 'approved', isOperator: true, createdAt: at, updatedAt: at }); } } finally { await store.close(); } console.log(`Bootstrap operator ready for ${email}`);