Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Nach Block 3 kann das Ticket-System fachliche Abläufe mit Transaktionen schützen. Ein Ticket, ein Kommentar und ein Event werden gemeinsam gespeichert oder gemeinsam zurückgerollt. Das löst aber noch nicht die Frage, welche Datenzustände überhaupt gültig sein dürfen.

Genau darum geht es in diesem Block. Ein Datenbankschema ist nicht nur eine technische Ablageform. Es ist ein Teil des Softwaredesigns: Es entscheidet, welche Pflichtfelder existieren, welche Werte erlaubt sind, welche Beziehungen gültig bleiben und welche Regeln auch dann gelten, wenn Daten nicht über den normalen Service geschrieben werden.

Für Block 4 arbeitest du normalerweise auf dem Stand weiter, den du nach Block 3 erreicht hast. Falls du mitten im Modul einsteigst, nutzt du den Checkpoint block-4-start. Das Checkpoint-System und die Lösungskopien werden im separaten Abschnitt Checkpoints erklärt.

Warum Schema Design Anwendungscode entlastet

Stell dir vor, ein Ticket wird mit leerem Titel, unbekanntem Status oder doppelter externer Referenz gespeichert. Der Anwendungscode kann solche Fälle prüfen. Das reicht aber nicht immer:

PostgreSQL kann viele einfache, dauerhafte Regeln direkt im Schema erzwingen, etwa Pflichtfelder, Eindeutigkeit, Wertelisten und Beziehungen PostgreSQL Global Development Group (2026). Der Anwendungscode wird dadurch nicht überflüssig. Er kann sich stärker auf Abläufe, Fehlermeldungen und fachliche Entscheidungen konzentrieren.

Die wichtigste Frage in einem Schema Review lautet deshalb:

Welche fehlerhaften Daten dürfen gar nie dauerhaft gespeichert werden?

Technische IDs und fachliche Schlüssel

Die Spalte id in tickets ist ein technischer Primärschlüssel. Sie ist stabil, kurz, gut für Foreign Keys geeignet und für JPA/Hibernate einfach zu verwenden. Für Menschen ist sie aber selten die wichtigste Referenz.

Eine fachliche Referenz hat eine andere Rolle. Sie kann aus einem Umsystem, einem Monitoring-Tool oder einer Supportnummer stammen. Im Block-4-Lösungsstand ergänzt die Migration eine optionale Spalte:

ALTER TABLE app_starter.tickets
    ADD COLUMN external_reference TEXT;

Diese Referenz ist fachlich bedeutsam, aber nicht zwingend für jedes Ticket vorhanden. Deshalb ist sie nullable. Wenn sie vorhanden ist, soll sie aber eindeutig sein:

ALTER TABLE app_starter.tickets
    ADD CONSTRAINT tickets_external_reference_unique
    UNIQUE (external_reference);

Das ist ein typischer Unterschied:

FrageTechnische IDFachliche Referenz
Wer nutzt sie primär?Datenbank, ORM, Foreign KeysBenutzerinnen, Umsysteme, Supportprozesse
Muss sie sprechend sein?NeinOft ja
Darf sie sich ändern?Möglichst nieJe nach Fachprozess
Braucht sie Eindeutigkeit?Ja, als PrimärschlüsselHäufig, aber fachlich begründet

Ein guter Entwurf verwendet technische IDs für robuste Beziehungen und fachliche Schlüssel für fachliche Wiedererkennung. Beides ist nicht dasselbe.

Constraints als dauerhafte Schutzschicht

Constraints sind keine lästige Zusatzarbeit. Sie machen Regeln sichtbar und überprüfbar. Im Ticket-System gehören einige Regeln direkt in PostgreSQL:

ALTER TABLE app_starter.tickets
    ADD CONSTRAINT tickets_priority_check
    CHECK (priority IN ('low', 'normal', 'high', 'urgent'));

Diese Regel ist einfach, lokal und unabhängig vom konkreten HTTP-Request. Genau deshalb passt sie gut in die Datenbank.

RegelTypischer Schutz
Ticket braucht einen TitelNOT NULL plus Anwendungvalidierung
Status hat nur erlaubte WerteCHECK, Enum oder Referenztabelle
externe Referenz ist eindeutigUNIQUE
Kommentar gehört zu einem TicketForeign Key
Statuswechsel erzeugt EventService-Transaktion
geschlossenes Ticket wird nicht wieder geöffnetService-Logik

Das Schema und der Service arbeiten zusammen. PostgreSQL schützt den gültigen Datenzustand. Der Service schützt fachliche Abläufe, die mehrere Schritte, Bedingungen oder Fehlermeldungen brauchen.

Status und Werte modellieren

Für Status, Priorität oder Event-Typen gibt es mehrere Modellierungsvarianten. Keine ist immer richtig.

VarianteGeeignet, wenn ...Risiko
CHECK Constraintdie Werteliste klein und stabil istSchemaänderung nötig bei neuen Werten
PostgreSQL-EnumWerte sehr stabil und stark typisiert sindspätere Änderungen können unbequemer werden
ReferenztabelleWerte Metadaten, Sortierung oder Übersetzungen brauchenmehr Tabellen und Joins
Nur Java-EnumRegel nur im Anwendungscode sichtbar sein sollandere Schreibpfade können falsche Werte speichern

