gdpr audit implemented, email log, vollmachten, pdf delete cancel data privacy and vollmachten, removed message no id card in engergy car, and other contracts that are not telecom contracts, added insert counter for engery

This commit is contained in:
2026-03-21 11:59:53 +01:00
parent 89cf92eaf5
commit f2876f877e
1491 changed files with 265550 additions and 1292 deletions
+148 -4
View File
@@ -1,5 +1,6 @@
import { PrismaClient } from '@prisma/client';
import bcrypt from 'bcryptjs';
import crypto from 'crypto';
const prisma = new PrismaClient();
@@ -26,6 +27,9 @@ async function main() {
// Spezial-Permissions
developer: ['access'],
emails: ['delete'],
// DSGVO & Audit
audit: ['read', 'export', 'admin'],
gdpr: ['export', 'delete', 'admin'],
};
const permissions: { resource: string; action: string }[] = [];
@@ -60,10 +64,42 @@ async function main() {
(p) => p.resource === 'providers' && p.action === 'read'
);
// Helper: Sync permissions for a role (adds missing, removes excess)
async function syncRolePermissions(roleId: number, permissionIds: number[]) {
const existing = await prisma.rolePermission.findMany({
where: { roleId },
select: { permissionId: true },
});
const existingIds = new Set(existing.map((e) => e.permissionId));
const targetIds = new Set(permissionIds);
// Add missing permissions
const missing = permissionIds.filter((id) => !existingIds.has(id));
if (missing.length > 0) {
await prisma.rolePermission.createMany({
data: missing.map((permissionId) => ({ roleId, permissionId })),
skipDuplicates: true,
});
console.log(`${missing.length} Permissions hinzugefügt für Rolle #${roleId}`);
}
// Remove excess permissions
const excess = existing.filter((e) => !targetIds.has(e.permissionId)).map((e) => e.permissionId);
if (excess.length > 0) {
await prisma.rolePermission.deleteMany({
where: { roleId, permissionId: { in: excess } },
});
console.log(`${excess.length} Permissions entfernt für Rolle #${roleId}`);
}
}
// Create roles
// Admin - all permissions EXCEPT developer:access (that's controlled separately)
// Admin - all permissions EXCEPT developer:access and audit/gdpr (controlled separately via checkboxes)
const adminPermissions = allPermissions.filter(
(p) => !(p.resource === 'developer' && p.action === 'access')
(p) =>
!(p.resource === 'developer' && p.action === 'access') &&
p.resource !== 'audit' &&
p.resource !== 'gdpr'
);
const adminRole = await prisma.role.upsert({
where: { name: 'Admin' },
@@ -76,8 +112,10 @@ async function main() {
},
},
});
await syncRolePermissions(adminRole.id, adminPermissions.map((p) => p.id));
// Developer - ALL permissions including developer:access
// Developer - ALL permissions (developer:access + alles andere)
const developerPermissions = allPermissions;
const developerRole = await prisma.role.upsert({
where: { name: 'Developer' },
update: {},
@@ -85,10 +123,28 @@ async function main() {
name: 'Developer',
description: 'Voller Zugriff inkl. Entwickler-Tools',
permissions: {
create: allPermissions.map((p) => ({ permissionId: p.id })),
create: developerPermissions.map((p) => ({ permissionId: p.id })),
},
},
});
await syncRolePermissions(developerRole.id, developerPermissions.map((p) => p.id));
// DSGVO - audit and gdpr permissions (hidden role, controlled via hasGdprAccess)
const gdprPermissions = allPermissions.filter(
(p) => p.resource === 'audit' || p.resource === 'gdpr'
);
const gdprRole = await prisma.role.upsert({
where: { name: 'DSGVO' },
update: {},
create: {
name: 'DSGVO',
description: 'DSGVO-Zugriff: Audit-Logs und Datenschutz-Verwaltung',
permissions: {
create: gdprPermissions.map((p) => ({ permissionId: p.id })),
},
},
});
await syncRolePermissions(gdprRole.id, gdprPermissions.map((p) => p.id));
// Employee - full access to customers, contracts, read access to lookup tables
const employeePermIds = allPermissions
@@ -119,6 +175,7 @@ async function main() {
},
},
});
await syncRolePermissions(employeeRole.id, employeePermIds);
// Read-only employee - read access to main entities and lookup tables
const readOnlyResources = [
@@ -146,6 +203,7 @@ async function main() {
},
},
});
await syncRolePermissions(readOnlyRole.id, readOnlyPermIds);
// Customer role - read own data only (handled in middleware)
const customerRole = await prisma.role.upsert({
@@ -159,6 +217,7 @@ async function main() {
},
},
});
await syncRolePermissions(customerRole.id, readOnlyPermIds);
console.log('Roles created');
@@ -346,6 +405,91 @@ async function main() {
console.log('App settings created');
// ==================== AUDIT RETENTION POLICIES (DSGVO) ====================
// Standard-Policy (ohne Sensitivity)
const existingDefault = await prisma.auditRetentionPolicy.findFirst({
where: { resourceType: '*', sensitivity: null },
});
if (!existingDefault) {
await prisma.auditRetentionPolicy.create({
data: {
resourceType: '*',
sensitivity: null,
retentionDays: 3650, // 10 Jahre
description: 'Standard-Aufbewahrungsfrist',
legalBasis: 'AO §147, HGB §257',
},
});
}
// Spezifische Policies mit Sensitivity
const specificPolicies = [
{
resourceType: 'Authentication',
sensitivity: 'CRITICAL' as const,
retentionDays: 730, // 2 Jahre
description: 'Login-Versuche und Authentifizierung',
legalBasis: 'Sicherheitsanforderungen',
},
{
resourceType: 'Customer',
sensitivity: 'HIGH' as const,
retentionDays: 3650, // 10 Jahre
description: 'Kundendaten-Zugriffe',
legalBasis: 'Steuerrecht (AO §147)',
},
{
resourceType: 'Contract',
sensitivity: 'MEDIUM' as const,
retentionDays: 3650, // 10 Jahre
description: 'Vertragsdaten-Zugriffe',
legalBasis: 'Steuerrecht (AO §147)',
},
{
resourceType: 'AppSetting',
sensitivity: 'LOW' as const,
retentionDays: 1095, // 3 Jahre
description: 'Allgemeine Einstellungen',
legalBasis: 'Verjährungsfrist (BGB §195)',
},
];
for (const policy of specificPolicies) {
await prisma.auditRetentionPolicy.upsert({
where: {
resourceType_sensitivity: {
resourceType: policy.resourceType,
sensitivity: policy.sensitivity,
},
},
update: {
retentionDays: policy.retentionDays,
description: policy.description,
legalBasis: policy.legalBasis,
},
create: policy,
});
}
console.log('Audit retention policies created');
// ==================== CONSENT HASH FÜR BESTEHENDE KUNDEN ====================
const customersWithoutHash = await prisma.customer.findMany({
where: { consentHash: null },
select: { id: true },
});
for (const c of customersWithoutHash) {
await prisma.customer.update({
where: { id: c.id },
data: { consentHash: crypto.randomUUID() },
});
}
if (customersWithoutHash.length > 0) {
console.log(`ConsentHash für ${customersWithoutHash.length} Kunden generiert`);
}
console.log('Seeding completed!');
}