All checks were successful
Container-Image bauen und veröffentlichen / build-and-push (push) Successful in 1m33s
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>
134 lines
6.3 KiB
Plaintext
134 lines
6.3 KiB
Plaintext
// 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
|
||
} |