Im Block-4-Lösungsstand ist priority bewusst als TEXT mit CHECK modelliert:

ALTER TABLE app_starter.tickets
    ADD COLUMN priority TEXT;

UPDATE app_starter.tickets
SET priority = 'normal'
WHERE priority IS NULL;

ALTER TABLE app_starter.tickets
    ALTER COLUMN priority SET NOT NULL;

ALTER TABLE app_starter.tickets
    ADD CONSTRAINT tickets_priority_check
    CHECK (priority IN ('low', 'normal', 'high', 'urgent'));

Diese mehrstufige Migration ist absichtlich. Bestehende Zeilen erhalten zuerst einen gültigen Wert. Erst danach wird NOT NULL aktiviert. Das passt zum Muster aus Schema Evolution: Produktionsdaten werden nicht ignoriert, sondern mitgedacht.

Audit-Felder

Audit-Felder beantworten später einfache, aber wichtige Fragen:

Im Starter gab es bereits created_at. Block 4 ergänzt updated_at:

ALTER TABLE app_starter.tickets
    ADD COLUMN updated_at TIMESTAMPTZ;

UPDATE app_starter.tickets
SET updated_at = created_at
WHERE updated_at IS NULL;

ALTER TABLE app_starter.tickets
    ALTER COLUMN updated_at SET NOT NULL;

In der Entity wird updatedAt bei Änderungen aktualisiert:

@PreUpdate
void markUpdated() {
    updatedAt = OffsetDateTime.now();
}

Das ist für den Kurs bewusst einfach gehalten. In grösseren Systemen können Audit-Informationen auch durch Datenbank-Trigger, zentrale JPA-Auditing-Funktionen oder separate Event-Tabellen gepflegt werden. Entscheidend ist die Designfrage: Welche Nachvollziehbarkeit braucht das System später wirklich?

Soft Deletes kritisch betrachten

Ein Soft Delete löscht eine Zeile nicht physisch. Stattdessen wird sie markiert, zum Beispiel mit deleted_at:

ALTER TABLE app_starter.tickets
    ADD COLUMN deleted_at TIMESTAMPTZ;

Der Block-4-Lösungsstand ergänzt einen einfachen API-Endpunkt:

DELETE /api/tickets/{id}

Der Service setzt dabei deleted_at. Listenabfragen zeigen nur Tickets, bei denen deleted_at IS NULL gilt.

Das klingt praktisch, ist aber kein kostenloser Gewinn.

NutzenRisiko
versehentliche Löschung kann eher nachvollzogen werdenjede Query muss gelöschte Zeilen korrekt ausfiltern
Daten bleiben für Support oder Audit sichtbarUNIQUE Regeln werden schwieriger, wenn gelöschte Werte wiederverwendet werden sollen
Wiederherstellung ist möglichTabellen wachsen und werden fachlich schwerer zu lesen

Soft Delete ist deshalb eine bewusste Entscheidung, nicht ein Standardreflex. Manchmal ist ein Statuswert besser. Manchmal braucht es Archivtabellen. Manchmal ist echte Löschung mit Audit-Event die klarere Lösung.

Schema, Entity, DTO und API-Modell

Ein häufiger Fehler in Backend-Projekten ist, Schema, Entity und API-Antwort als dasselbe Modell zu behandeln. Das wirkt am Anfang bequem, erzeugt aber schnell enge Kopplung.

Im Block-4-Lösungsstand sieht man vier Sichten:

SichtAufgabe
Datenbankschemadauerhafte Struktur, Constraints, Indizes und Datenregeln
JPA-EntityMapping zwischen Java und Tabelle
Request-DTOwas ein Client beim Erstellen senden darf
Response-DTOwas die API nach aussen zurückgibt

Die Entity kennt deletedAt, weil die Anwendung diese Spalte zum Ausblenden braucht. Die API-Antwort gibt deletedAt aber nicht aus. Das ist Absicht: Die API soll nicht jedes interne Implementierungsdetail nach aussen tragen.

Diese Trennung hilft bei späteren Änderungen. Das Schema darf technische Spalten enthalten. Die Entity darf ORM-Details kennen. Die API bleibt ein bewusster Vertrag.

Review-Fragen für Schema Design

Wenn du ein Schema in einem Softwareprojekt reviewst, helfen diese Fragen:

Ausblick

Block 4 entscheidet, welche Datenzustände gültig sind. Block 5 fragt danach, wie diese Daten gezielt gelesen werden. Ein klares Schema macht Queries nicht automatisch perfekt, aber es macht sie verständlicher: Status, Priorität, fachliche Referenz und Soft-Delete-Markierung sind dann explizite Entscheidungen statt versteckte Annahmen im Code.

References
  1. PostgreSQL Global Development Group. (2026). PostgreSQL Documentation. https://www.postgresql.org/docs/