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

209 lines
8.3 KiB
Markdown

# 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:
```ts
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.
**`.gitignore`** — `pb_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:
```js
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