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