feat(legal): Consent-Datenmodell, Migration & Registrierungs-Zustimmung (v1.7.1)
Teil 2 des Compliance-Updates — revisionssichere Zustimmungsprotokollierung: - Prisma: Modelle LegalDocument (versioniert, contentHash, isActive, unique[type,version]) und LegalAcceptance (userId, organizationId?, documentType/-Version, contentHash, context, unique gegen Duplikate, User-Relation) - migrate.js: idempotente Tabellen + Indizes + Seeding/Aktivierung der 5 Rechtsdokumente (eine aktive Version je Typ; contentHash aus bewusster Versionsangabe) - src/lib/legal.ts: getActiveDocuments, getPendingAcceptances, recordAcceptances (skipDuplicates, nie überschreiben), Pflichtsets (alle: TERMS+PRIVACY; Org-Admin zusätzlich ORGANIZATION_DECLARATION) - API: GET /api/legal/status (offene Zustimmungen), POST /api/legal/accept (erfassen, CSRF-Check) - Registrierung: zwei getrennte, nicht vorausgewählte Zustimmungen (Nutzungsbedingungen akzeptieren + Datenschutz-Kenntnisnahme), serverseitig via zod erzwungen, Version protokolliert Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -134,10 +134,56 @@ model User {
|
||||
iconAssets IconAsset[]
|
||||
upgradeRequests UpgradeRequest[]
|
||||
rapports Rapport[]
|
||||
legalAcceptances LegalAcceptance[]
|
||||
|
||||
@@map("users")
|
||||
}
|
||||
|
||||
// ─── Rechtsdokumente & revisionssichere Zustimmungen ──────────
|
||||
// Dokumenttypen (als String gehalten, damit die idempotente Raw-SQL-Migration einfach bleibt):
|
||||
// TERMS | PRIVACY | ORGANIZATION_DECLARATION | RESPONSIBLE_USE | DATA_PROCESSING_AGREEMENT
|
||||
|
||||
model LegalDocument {
|
||||
id String @id @default(uuid())
|
||||
type String
|
||||
version String
|
||||
title String
|
||||
publishedAt DateTime @default(now())
|
||||
effectiveAt DateTime?
|
||||
contentHash String
|
||||
url String?
|
||||
isActive Boolean @default(false)
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@unique([type, version])
|
||||
@@index([type, isActive])
|
||||
@@map("legal_documents")
|
||||
}
|
||||
|
||||
model LegalAcceptance {
|
||||
id String @id @default(uuid())
|
||||
userId String
|
||||
// NULL = persönliche Zustimmung (nicht organisationsbezogen)
|
||||
organizationId String?
|
||||
documentType String
|
||||
documentVersion String
|
||||
contentHash String
|
||||
acceptedAt DateTime @default(now())
|
||||
locale String?
|
||||
// REGISTRATION | LOGIN_RECONSENT | ORGANIZATION_CREATION | ADMIN_ROLE_ACCEPTANCE | DONATION
|
||||
context String
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
|
||||
// Verhindert doppelte identische Zustimmungen; neue Version erzeugt neuen Datensatz.
|
||||
@@unique([userId, organizationId, documentType, documentVersion, context])
|
||||
@@index([userId])
|
||||
@@index([documentType, documentVersion])
|
||||
@@map("legal_acceptances")
|
||||
}
|
||||
|
||||
model TenantMembership {
|
||||
id String @id @default(uuid())
|
||||
role Role @default(OPERATOR)
|
||||
|
||||
Reference in New Issue
Block a user