Auf einer leeren Datenbank brach der Start des Backends ab, damit war die Anwendung insgesamt nicht benutzbar. Zwei Ursachen, beide nur ohne bestehende pb_data sichtbar, weil angewendete Migrationen nicht erneut laufen. Erstens verwies trail_flags.deleteRule auf @collection.trail_markers, obwohl trail_markers erst danach angelegt wird. Die verschaerfte Regel war nachtraeglich in die bereits angewendete Migration eingebaut worden, zusaetzlich zu den korrekten Folgemigrationen 200/300. Hier steht nun wieder die referenzfreie Ursprungsregel; den Zielzustand setzen die Nachtraege. Zweitens enthaelt 1754400000_init_schema.js als Snapshot des Live-Schemas die trail-Collections bereits, wodurch diese Migration sie ein zweites Mal anlegte und am eindeutigen Collection-Namen scheiterte. Ein Guard ueberspringt sie, wenn trails schon existiert. Verifiziert gegen ein leeres Datenverzeichnis: alle Migrationen laufen durch, alle elf Anwendungs-Collections vorhanden, die Nachtraege korrekt im Endzustand (geklammerte deleteRule, coord_distances, avatar.maxSize), Team-Anlage als normaler User erfolgreich. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|---|---|---|
| .. | ||
| pb_hooks | ||
| pb_migrations | ||
| .env.example | ||
| .gitignore | ||
| docker-compose.yaml | ||
| Dockerfile | ||
| entrypoint.sh | ||
| README.md | ||
stammtisch-hersbruck.de — Backend (PocketBase)
PocketBase-Instanz für Events, Läufe, Fahrer, Zeiten und Teams.
Lokal starten
.env aus der Vorlage anlegen (die .env selbst steht in .gitignore):
cp .env.example .env
und die Werte eintragen — .env.example beschreibt jede Variable. Dann:
docker compose up -d --build
Admin-UI: http://127.0.0.1:8090/_/ — Login mit SUPERUSER_EMAIL/SUPERUSER_PASSWORD.
Damit das Frontend gegen diese Instanz läuft, in ../frontend/.env
PUBLIC_PB_URL=http://127.0.0.1:8090 setzen.
Schema
Das Schema liegt als versionierte Migration in pb_migrations/ und wird beim
Start automatisch angewendet. Es enthält die sechs fachlichen Collections
users, teams, events, runs, riders, times.
1754400000_init_schema.js ist ein Snapshot der produktiven Instanz. Er wurde
per GET /api/collections abgezogen und ruft importCollections mit
deleteMissing = false auf — die Migration legt an und aktualisiert, löscht
aber nichts, was nicht im Snapshot steht.
Schema-Änderungen aus dem Admin-UI holen
pb_migrations/ wird nicht in den Container gemountet — die Migrationen
kommen über COPY ins Image (siehe Dockerfile). Das ist Absicht: Ein
Bind-Mount überdeckt das Image-Verzeichnis, und auf einem Deployment-Host ohne
ausgechecktes Repo legt Docker dort ein leeres Verzeichnis an. PocketBase
findet dann keine Migration und startet mit einer Datenbank ohne Collections.
Die Kehrseite: Eine im Admin-UI erzeugte Migration liegt zunächst nur im Container und muss von Hand herausgeholt werden:
# Welche Dateien sind dazugekommen?
docker compose exec pocketbase ls /pb/pb_migrations
# Die neue Datei ins Repo kopieren und committen
docker compose cp pocketbase:/pb/pb_migrations/<datei> ./pb_migrations/
Ohne diesen Schritt ist die Änderung beim nächsten --build verloren.
Ein frisch gestarteter Container hat damit dasselbe Schema wie die produktive Instanz — aber keine Daten.
Datenpersistenz
Sämtliche Laufzeitdaten liegen in der SQLite-DB unter /pb/pb_data: Datensätze,
Uploads, die SMTP-Einstellungen und der Superuser. Ohne gemountetes Volume auf
diesem Pfad sind sie nach jedem Redeploy verloren.
Das Volume-Mapping ./pb_data:/pb/pb_data steht in der docker-compose.yaml,
damit die Persistenz-Konfiguration versioniert im Repo liegt.
Trügerisches Signal: Die Collections kommen aus der Migration und sind nach einem Redeploy auch dann da, wenn gar kein Volume existiert. Sie taugen nicht als Nachweis funktionierender Persistenz — das zeigt nur ein Datensatz, der in keiner Migration steht.
Mount prüfen:
docker inspect <container> --format '{{json .Mounts}}' | jq
Erscheint dort kein Eintrag mit "Destination": "/pb/pb_data", fehlt die Persistenz.
pb_data/ steht in .gitignore und gehört dort auch hin.
Superuser-Verhalten
entrypoint.sh ruft superuser create auf — bewusst nicht upsert.
Existiert der Account bereits, scheitert create mit „Value must be unique" und
das Passwort bleibt unangetastet. Eine im Admin-UI vorgenommene
Passwortänderung überlebt damit jeden Redeploy.
| Situation | Verhalten |
|---|---|
| Erster Start, Variablen gesetzt | Superuser wird angelegt |
| Neustart, Account existiert | „Superuser existiert bereits — Passwort bleibt unverändert" |
| Passwort im UI geändert, dann Neustart | UI-Passwort gilt weiter, Env wird ignoriert |
| Variablen nicht gesetzt | Übersprungen, PocketBase gibt Installer-Link im Log aus |
| Passwort zu kurz (< 8 Zeichen) | Container bricht mit Exitcode 1 ab |
Passwort später ändern: im Admin-UI, nicht über die Env — eine Änderung der Env-Variable hat keine Wirkung mehr, sobald der Account existiert.
PocketBase aktualisieren
Die Version ist über das Build-Arg PB_VERSION gepinnt (Dockerfile und
docker-compose.yaml). Wert hochsetzen, committen, neu bauen.
Ein latest gibt es bewusst nicht: Der GitHub-Asset heißt
pocketbase_<version>_linux_amd64.zip, enthält die Version also im Dateinamen.
Der Pin ist auch gewollt — sonst zieht jeder Rebuild unangekündigt eine neue
Version, inklusive möglicher DB-Schema-Migrationen.
Vor einem Update: Changelog prüfen
(https://github.com/pocketbase/pocketbase/releases) und pb_data sichern —
PocketBase migriert die DB beim Start automatisch, ein Downgrade ist danach
nicht mehr ohne Weiteres möglich.