Damit eine frische Instanz die Collection direkt aus dem Snapshot
bekommt und die Typen aus derselben versionierten Quelle entstehen wie
das Schema.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P32KoesVtABd6xWsqMKzhr
Bisher legte die Teamleitung jedem Fahrer von Hand ein Konto an und gab
das Passwort weiter. Bei zwanzig Leuten in einer WhatsApp-Gruppe ist ein
Link die kuerzere Strecke.
Die oeffentliche Seite der Einladung laeuft ueber eigene Routen in
pb_hooks, nicht ueber die Collection: Ohne Login ist dort nichts
sichtbar, auch nicht mit Token. Der Token kommt vom Server, ein
mitgeschickter wird abgewiesen.
Dazu der Login-Vorspann vor jeder Regel, die @request.auth.id erwaehnt.
Das ist ein Loch und keine Kosmetik: Eine leere Relation ist in
PocketBase gleich dem leeren @request.auth.id einer anonymen Anfrage —
ein Team ohne Admins stuende sonst offen im Netz.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P32KoesVtABd6xWsqMKzhr
Damit sind alle offenen Punkte aus TODO.md gebaut.
Fahrer gehoeren ab jetzt dem Team, nicht mehr einem Event. Wer bei einem
Termin dabei ist, steht in event_participants - dort haengt auch die
Startnummer, denn die gilt je Event: Derselbe Fahrer kann in zwei Rennen
zwei Nummern haben und beim Stammtisch gar keine. Die vorhandenen Daten
wandern in der Migration mit.
Events tragen zwei Schalter. timing blendet Runs und Zeitnahme ein - der
woechentliche Stammtisch braucht sie nicht. participation regelt, wie man
dazukommt: offen (jeder traegt sich selbst ein), bestaetigung (Anmeldung,
Ersteller oder Team-Admin bestaetigt) oder geschlossen. Durchgesetzt wird
das serverseitig, nicht nur im Formular.
Serien erzeugen echte Einzeltermine statt einer Wiederholungsregel, aus der
Termine nur gerechnet werden. Nur so laesst sich beantworten, wer am 12.
kommt, und nur so faellt eine einzelne Woche aus. Gerechnet wird auf
Kalendertagen: ueber die Zeitumstellung hinweg kippte ein Termin sonst auf
den Vortag - dafuer gibt es einen Test.
Ausserdem: Teammitglieder duerfen den Zustand eines Trails melden. Die Regel
gibt genau die drei Statusfelder frei und schliesst jedes andere aus; ohne
das haette man Mitgliedern das ganze Objekt oeffnen muessen. Und bestehende
Konten lassen sich wieder per E-Mail ins Team holen, wofuer users.listRule
sich oeffnet.
Die neuen Regeln sind ungetestet - weder Docker noch eine lokale
PocketBase-Instanz standen zur Verfuegung. TODO.md sagt, was nach dem Deploy
durchzuspielen ist.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014dh9W1i7aLSdPYJzQPid5o
teams.logo nimmt eine Datei auf; hochgeladen wird sie in den
Team-Einstellungen. Ohne eigenes Logo bleibt das Wappen aus static/ als
Rueckfalloption - fuer den Stammtisch Hersbruck aendert sich damit nichts,
fuer jedes weitere Team waere es fremdes Vereinswappen gewesen.
Dasselbe Logo liegt gedreht und sehr blass in der rechten unteren Ecke der
Seite. Es haengt fest im Bildschirm, faengt keine Klicks ab und ist fuer
Screenreader nicht vorhanden; im Dunkelmodus etwas kraeftiger, sonst
verschwaende es im dunklen Grund.
In TODO.md ausserdem der Plan fuer Ausfahrten: Sie werden kein zweites
Konzept neben Events, sondern Schalter daran - timing, participation
(offen/bestaetigung/geschlossen) und Serien, die echte Einzeltermine
erzeugen.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014dh9W1i7aLSdPYJzQPid5o
Die Rolle superadmin kommt als Feld an users, der erste ist
stammtisch@dne.name. Vergeben wird sie nur in PocketBase: Die updateRule
schliesst das Feld ueber @request.body.superadmin:isset = false aus, sonst
koennte sich jeder selbst befoerdern - jeder darf schliesslich seinen
eigenen Datensatz aendern. Besondere Rechte in der App haengen noch nicht
daran.
Flag-Typen bleiben ausdruecklich Sache der Teams. Ein neues Team bekommt
beim Anlegen den hartkodierten Standardsatz aus der App und kann ihn danach
frei aendern; eine appweite Verwaltung entfaellt damit. Ein Team ohne
Flag-Typen koennte zwar Marker aufnehmen, aber nichts einordnen.
Im Kopf stehen Avatar und Name links, Design-Umschalter und Logout rechts.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014dh9W1i7aLSdPYJzQPid5o
Auf dem Trail passt nicht immer ein vorgefertigter Typ - "Wespennest am
Anlieger" legt niemand vorher an. Der Marker-Dialog fuehrt deshalb ein
Dropdown, dessen erste Zeile "Eigener Typ" ist und ein Textfeld oeffnet.
Das Icon steht ab jetzt am Marker selbst. Ein gewaehlter Typ schlaegt seines
vor, ueberschreiben laesst es sich jederzeit: Dieselbe Art Hindernis sieht
nicht immer gleich aus. Der Picker ist deshalb immer sichtbar und wandert
als eigene Komponente auch in die Flag-Verwaltung.
Schema: trail_markers.flag ist nicht mehr Pflicht, dafuer gibt es label und
icon. Bestehende Marker bleiben gueltig - ohne eigene Angaben faellt die
Anzeige auf den Typ zurueck.
Damit braucht ein Trail auch keine Flag-Typen mehr, um ueberhaupt Meldungen
aufnehmen zu koennen.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014dh9W1i7aLSdPYJzQPid5o
Drei Migrationen, dazu der Snapshot in 1754400000_init_schema.js, aus dem
die TypeScript-Typen erzeugt werden - beide muessen zusammenpassen, sonst
laufen Schema und Typen auseinander.
riders.user verknuepft einen Fahrer mit einem Login, ohne cascadeDelete:
Ein geloeschtes Konto darf keine Zeiten mitreissen. Anlegen, Aendern und
Loeschen von Fahrern wird zur Sache der Teamleitung; bisher durfte das
jedes Teammitglied.
users.viewRule von "nur ich selbst" auf "eingeloggt" - ohne das laesst sich
zu einer bekannten ID kein Name anzeigen, was Mitgliederliste,
Fahrerkonten und den Melder eines Trail-Markers betrifft. Die listRule
bleibt eng, E-Mails bleiben ueber emailVisibility verborgen. users.createRule
erlaubt eingeloggten Nutzern das Anlegen von Konten, nicht der ganzen Welt.
events verliert status und bekommt starts/ends. Der Status war Handarbeit:
Wer vergass, ein Event abzuschliessen, hatte eine falsche Uebersicht. Ein
Datum weiss von selbst, was ansteht, laeuft und vorbei ist. ACHTUNG: Die
Migration entfernt das Feld samt seiner Werte.
trails bekommt status_changed und status_by. Einer Sperrung soll man
ansehen, ob sie von heute Morgen oder vom letzten Herbst ist.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014dh9W1i7aLSdPYJzQPid5o
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>
elevation enthält einen Eintrag pro Originalpunkt, geojson.coordinates
nur die per Douglas-Peucker vereinfachten Punkte. Ein gemeinsamer Index
zeigte deshalb ab rund 3 % des Profils auf das Streckenende. Die neue
Distanz-Kopplung nutzt coord_distances (kumulative Distanz je
vereinfachter Koordinate), um beim Überfahren des Höhenprofils die
nächstgelegene Stelle auf der Karte zu finden.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NBMBfip6BAG8VV9raSf6vu
&& bindet stärker als || — ohne Klammern galt die
Marker-Referenzprüfung nur für den admins-Zweig. Ein Team-Owner konnte
dadurch einen noch von Markern referenzierten Flag-Typ löschen und
verwaiste Marker hinterlassen.
Klammerung in 1754500000_created_trails.js korrigiert, damit ein
Neuaufbau der Datenbank die richtige Regel von Anfang an bekommt.
1754500200_trail_flags_delete_rule.js (bereits mit der fehlerhaften
Regel angewendet) inhaltlich ebenfalls korrigiert, und eine neue
Migration 1754500300_trail_flags_delete_rule_precedence.js trägt die
Korrektur für bestehende Instanzen nach. Snapshot aktualisiert.
trail_markers.flag ist required, hatte aber cascadeDelete: false — beim
Löschen eines Flag-Typs blieben Marker mit toter Referenz zurück. Die
deleteRule von trail_flags verbietet das Löschen jetzt, solange noch
Marker den Typ referenzieren.
1754500000_created_trails.js wurde direkt angepasst, damit ein Neuaufbau
der DB die Regel von Anfang an enthält. Da die Migration lokal bereits
angewendet war, trägt 1754500200_trail_flags_delete_rule.js dieselbe
Änderung für bestehende Instanzen nach. Snapshot in
1754400000_init_schema.js entsprechend aktualisiert.
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>