import { drizzle } from "drizzle-orm/node-postgres"; import { Pool } from "pg"; import { eq } from "drizzle-orm"; import { hash } from "@node-rs/argon2"; import * as schema from "../src/db/schema/index.js"; /** * Seed für Auth-Erstkonten (idempotent — mehrfaches Ausführen ändert keine * Counts; Querschnittsstandard 7). * * - 1 platform_admin (authTyp `authentik`, brigadeId = NULL). Muss zusätzlich * in Authentik existieren; der signIn-Callback verweigert sonst (Henne-Ei * beim Erst-Deploy, siehe Plan, Risiken Punkt 7). * - 1 Demo-Wehr + 1 wehr_admin (authTyp `local`, argon2id-Passworthash). * * Liest `DATABASE_URL` direkt aus der Umgebung (keine Next.js-Env-Validierung). */ const ARGON2_PARAMS = { type: 2 as const, memoryCost: 19456, timeCost: 2, parallelism: 1, }; const PLATFORM_ADMIN_EMAIL = process.env.SEED_PLATFORM_ADMIN_EMAIL ?? "admin@floriannetz.local"; const WEHR_ADMIN_EMAIL = process.env.SEED_WEHR_ADMIN_EMAIL ?? "wehr-admin@floriannetz.local"; const WEHR_ADMIN_PASSWORD = process.env.SEED_WEHR_ADMIN_PASSWORD ?? "florian-netz-demo"; const DEMO_BRIGADE_NAME = process.env.SEED_DEMO_BRIGADE_NAME ?? "FF Demo (Seed)"; async function main(): Promise { const connectionString = process.env.DATABASE_URL; if (!connectionString) { throw new Error("DATABASE_URL ist nicht gesetzt."); } const pool = new Pool({ connectionString, max: 1 }); const db = drizzle(pool, { schema }); try { // Platform-Admin (authentik): Upsert auf E-Mail (Natural Key). await db .insert(schema.users) .values({ email: PLATFORM_ADMIN_EMAIL, name: "Plattform-Administration", rolle: "platform_admin", authTyp: "authentik", brigadeId: null, passwortHash: null, aktiv: true, }) .onConflictDoUpdate({ target: schema.users.email, set: { rolle: "platform_admin", authTyp: "authentik", brigadeId: null, aktiv: true, }, }); // Demo-Wehr: idempotent (brigades hat keinen Natural-Key-Unique → Lookup). let brigade = await db.query.brigades.findFirst({ where: eq(schema.brigades.name, DEMO_BRIGADE_NAME), }); if (!brigade) { const [created] = await db .insert(schema.brigades) .values({ name: DEMO_BRIGADE_NAME, art: "FF" }) .returning(); brigade = created; } if (!brigade) throw new Error("Demo-Wehr konnte nicht angelegt werden."); // Wehr-Admin (local) mit argon2id-Hash: Upsert auf E-Mail. const passwortHash = await hash(WEHR_ADMIN_PASSWORD, ARGON2_PARAMS); await db .insert(schema.users) .values({ email: WEHR_ADMIN_EMAIL, name: "Wehr-Administration (Demo)", rolle: "wehr_admin", authTyp: "local", brigadeId: brigade.id, passwortHash, aktiv: true, }) .onConflictDoUpdate({ target: schema.users.email, set: { rolle: "wehr_admin", authTyp: "local", brigadeId: brigade.id, passwortHash, aktiv: true, }, }); console.log("Auth-Seed erfolgreich (idempotent)."); console.log(` platform_admin (authentik): ${PLATFORM_ADMIN_EMAIL}`); console.log(` wehr_admin (local): ${WEHR_ADMIN_EMAIL}`); } finally { await pool.end(); } } main().catch((err: unknown) => { console.error("Auth-Seed fehlgeschlagen:", err); process.exit(1); });