import "dotenv/config"; import { PrismaClient } from "@prisma/client"; import { PrismaPg } from "@prisma/adapter-pg"; import { hash } from "@node-rs/argon2"; import { PERMISSIONS, ROLE_DEFS } from "../src/server/rbac"; /** * Seed: global permission catalog + demo tenant with roles and users. * Idempotent (upserts) — safe to run repeatedly. */ const prisma = new PrismaClient({ adapter: new PrismaPg({ connectionString: process.env.DATABASE_URL }), }); const DEMO_PASSWORD = "Demo1234!"; async function main() { // 1. Global permission catalog for (const key of PERMISSIONS) { await prisma.permission.upsert({ where: { key }, update: {}, create: { key } }); } console.log(`✔ ${PERMISSIONS.length} Permissions`); // 2. Demo tenant const tenant = await prisma.tenant.upsert({ where: { slug: "demo" }, update: {}, create: { name: "Demo GmbH", slug: "demo" }, }); // 3. Roles from blueprints, with permission bundles for (const [key, def] of Object.entries(ROLE_DEFS)) { const role = await prisma.role.upsert({ where: { tenantId_key: { tenantId: tenant.id, key } }, update: { name: def.name }, create: { tenantId: tenant.id, key, name: def.name }, }); const perms = await prisma.permission.findMany({ where: { key: { in: [...def.permissions] } }, }); for (const p of perms) { await prisma.rolePermission.upsert({ where: { roleId_permissionId: { roleId: role.id, permissionId: p.id } }, update: {}, create: { roleId: role.id, permissionId: p.id }, }); } } console.log(`✔ Mandant "demo" mit ${Object.keys(ROLE_DEFS).length} Rollen`); // 4. Demo users const passwordHash = await hash(DEMO_PASSWORD); const demoUsers: { email: string; name: string; roles: string[] }[] = [ { email: "admin@demo.example", name: "Anna Admin", roles: ["tenant-admin", "isb"] }, { email: "auditor@demo.example", name: "Axel Auditor", roles: ["auditor"] }, { email: "owner@demo.example", name: "Oskar Owner", roles: ["owner"] }, { email: "user@demo.example", name: "Ulla User", roles: ["user"] }, ]; for (const u of demoUsers) { const user = await prisma.user.upsert({ where: { tenantId_email: { tenantId: tenant.id, email: u.email } }, update: {}, create: { tenantId: tenant.id, email: u.email, name: u.name, passwordHash, }, }); const roles = await prisma.role.findMany({ where: { tenantId: tenant.id, key: { in: u.roles } }, }); for (const r of roles) { await prisma.userRole.upsert({ where: { userId_roleId: { userId: user.id, roleId: r.id } }, update: {}, create: { userId: user.id, roleId: r.id }, }); } } console.log(`✔ ${demoUsers.length} Demo-Nutzer (Passwort: ${DEMO_PASSWORD})`); // 5. Beispiel-Assets, -Prozesse und BIA (nur wenn noch keine Assets existieren) const assetCount = await prisma.asset.count({ where: { tenantId: tenant.id } }); if (assetCount === 0) { const isb = await prisma.user.findUniqueOrThrow({ where: { tenantId_email: { tenantId: tenant.id, email: "admin@demo.example" } }, }); const owner = await prisma.user.findUniqueOrThrow({ where: { tenantId_email: { tenantId: tenant.id, email: "owner@demo.example" } }, }); const mk = (data: { name: string; type: "INFORMATION" | "SYSTEM" | "APPLICATION" | "LOCATION" | "SUPPLIER" | "PERSON" | "DATA"; c: number; i: number; a: number; ownerId?: string; location?: string; tags?: string[]; description?: string; }) => prisma.asset.create({ data: { tenantId: tenant.id, name: data.name, type: data.type, confidentiality: data.c, integrity: data.i, availability: data.a, ownerId: data.ownerId, location: data.location, tags: data.tags ?? [], description: data.description, }, }); const erp = await mk({ name: "ERP-System", type: "SYSTEM", c: 3, i: 4, a: 3, ownerId: owner.id, location: "RZ Frankfurt", tags: ["kritisch", "kern"] }); const crm = await mk({ name: "Kundendatenbank", type: "DATA", c: 4, i: 3, a: 2, ownerId: isb.id, tags: ["dsgvo"] }); const auftraege = await mk({ name: "Auftragsdaten", type: "INFORMATION", c: 3, i: 4, a: 3, ownerId: owner.id }); const hoster = await mk({ name: "Cloud-Hoster (IaaS)", type: "SUPPLIER", c: 2, i: 3, a: 4, description: "Betreibt das Rechenzentrum für ERP und CRM." }); const buero = await mk({ name: "Bürostandort München", type: "LOCATION", c: 2, i: 2, a: 2 }); const itTeam = await mk({ name: "IT-Administration", type: "PERSON", c: 3, i: 3, a: 3 }); await prisma.assetRelation.createMany({ data: [ { tenantId: tenant.id, assetId: erp.id, relatedAssetId: hoster.id, type: "depends_on" }, { tenantId: tenant.id, assetId: crm.id, relatedAssetId: hoster.id, type: "depends_on" }, { tenantId: tenant.id, assetId: erp.id, relatedAssetId: itTeam.id, type: "depends_on" }, ], }); const auftrag = await prisma.process.create({ data: { tenantId: tenant.id, name: "Auftragsabwicklung", description: "Vom Kundenauftrag bis zur Auslieferung.", ownerId: owner.id, }, }); await prisma.processAsset.createMany({ data: [ { tenantId: tenant.id, processId: auftrag.id, assetId: auftraege.id, role: "PRIMARY" }, { tenantId: tenant.id, processId: auftrag.id, assetId: erp.id, role: "SECONDARY" }, { tenantId: tenant.id, processId: auftrag.id, assetId: crm.id, role: "SECONDARY" }, { tenantId: tenant.id, processId: auftrag.id, assetId: itTeam.id, role: "SECONDARY" }, ], }); await prisma.biaEntry.create({ data: { tenantId: tenant.id, processId: auftrag.id, rtoHours: 8, rpoHours: 4, mtdHours: 24, impactC: 2, impactI: 4, impactA: 3, criticality: 4, notes: "Ausfall > 1 Tag führt zu Lieferverzug und Vertragsstrafen.", }, }); const vertrieb = await prisma.process.create({ data: { tenantId: tenant.id, name: "Kundenbetreuung", description: "Anfragen, Angebote, Support.", ownerId: isb.id, }, }); await prisma.processAsset.createMany({ data: [ { tenantId: tenant.id, processId: vertrieb.id, assetId: crm.id, role: "PRIMARY" }, { tenantId: tenant.id, processId: vertrieb.id, assetId: buero.id, role: "SECONDARY" }, ], }); await prisma.biaEntry.create({ data: { tenantId: tenant.id, processId: vertrieb.id, rtoHours: 24, rpoHours: 24, mtdHours: 72, impactC: 3, impactI: 2, impactA: 2, criticality: 3, notes: "Kundenkommunikation kann kurzfristig über Ausweichkanäle laufen.", }, }); console.log("✔ Beispiel-Assets, -Prozesse und BIA angelegt"); } } main() .then(() => prisma.$disconnect()) .catch(async (e) => { console.error(e); await prisma.$disconnect(); process.exit(1); });