# 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/ │ └── _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/_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