stammtisch-hersbruck/docs/superpowers/specs/2026-08-06-repo-frontend-backend-design.md
Daniel Michelberger 1061a8b9ad chore: Repo-Struktur mit frontend/ und backend/ aufsetzen
Die SvelteKit-App liegt unter frontend/, das Backend unter backend/ als
eigenständige PocketBase-Instanz mit Dockerfile, docker-compose und
versioniertem Schema.

- PocketBase-URL über PUBLIC_PB_URL konfigurierbar, Default bleibt die
  produktive Instanz https://api.stammtisch-hersbruck.de
- Schema als Snapshot-Migration der sechs fachlichen Collections
  (users, teams, events, runs, riders, times), abgezogen von der
  produktiven Instanz. Verifiziert: ein Erststart gegen leere pb_data
  legt alle sechs an, Felder und API-Rules stimmen überein.
- pb_data und pb_migrations als Bind-Mounts, damit Daten persistieren und
  im Admin-UI erzeugte Migrationen im Repo landen
- Veraltete Dokumentation entfernt: pocketbase_schema.json nannte
  Collections (stages, results, organizers), die es nicht gibt

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-06 13:16:43 +02:00

8.3 KiB

Repo-Umbau auf frontend/ und backend/

Datum: 2026-08-06 Status: Entwurf, vom Nutzer freigegeben

Ziel

Das Repository so umbauen, dass die SvelteKit-App unter frontend/ und eine eigenständige, lokal lauffähige PocketBase-Instanz unter backend/ liegt — nach dem Vorbild von therapiezentrum-fortschritt-landingpage.

Anders als beim Vorbild bleibt dies ein Monorepo: Das vorhandene .git im Root bleibt bestehen, frontend/ und backend/ sind Unterverzeichnisse ohne eigene Repos.

Ausgangslage

  • SvelteKit 5 mit Svelte-5-Runes, PocketBase als Backend
  • App liegt direkt im Repo-Root (src/, static/, scripts/, Configs)
  • Git-Repo existiert, Branch master, noch kein Commit — alles untracked
  • PocketBase läuft ausschließlich remote unter https://api.stammtisch-hersbruck.de
  • Die URL ist in src/lib/stores/pocketbase.svelte.ts:4 hartkodiert
  • Schema-Pflege bisher über scripts/migrate-schema.ts per Superuser-Token
  • Es gibt kein pb_migrations, kein pb_hooks, kein Dockerfile

Befund zum vorhandenen Schema

Der Live-Abruf über GET /api/collections liefert die fachlichen Collections users, riders, times, events, runs, teams (plus System-Collections _superusers, _externalAuths, _mfas, _otps, _authOrigins).

Die Datei pocketbase_schema.json im Root nennt dagegen zusätzlich stages, organizers und results, die live nicht existieren. Sie ist damit nachweislich veraltet. Maßgeblich ist der Live-Stand — er deckt sich mit den vorhandenen Stores unter src/lib/stores/.

Zielstruktur

stammtisch-hersbruck.de/          ← .git bleibt hier (Monorepo)
├── CLAUDE.md
├── README.md
├── .gitignore
├── docs/superpowers/{specs,plans}/
├── frontend/
│   ├── src/  static/  scripts/
│   ├── package.json  package-lock.json  .npmrc
│   ├── svelte.config.js  vite.config.ts  tsconfig.json
│   ├── components.json
│   ├── .env  .env.example  .gitignore
│   └── README.md
└── backend/
    ├── Dockerfile  docker-compose.yaml  entrypoint.sh
    ├── .env.example  .gitignore  README.md
    ├── pb_migrations/
    │   └── <ts>_init_schema.js
    ├── pb_hooks/          (leer, .gitkeep)
    └── pb_data/           (gitignored, entsteht beim ersten Start)

Umsetzung

1. Frontend verschieben

Alle App-Dateien nach frontend/ verschieben: src/, static/, scripts/, package.json, package-lock.json, .npmrc, svelte.config.js, vite.config.ts, tsconfig.json, components.json, .env.

node_modules/ und .svelte-kit/ werden nicht verschoben, sondern gelöscht und in frontend/ per npm ci neu erzeugt — verschobene node_modules enthalten absolute Pfade in Binaries und Caches.

Keine Config braucht eine Pfadanpassung: Alle Pfade in svelte.config.js, vite.config.ts und tsconfig.json sind relativ zum jeweiligen Projekt-Root. Die Scripts unter scripts/ lesen .env relativ zum Arbeitsverzeichnis und laufen über npm-Scripts, also aus frontend/ heraus — sie funktionieren unverändert.

2. PocketBase-URL konfigurierbar machen

src/lib/stores/pocketbase.svelte.ts verwendet statt der hartkodierten URL:

import { PUBLIC_PB_URL } from '$env/static/public'
export const api = new PocketBase(PUBLIC_PB_URL) as TypedPocketBase

In frontend/.env und frontend/.env.example:

PUBLIC_PB_URL=https://api.stammtisch-hersbruck.de

Der Default bleibt damit die Remote-Instanz — nichts am bisherigen Verhalten ändert sich. Für Arbeit gegen das lokale Backend wird die Variable auf http://127.0.0.1:8090 gesetzt.

Die bestehenden Variablen PB_TYPEGEN_URL, PB_TYPEGEN_TOKEN und PB_SUPERUSER_TOKEN bleiben unverändert in .env (Typgenerierung und Migrations-Scripts).

