Files
craftvia/scripts/sync-role-permissions.ts
msolarczekandClaude Opus 5 1701db0a62 Fundament: Doku, Testanpassungen, Restbereinigung
- AGENTS.md und README.md auf Craftvia umgeschrieben (Regeln, Andockpunkte,
  Stack mit Garage, tsx-Tests, Gate, Demo-Logins)
- ISMS-Dokumente entfernt (SPEC, Prototypen, Lane-Prompts, Übergaben, Konzepte
  Incidents/Framework); Fundament-Doku (Deploy, Sicherheit, Backup, Identity) bleibt
- Fundament-Tests an Craftvia-Rollen/Branding angepasst, Resttreffer
  certvia/isms in Skripten und Kommentaren bereinigt

Gate: prisma generate, migrate status, tsc, lint, build, 22/22 Testskripte grün.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-14 11:44:58 +02:00

80 lines
3.4 KiB
TypeScript

// Rollen-Rechte-Sync (Wartung): gleicht die Rollen→Rechte-Zuordnung ALLER bestehenden
// Mandanten mit dem aktuellen Rechtekatalog (ROLE_DEFS) ab. Nötig, weil Rechte bei der
// Provisionierung in die DB geschrieben werden — neu hinzugekommene Rechte (z. B.
// `report:approve_team`, `lotse:use`) fehlen bestehenden Mandanten sonst, bis dieses
// Skript läuft. Rein additiv (entfernt keine bestehenden Zuordnungen).
//
// Lauf (lokal): npx tsx scripts/sync-role-permissions.ts
// Lauf (Deploy): im Container/Coolify mit gesetzter DATABASE_URL ausführen.
// WICHTIG: Betroffene Nutzer müssen sich danach neu einloggen (Rechte werden im JWT
// beim Login aufgelöst).
import "dotenv/config"; // lädt DATABASE_URL aus .env beim lokalen `npx tsx`-Lauf
import { PrismaClient } from "@prisma/client";
import { PrismaPg } from "@prisma/adapter-pg";
import { PERMISSIONS, ROLE_DEFS } from "../src/server/rbac";
const prisma = new PrismaClient({ adapter: new PrismaPg({ connectionString: process.env.DATABASE_URL }) });
async function main() {
// 1. Globalen Rechtekatalog sicherstellen.
for (const key of PERMISSIONS) {
await prisma.permission.upsert({ where: { key }, update: {}, create: { key } });
}
const permByKey = new Map((await prisma.permission.findMany()).map((p) => [p.key, p.id]));
// 2. Fehlende ROLE_DEFS-Rollen je Mandant anlegen (z. B. neue Rolle „pm").
const tenants = await prisma.tenant.findMany({ select: { id: true } });
let createdRoles = 0;
for (const tenant of tenants) {
for (const [key, def] of Object.entries(ROLE_DEFS)) {
const existing = await prisma.role.findUnique({ where: { tenantId_key: { tenantId: tenant.id, key } } });
if (!existing) {
await prisma.role.create({ data: { tenantId: tenant.id, key, name: def.name } });
createdRoles++;
console.log(` ${tenant.id}: Rolle „${key}" angelegt`);
}
}
}
// 3. Alle Rollen (mandantenübergreifend) gegen ROLE_DEFS abgleichen (Rechte + Name).
const roles = await prisma.role.findMany({ include: { rolePermissions: true } });
let addedTotal = 0;
let touchedRoles = 0;
for (const role of roles) {
const def = ROLE_DEFS[role.key as keyof typeof ROLE_DEFS];
if (!def) continue; // unbekannte/manuelle Rolle unangetastet lassen
const have = new Set(role.rolePermissions.map((rp) => rp.permissionId));
const missing = def.permissions.filter((k) => {
const id = permByKey.get(k);
return id && !have.has(id);
});
if (missing.length === 0) continue;
for (const key of missing) {
const permissionId = permByKey.get(key)!;
await prisma.rolePermission.upsert({
where: { roleId_permissionId: { roleId: role.id, permissionId } },
update: {},
create: { roleId: role.id, permissionId },
});
}
// Rollenname ebenfalls aktualisieren (falls in ROLE_DEFS geändert).
if (role.name !== def.name) await prisma.role.update({ where: { id: role.id }, data: { name: def.name } });
addedTotal += missing.length;
touchedRoles++;
console.log(` ${role.tenantId}/${role.key}: +${missing.length} Recht(e) [${missing.join(", ")}]`);
}
console.log(`\nFertig: ${createdRoles} Rolle(n) neu angelegt, ${addedTotal} Zuordnung(en) über ${touchedRoles} Rolle(n) ergänzt. Betroffene Nutzer bitte neu einloggen.`);
}
main()
.catch((e) => {
console.error("Sync fehlgeschlagen:", e.message);
process.exit(1);
})
.finally(() => prisma.$disconnect());