---
title: "Datenbankmigrationen"
description: "Wie das PostgreSQL-Schema von Ring bei einer frischen Installation angewendet wird, wie inkrementelle Migrationen bestehende Datenbanken erreichen und wie das zusammengeführte schema.sql neu erstellt wird"
locale: "de"
---
# Datenbankmigrationen

Ring hält sein PostgreSQL-Schema an zwei Stellen in `ring/web/data/`. `schema.sql` ist die zusammengeführte einzige Referenz für **neue** Datenbanken. `migrations/` enthält die nummerierten inkrementellen Dateien, die **bestehende** Datenbanken auf denselben Stand gebracht haben. Diese Seite erklärt, was du wann verwendest.

> **Info**
> Nutze die Tabs **Gründer** / **Entwickler** in der Seitenleiste, um diese Seite zu filtern. Gemeinsame Abschnitte gelten für beide Zielgruppen.

> **Warning**
> **Status:** `./install.sh setup-db` und `npm run db:apply-schema` schlagen in öffentlichen Checkouts derzeit fehl, weil sie Pfade suchen, die nach `web/` verschoben wurden. Außerdem enthält `schema.sql` die Zeile `CREATE EXTENSION IF NOT EXISTS postgis;`, sodass ein einfaches `psql -f data/schema.sql` auf PostgreSQL-Images ohne PostGIS (zum Beispiel `postgres:16-alpine`) mit einem Fehler abbricht. Nutze die Befehle aus Schritt 2 unten.

| Frühere Dokumentation sagte | Aktuelles Verhalten |
|-----------------|------------------|
| `schema.sql` anwenden, danach `002`, `003`, `004` der Reihe nach | Frische Installationen wenden **nur** `web/data/schema.sql` an (zusammengeführt, Version 4.1.0) |
| `./scripts/run-migration.sh` oder `apply-*-migrations-dev.sh` ausführen | Diese Hilfsskripte sind nicht im öffentlichen Baum. Nutze `psql` direkt |
| Homebrew `postgresql@18` mit einem Bootstrap-Skript installieren | Jedes PostgreSQL ab 16 funktioniert. Das Bootstrap-Skript ist Ringdom-intern |
| News aus `scripts/seed-news-v1.6.0.sql` laden | Diese Datei existiert nicht. Startdaten für Währungen, Länder, Shop-Einstellungen und News-Kategorien stehen in `schema.sql` |
| `data/schema-delta.sql` | Wird nicht verwendet. Änderungen liegen als nummerierte Dateien in `data/migrations/` |

### For founders

## Was das für deine Community bedeutet

Du musst kein SQL verstehen, um einen Ring-Klon zu betreiben. Die Regel, der dein Entwickler folgt, solltest du aber kennen: **Eine neue Datenbank bekommt eine Datei, eine bestehende Datenbank bekommt nur die neuen Dateien.** Diese Regel sorgt dafür, dass Upgrades langweilig bleiben.

  
- **[Neuer Klon](/docs/deployment/self-hosted.md)** — Eine einzige Schema-Datei legt alle Tabellen an (109 in Version 4.1.0) und dazu die Referenzdaten. Kein Nachspielen der Historie.

  
- **[Laufenden Klon aktualisieren](/docs/getting-started/troubleshooting.md)** — Dein Entwickler wendet nach einem Backup nur die nummerierten Dateien an, die deine Datenbank noch nicht kennt.

  
- **[Datenbank wählen](/docs/customization/database-selection.md)** — PostgreSQL ist das Standard-Backend für die Produktion (`k8s-postgres-fcm`).

### Typische Szenarien

- **Erster Start.** Dein Entwickler legt eine leere Datenbank an und wendet `schema.sql` an. Die Seite ist bereit für die erste Anmeldung des Admins.
- **Plattform-Upgrade.** Ein Ring-Release bringt eine Migration wie `051_likes_uci_favorites_indexes.sql`. Dein Entwickler macht ein Backup, wendet genau diese Datei an und deployt neu.
- **Nach einem Upgrade wirkt etwas falsch.** Migrationen ab `051` können eine passende `.down.sql`-Datei mitbringen, damit sich die Änderung zurücknehmen lässt. Ältere Dateien haben keine.

```mermaid
flowchart TD
  A[Datenbank] --> B{Leer?}
  B -->|Ja| C[Nur web/data/schema.sql anwenden]
  B -->|Nein| D[Backup]
  D --> E[Neue nummerierte Dateien einmal anwenden]
  E --> F[App neu deployen]
  C --> F
```

### For developers

## Aufbau von `web/data`

| Pfad | Zweck |
|------|---------|
| `data/schema.sql` | Zusammengeführte Referenz, Version 4.1.0. Legt 109 Tabellen in `public` an, dazu die Erweiterungen `uuid-ossp`, `pgcrypto` und `postgis` sowie die Referenzdaten |
| `data/migrations/NNN_*.sql` | Inkrementelle Änderungen, heute `001` bis `051` im Repository |
| `data/migrations/NNN_*.down.sql` | Optionales Rollback, vorhanden für `051` |
| `data/migrations/README.md` | Regeln für neue Migrationen. Vor dem Schreiben einer Migration lesen |
| `data/migrations/EMAIL-CRM-OPS.md` | Betriebshinweise für die Tabellen des E-Mail-CRM |

Jede nummerierte Migration im Repository bis `051` ist bereits in `schema.sql` eingeflossen. Spiele `data/migrations/*.sql` nicht auf einer leeren Datenbank nach und wende `001_email_crm_schema.sql` niemals an: Die JSONB-CRM-Tabellen aus `009` und `010` haben sie ersetzt und sind Teil von `schema.sql`.

