← back to Lawyer Directory Builder

src/scripts/create_admin.ts

37 lines

/**
 * Seed an admin user. Re-runs are idempotent — if email exists, password is
 * reset and role is forced to admin.
 *
 *   CREATE_ADMIN_PASSWORD='...' npm run create-admin -- --email steve@designerwallcoverings.com
 */
import 'dotenv/config';
import { pool, query } from '../db/pool.ts';
import { hashPassword } from '../server/auth.ts';

function arg(name: string): string | undefined {
  const i = process.argv.indexOf('--' + name);
  return i >= 0 ? process.argv[i + 1] : undefined;
}

(async () => {
  const email = arg('email');
  const password = process.env.CREATE_ADMIN_PASSWORD || process.env.ADMIN_PASSWORD;
  const fullName = arg('name') || 'Steve Abrams';
  if (!email || !password) {
    console.error('usage: CREATE_ADMIN_PASSWORD=<p> create-admin --email <e> [--name <n>]');
    process.exit(2);
  }
  const hash = await hashPassword(password);
  const r = await query<{ id: number; created: boolean }>(`
    INSERT INTO app_users (email, password_hash, full_name, role, tier, plan, status)
    VALUES (LOWER($1), $2, $3, 'admin', 'admin', 'pro', 'active')
    ON CONFLICT (email) DO UPDATE SET
      password_hash = EXCLUDED.password_hash,
      full_name = COALESCE(app_users.full_name, EXCLUDED.full_name),
      role = 'admin', tier = 'admin', status = 'active', updated_at = NOW()
    RETURNING id, (xmax = 0) AS created
  `, [email, hash, fullName]);
  console.log(`✓ admin ${r.rows[0].created ? 'created' : 'updated'}: ${email} (id=${r.rows[0].id})`);
  await pool.end();
})().catch(async (e) => { console.error(e); try { await pool.end(); } catch {} process.exit(1); });