syncova-policies/prisma/schema.prisma
Weapie 3633e8a4cf
All checks were successful
Container-Image bauen und veröffentlichen / build-and-push (push) Successful in 1m33s
Responsiv machen und Barrierefreiheit nach WCAG 2.1 AA herstellen
Rechtsrahmen: § 13 Abs. 3 LBGG SH i. V. m. §§ 3 und 4 BITV 2.0. Eine
Erklaerung "nicht barrierefrei" ersetzt die Herstellungspflicht nicht,
sie dokumentiert den Stand nur voruebergehend.

Farben, alle Werte gegen die WCAG-Formel nachgerechnet:
- Sekundaertext 4.40:1 auf muted-Flaechen -> 4.55:1
- Rahmen von Eingabefeldern 1.24:1 -> 3:1 (WCAG 1.4.11); dekorative
  Trenner bleiben unveraendert
- Badge-Farben scheiterten auf der eigenen 10-Prozent-Flaeche
  (brand 4.20, success 4.18, destructive 3.88) -> jeweils ueber 4.5
- Warnfarbe im Admin 3.11:1 -> amber-700 mit 4.90:1

Fokus war faktisch unsichtbar: Der Ring wurde durchgaengig mit halber
Deckkraft gezeichnet (ring-ring/50), effektiv rund 1.5:1. Jetzt volle
Deckkraft in Markenfarbe, 12 Dateien betroffen.

Weiter: Sprungmarke zum Inhalt auf allen Seiten, Suchfelder beschriftet,
Druck-Schaltflaechen hatten als reine Icon-Buttons gar keinen
zugaenglichen Namen, Liste als echte Liste ausgezeichnet, doppelter Link
je Zeile entfernt, Trefferzahl als Live-Region.

Responsiv: Aussenabstaende und Kopfzeilen ab 320 Pixel, Listenzeilen
brechen um.

Neu nach § 4 BITV 2.0: Seiten fuer Leichte Sprache und Gebaerdensprache,
im Admin pflegbar. Leer gelassen und damit noch nicht online - die
Inhalte kommen vom Amt. In der Erklaerung als bekannte Luecke benannt.

Geprueft mit axe-core (WCAG 2.1 A und AA) ueber alle oeffentlichen Seiten
und den Adminbereich, hell und dunkel, dazu Tastaturbedienung, 200
Prozent Vergroesserung und 320 Pixel Breite: keine Verstoesse, kein
waagerechter Ueberlauf.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-08 15:44:30 +02:00