Die App verbindet sich über `DB_HOST`, `DB_PORT`, `DB_NAME`, `DB_USER`, `DB_PASSWORD` und `DB_SSL`. `DATABASE_URL` liest sie nicht. Siehe [Umgebung](/docs/deployment/environment.md).

## Frische Installation

### Leere Datenbank anlegen

{`createdb -h localhost -U postgres ring_platform`}

Führe den nächsten Schritt als Superuser oder als Eigentümer der Datenbank aus, weil `schema.sql` Erweiterungen anlegt.

### schema.sql anwenden

Wenn auf deinem Server PostGIS installiert ist (zum Beispiel ein Image `postgis/postgis`), wende die Datei unverändert an:

{`cd ring/web
psql -h localhost -U postgres -d ring_platform \\
  -v ON_ERROR_STOP=1 -f data/schema.sql`}

Auf PostgreSQL ohne PostGIS entfernst du zuerst die PostGIS-Zeile. Keine Tabelle nutzt einen PostGIS-Typ, deshalb ändert sich sonst nichts:

{`cd ring/web
sed '/^CREATE EXTENSION IF NOT EXISTS postgis;$/d' data/schema.sql \\
  | psql -h localhost -U postgres -d ring_platform -v ON_ERROR_STOP=1`}

### Ergebnis prüfen

{`psql -h localhost -U postgres -d ring_platform \\
  -c "SELECT version, applied_at FROM schema_versions ORDER BY applied_at DESC LIMIT 5;"`}

Gib der Rolle deiner App (`DB_USER`) Zugriff auf das Schema `public` und starte dann die App.

## Bestehende Datenbank

Wende nur die Dateien an, die deine Datenbank noch nicht kennt. Einige Migrationen tragen sich mit einem `INSERT ... WHERE NOT EXISTS` in `schema_versions` ein (`016` bis `025`, `037`, `043` bis `046`, `050`, `051`). Die anderen nicht. Prüfe deshalb vor dem Anwenden, ob die Tabellen oder Indizes, die sie anlegen, schon existieren.

{`pg_dump -h localhost -U postgres -d ring_platform -Fc -f ring-before-051.dump
psql -h localhost -U postgres -d ring_platform -v ON_ERROR_STOP=1 \\
  -f data/migrations/051_likes_uci_favorites_indexes.sql`}

Um eine Migration mit Down-Datei zurückzunehmen, wende `051_likes_uci_favorites_indexes.down.sql` auf dieselbe Weise an. Sie löscht auch ihre Zeile in `schema_versions`.

## Eine Migration hinzufügen (Mitwirkende)

### Die nächste nummerierte Datei schreiben

Nimm die nächste freie Nummer nach der höchsten Datei in `data/migrations/`. Mache sie idempotent (`IF NOT EXISTS`), trage sie in `schema_versions` ein und füge eine `.down.sql` hinzu, wenn die Änderung umkehrbar ist.

### schema.sql neu zusammenführen

{`cd ring/web
npm run db:flatten-schema`}

Das führt `ring/scripts/flatten-schema-from-migrations.sh` aus. Es braucht ein lokales PostgreSQL, in dem deine Rolle Datenbanken anlegen darf (`PGHOST` und `PGUSER` sind standardmäßig `localhost` und `ring_user`). Das Skript legt die temporäre Datenbank `ring_schema_flatten` neu an, sichert `schema.sql` als `schema.sql.bak-pre-flatten-`, wendet das bisherige Schema und alle Migrationen außer `001` an, exportiert DDL und Referenzdaten und prüft das Ergebnis auf `ring_schema_flatten_verify`. Der Prüfschritt braucht PostGIS, aus dem oben genannten Grund.

## Häufige Fragen

### Auswirkungen

#### Verliere ich Daten, wenn das Schema neu zusammengeführt wird?

Nein. Das Zusammenführen schreibt nur die Datei `schema.sql` im Repository neu. Laufende Datenbanken berührt es nie.

### Migration

#### Meine Datenbank wurde aus einem alten `schema.sql` erstellt. Welche Dateien brauche ich?

Vergleiche `SELECT version FROM schema_versions` mit den nummerierten Dateien und wende die fehlenden nach einem Backup der Reihe nach an. Nur manche Dateien tragen eine Version ein (siehe Bestehende Datenbank oben). Prüfe im Zweifel also ihre Tabellen. Beachte, dass eine frische Installation aus dem heutigen `schema.sql` Versionen bis `045` anzeigt, obwohl die Tabellen und Indizes aus `046` bis `051` bereits vorhanden sind.

### Betrieb

#### Warum schlägt `CREATE EXTENSION postgis` fehl?

Dein PostgreSQL-Build enthält kein PostGIS. Entferne die Zeile wie in Schritt 2 gezeigt oder nutze ein Image mit PostGIS.

  
- [deployment/self-hosted](/docs/deployment/self-hosted.md) — Nächster Schritt: die App gegen die gerade angelegte Datenbank starten.

  
- [deployment/docker](/docs/deployment/docker.md) — Gleicher Ablauf: das Schema auf den Postgres-Container aus Compose anwenden.

  
- [architecture/backend-modes-and-databases](/docs/architecture/backend-modes-and-databases.md) — Voraussetzung: warum k8s-postgres-fcm dieses Schema braucht.

  
- [development/community-tooling](/docs/development/community-tooling.md) — Siehe auch: install.sh und die npm-Skripte für die Datenbank, einschließlich derer, die heute fehlschlagen.