3. Backend aufsetzen

Übernommen aus dem Vorbild, projektspezifisch angepasst:

Dockerfile — Alpine-Basis, PocketBase über Build-Arg PB_VERSION gepinnt, kopiert pb_migrations/ und pb_hooks/, startet über entrypoint.sh mit serve --http=0.0.0.0:8090 --dir=/pb/pb_data.

docker-compose.yaml — Volume ./pb_data:/pb/pb_data für Persistenz, restart: unless-stopped, Healthcheck gegen /api/health, Port 8090. Env: SUPERUSER_EMAIL, SUPERUSER_PASSWORD, PB_VERSION.

Die TZF-spezifischen Notify-Variablen (TZF_NOTIFY_EMAIL*, TZF_DASHBOARD_URL) entfallen — dieses Projekt hat keine Mail-Hooks.

entrypoint.sh — legt den Superuser über superuser create an, bewusst nicht upsert: Existiert der Account schon, scheitert create mit „must be unique" und ein im Admin-UI geändertes Passwort überlebt jeden Redeploy. Ohne gesetzte Variablen wird der Schritt übersprungen und PocketBase gibt seinen Installer-Link im Log aus. Da PocketBase auch im Fehlerfall Exitcode 0 liefert, wird die Ausgabe ausgewertet, nicht der Status.

.gitignorepb_data/, *.db, .env, .env.* (Ausnahme .env.example).

README.md — lokaler Start, Schema-Verwaltung, Persistenz-Hinweise, Superuser-Verhalten, Update der PocketBase-Version.

4. Schema-Migration erzeugen

Aus dem Live-Export entsteht eine Snapshot-Migration backend/pb_migrations/<timestamp>_init_schema.js nach dem PocketBase-Muster:

migrate((app) => {
    app.importCollections(JSON.stringify([ /* Collections */ ]), false)
}, (app) => { /* down: Collections wieder entfernen */ })

Enthalten sind die sechs fachlichen Collections users, teams, riders, events, runs, times mit ihren Feldern, API-Rules und Indizes. System-Collections (_superusers, _mfas, _otps, _externalAuths, _authOrigins) bleiben außen vor — PocketBase legt sie selbst an.

importCollections mit deleteMissing = false, damit die Migration nichts löscht, was nicht im Snapshot steht.

Ergebnis: Ein frisch gestarteter Container hat dasselbe Schema wie die Live-Instanz, ohne deren Daten.

Die Migration wird nicht gegen die Live-Instanz angewendet — sie beschreibt nur den Zustand, den ein neuer Container herstellen soll.

5. Altlasten entfernen

Gelöscht werden (alle untracked, also unwiederbringlich):

  • pocketbase_schema.json — veraltet (siehe Befund oben), abgelöst durch die Migration
  • example_pb_schema.json — Beispieldatei ohne Bezug zum Projekt
  • pocketbase_migrate.zip — altes pb_data von 2023 inkl. Bilddaten, gehört nicht ins Repo

IMPLEMENTATION_SUMMARY.md, POCKETBASE_SCHEMA.md, README_SETUP.md und UML_basic.png bleiben zunächst im Root erhalten.

6. Root-Dateien anpassen

  • .gitignore im Root: ergänzt um frontend/node_modules/, frontend/.svelte-kit/, frontend/build/, backend/pb_data/, .env, .env.* mit Ausnahme .env.example. Wichtig: frontend/.env enthält PB_SUPERUSER_TOKEN und darf nicht in den Commit gelangen — das wird vor dem Commit über git status geprüft.
  • CLAUDE.md: Pfadangaben auf die neue Struktur umstellen (Dev-Commands laufen aus frontend/), Abschnitt zum Backend ergänzen
  • README.md im Root: kurze Übersicht beider Teile

7. Erster Commit

Das Repo hat noch keinen Commit. Die fertige Struktur wird als initialer Commit angelegt — der Umbau erscheint damit nicht als Verschiebung in der Historie, sondern die Struktur steht von Anfang an richtig da.

Kein git push — der bleibt ausdrücklicher Anweisung vorbehalten.

Verifikation

Der Umbau gilt als erfolgreich, wenn:

  1. cd frontend && npm ci fehlerfrei durchläuft
  2. cd frontend && npm run check ohne neue Fehler durchläuft (Vergleich gegen den Stand vor dem Umbau — bestehende Fehler zählen nicht als Regression)
  3. cd frontend && npm run dev startet und die App unter http://stammtisch-hersbruck.de.localhost:31337 lädt und Daten von der Remote-Instanz zeigt
  4. cd backend && docker compose up -d --build startet und curl http://127.0.0.1:8090/api/health antwortet
  5. Im lokalen Admin-UI sind die sechs Collections mit ihren Feldern vorhanden

Punkt 4 und 5 setzen ein lauffähiges Docker voraus; ist das nicht verfügbar, wird das ausdrücklich als ungeprüft berichtet statt als erledigt.

Bewusst nicht Teil dieses Umbaus

  • Keine Änderung an der Live-Instanz oder deren Daten
  • Keine Datenmigration ins lokale Backend
  • Kein Deployment-Setup (Coolify o. ä.)
  • Keine pb_hooks — das Verzeichnis wird leer angelegt
  • Kein Ablösen von scripts/migrate-schema.ts; das Script bleibt vorerst unverändert im Frontend