134 lines
6.3 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "sqlite"
// Lokal: file:./dev.db (relativ zu diesem Verzeichnis)
// Container: file:/app/data/syncova.db
url = env("DATABASE_URL")
}
/// Standardtexte, die für alle Erklärungen gelten.
///
/// Genau ein Datensatz (id = 1). Die gleichnamigen Felder in `PrivacyPolicy`
/// sind Ausnahmen: Steht dort NULL, gilt der Standard von hier; steht dort ein
/// Wert, weicht diese eine Erklärung bewusst ab.
model PolicyDefaults {
id Int @id @default(1) // Singleton – immer 1
responsible String @default("") // Verantwortlicher im Sinne der DSGVO
contactDPO String @default("") // Kontaktdaten der/des Datenschutzbeauftragten
dataSubjectsRights String @default("") // Betroffenen-Rechte
complaintRight String @default("") // Beschwerderecht bei der Aufsichtsbehörde
withdrawalRight String @default("") // Widerrufsrecht bei Einwilligung
objectionRight String @default("") // Widerspruchsrecht (Art. 21 DSGVO)
thirdCountryTransfer String @default("") // Übermittlung in Drittländer (Art. 13 Abs. 1 lit. f)
automatedDecision String @default("") // Automatisierte Entscheidungsfindung (Art. 13 Abs. 2 lit. f)
provisionObligation String @default("") // Pflicht zur Bereitstellung der Daten
provisionConsequences String @default("") // Folgen, wenn die Daten nicht angegeben werden
updatedAt DateTime @updatedAt // Automatisch bei Update gesetzt
}
/// Inhalte der rechtlichen Seiten des Portals selbst.
///
/// Genau ein Datensatz (id = 1), gepflegt im Admin. Ein leerer Text bedeutet:
/// Die Seite wird nicht ausgeliefert und nicht in der Fußzeile verlinkt.
model SitePages {
id Int @id @default(1) // Singleton – immer 1
imprint String @default("") // Impressum (§ 5 DDG)
privacy String @default("") // Datenschutzerklärung für dieses Portal
accessibility String @default("") // Erklärung zur Barrierefreiheit (§ 7 BITV 2.0)
easyLanguage String @default("") // Erläuterungen in Leichter Sprache (§ 4 BITV 2.0)
signLanguage String @default("") // Erläuterungen in Deutscher Gebärdensprache (§ 4 BITV 2.0)
updatedAt DateTime @updatedAt // Automatisch bei Update gesetzt
}
// Datenschutzerklärung model for structured privacy policies
model PrivacyPolicy {
id Int @id @default(autoincrement()) // Auto-Increment Primary Key
slug String @unique // Bezeichner in der öffentlichen URL /erklaerung/<slug>
title String // Pflichtfeld - Title of privacy policy
// NULL = Standard aus PolicyDefaults gilt, Wert = bewusste Abweichung
responsible String? // Verantwortlicher im Sinne der DSGVO
contactDPO String? // Kontaktdaten des Datenschutzbeauftragten
dataSubjectsRights String? // Betroffenen-Rechte
complaintRight String? // Beschwerderecht bei der Aufsichtsbehörde
withdrawalRight String? // Widerrufsrecht bei Einwilligung
objectionRight String? // Widerspruchsrecht (Art. 21 DSGVO)
thirdCountryTransfer String? // Übermittlung in Drittländer (Art. 13 Abs. 1 lit. f)
automatedDecision String? // Automatisierte Entscheidungsfindung (Art. 13 Abs. 2 lit. f)
processingDescription String // Bezeichnung der Verarbeitungstätigkeit
processingPurposes String? // Zweck der Verarbeitung (Art. 13 Abs. 1 lit. c) - Pflicht zur Veröffentlichung
legalBasis String? // Rechtsgrundlage (Art. 13 Abs. 1 lit. c) - Pflicht zur Veröffentlichung
legitimateInterests String? // Berechtigte Interessen, nur bei Art. 6 Abs. 1 lit. f (Art. 13 Abs. 1 lit. d)
recipients String // Wir beabsichtigen, Ihre Daten an folgende Empfänger weiterzuleiten
storageDuration String? // Speicherdauer oder Kriterien (Art. 13 Abs. 2 lit. a) - Pflicht zur Veröffentlichung
dataSource String? // Optional - Wir haben Ihre Daten aus folgender Quelle erhalten
dataCategories String? // Kategorien der Daten (Art. 14 Abs. 1 lit. d) - Pflicht, wenn dataSource gesetzt ist
provisionObligation String? // Abweichung vom Standard - Pflicht zur Bereitstellung (Art. 13 Abs. 2 lit. e DSGVO)
provisionConsequences String? // Abweichung vom Standard - Folgen, wenn die Daten nicht angegeben werden
createdAt DateTime @default(now()) // Automatisch bei Erstellung gesetzt
updatedAt DateTime @updatedAt // Automatisch bei Update gesetzt
isPublic Boolean @default(true) // Default true, bestimmt ob die Datenschutzerklärung öffentlich sichtbar ist
}
// User model for authentication
model User {
id Int @id @default(autoincrement())
email String @unique
name String?
password String
role UserRole @default(ADMIN)
isActive Boolean @default(true)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
createdBy Int?
createdByUser User? @relation("UserCreatedBy", fields: [createdBy], references: [id])
createdUsers User[] @relation("UserCreatedBy")
// NextAuth fields
accounts Account[]
sessions Session[]
}
model Account {
id Int @id @default(autoincrement())
userId Int
type String
provider String
providerAccountId String
refresh_token String?
access_token String?
expires_at Int?
token_type String?
scope String?
id_token String?
session_state String?
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@unique([provider, providerAccountId])
}
model Session {
id Int @id @default(autoincrement())
sessionToken String @unique
userId Int
expires DateTime
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
}
model VerificationToken {
identifier String
token String @unique
expires DateTime
@@unique([identifier, token])
}
enum UserRole {
ADMIN
SUPER_ADMIN
}