Ohne hinterlegtes Bild stehen Initialen auf einem Farbton, der sich aus der
User-ID errechnet: Derselbe Mensch bekommt ueberall dasselbe Bild, ohne dass
es irgendwo gespeichert werden muss. Bewusst kein externer Avatar-Dienst -
der wuerde bei jedem Seitenaufruf verraten, wer hier unterwegs ist.
Kommentare zeigen jetzt ihren Verfasser, aber nur als Bild; der Name steht
im Tooltip. In einer schmalen Spalte neben der Karte ist fuer mehr kein
Platz.
Verwendet wird der Avatar ausserdem in der Kopfzeile, im Profil und in der
Mitgliederliste.
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
Der Kopf traegt jetzt Name, Zustand und Kennzahlen: Der Status sitzt als
farbiges Dropdown direkt hinter dem Namen und nennt darunter, wann und von
wem er gemeldet wurde. Laenge und Hoehenmeter stehen mit Icons daneben.
Karte und Hoehenprofil links, Marker, Kommentare und Versionen rechts
daneben in einer Spalte. Die Reiter entfallen - alles ist gleichzeitig zu
sehen. Versionen sind Archiv und deshalb eingeklappt; der GPX-Upload sitzt
dort statt im Kopf.
Marker lassen sich jetzt auch loeschen und auch ueber das Hoehenprofil
setzen: Die angeklickte Stelle wird auf dieselbe Linie zurueckgerechnet,
die ein Klick auf der Karte trifft.
Die Flag-Icons wurden bisher gespeichert, aber nirgends gezeichnet. Sie
erscheinen jetzt in der Karte, im Popup, in der Markerliste und in der
Verwaltung. Erlaubt ist jeder Name von lucide.dev - moeglich macht das ein
Glob ueber die Icon-Dateien, der jedes Icon zu einem eigenen, erst bei
Bedarf geladenen Chunk macht. Die Liste im Dialog sind nur Vorschlaege.
Die Karte kommt von CARTO statt von OSM direkt: zurueckhaltend gezeichnet,
sodass die Trail-Linie darueber steht, und mit einer echten dunklen
Fassung. Das vorherige Abdunkeln der OSM-Kacheln ergab nur ein dunkleres
Bild, keine dunkle Karte. In der Kachelvorschau der Liste sind Zoom,
Massstab und Quellenangabe abgeschaltet - dort ist die Karte Bild, nicht
Werkzeug; die grosse Karte traegt die Angabe weiterhin.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014dh9W1i7aLSdPYJzQPid5o
Die Einstellungen bekommen Reiter: Profil, Team, Fahrer (nur Teamleitung)
und Flag-Typen. /dashboard/teams wandert dorthin.
Neu ist die Hauptroute Fahrer - das Verzeichnis des Teams, fuer alle
sichtbar und fuer niemanden dort aenderbar. Angelegt, geaendert und mit
einem Konto verknuepft wird in den Einstellungen; serverseitig setzen das
die neuen Regeln der Collection durch.
Ein Fahrer bekommt sein Login entweder aus den vorhandenen Teammitgliedern
oder direkt neu angelegt. Die Einladung per E-Mail-Suche entfaellt: Sie
konnte nie funktionieren, weil users.listRule nur den eigenen Datensatz
freigibt - daher auch die abgeschnittenen IDs in der alten Mitgliederliste.
Events zeigen statt eines Status ihr Datum, mit Checkbox fuer mehrtaegig.
Gespeichert wird ein Enddatum nur, wenn es sich vom Beginn unterscheidet -
es ist damit zugleich das Kennzeichen fuer mehrtaegig statt einer zweiten
Wahrheit ueber dieselbe Sache. Listen gruppieren nach laufend, anstehend,
ohne Termin und vorbei.
Im Kopf teilen sich Name, Design-Umschalter und Logout eine Zeile, das
Team-Dropdown sitzt darunter; das Logo passt jetzt in die Leiste, statt
beschnitten zu wirken.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014dh9W1i7aLSdPYJzQPid5o
Start und Stopp laufen ausschliesslich ueber TimeDialog. Der fuehrt immer
beide Angaben - Fahrer und Run -, auch wenn eine davon aus dem Kontext
vorbelegt ist: Beim Stoppen an der Strecke soll kein Zweifel bleiben, wen
man gerade erwischt.
DNF fragt nach, bevor es schreibt. Eine Zeit ohne Wertung laesst sich nicht
zurueckholen, ein Fehlgriff waere also endgueltig.
Tabelle und Toast-Leiste zeigen damit nur noch an; ihre Knoepfe oeffnen den
Dialog mit passender Vorbelegung. Der alte Stopp-Dialog und der
Fahrerlisten-Start entfallen - beides waren Ein-Tipp-Aktionen und damit
genau das, was hier nicht mehr sein soll.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014dh9W1i7aLSdPYJzQPid5o
Die eigene Karte "Laufende Zeiten" entfaellt: Laufende stehen jetzt oben in
derselben Tabelle wie die gewerteten, mit "laeuft"-Badge statt Platzziffer.
Die Zeile ist Klickziel fuer den Stopp-Dialog, der Knopf daneben macht sie
auch per Tastatur bedienbar.
Neu ist eine dauerhaft sichtbare Leiste ueber allen Dashboard-Seiten,
solange irgendwo eine Zeit laeuft - bei mehreren eingeklappt mit Anzahl und
laengster Zeit, aufklappbar. Damit bleibt die Uhr im Blick, waehrend man
zwischen zwei Startern woanders unterwegs ist.
Der Stopp-Dialog wandert dafuer in eine eigene Komponente, die sich
Run-Seite und Leiste teilen, statt die Logik zweimal zu haben.
Monospace faellt appweit weg; einzige Ausnahme bleibt die grosse mitlaufende
Uhr im Stopp-Dialog. tabular-nums bleibt stehen: gleich breite Ziffern
derselben Schrift, ohne die eine laufende Uhr bei jedem Zehntel springt.
Tabellenkoepfe hatten den Hover-Hintergrund der Body-Zeilen geerbt; die
Regel sitzt jetzt im thead und gilt fuer alle Tabellen der App.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014dh9W1i7aLSdPYJzQPid5o
Die Routen /dashboard/timing und /dashboard/results entfallen samt ihrer
Menueeintraege. Beides passiert jetzt dort, wo es hingehoert: am Run
innerhalb seines Events.
Die Run-Seite zeigt laufende Zeiten in Echtzeit, jede Zeile ist Klickziel
fuer den Stopp-Dialog (Stoppen oder DNF). Gestartet wird ueber einen Dialog
mit Fahrersuche. Dazu Rangliste mit CSV-Export und ein Abschnitt fuer
Zeiten ohne Wertung.
Die Fahrer-Seite zeigt alle Runs des Events aus Sicht eines Fahrers, mit
Zeit, Status und Platz - auch Runs ohne Zeit, damit sichtbar bleibt, was
fehlt.
enrich() im times-Store nimmt now als Parameter: Ohne das waere Date.now()
fuer Svelte keine Abhaengigkeit und laufende Zeiten stuenden still. Der
neue ticker() liefert diesen Wert, wodurch die {#key tick}-Bloecke der
alten Zeitnahmeseite entfallen.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014dh9W1i7aLSdPYJzQPid5o
Die Trail-Linie ist jetzt selbst die Bedienflaeche: Eine unsichtbare breite
Kopie der Linie faengt Hover und Klick ab, deshalb kann daneben gar nichts
mehr passieren. Geklickte Punkte werden auf die Linie projiziert, der
Setzmodus samt Button entfaellt.
Beim Ueberfahren wandert der Punkt in Karte und Hoehenprofil synchron mit,
inklusive Anzeige von Hoehe und Streckenkilometer. Die Kopplung laeuft in
beide Richtungen ueber die Distanz und interpoliert zwischen den
Stuetzpunkten, statt zum naechsten Vertex zu springen.
Ein Klick auf einen vorhandenen Marker oeffnet kein Setzen-Fenster mehr,
sondern ein Popup mit Typ, Notiz, Zeitpunkt und Melder. Fremde User-Namen
bleiben vorerst verborgen, weil users.listRule nur den eigenen Datensatz
freigibt.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014dh9W1i7aLSdPYJzQPid5o
Auf der Login-Karte steht jetzt das Logo an Stelle des Titels "Zeitnahme",
ebenso entfaellt der Name im Seitentitel. Im Header stand ohnehin nur das
Logo, dort war nichts zu entfernen.
Logo.svelte nimmt dafuer eine class-Prop entgegen, damit dieselbe
Komponente im Header und auf der Login-Karte in unterschiedlicher Groesse
verwendet werden kann; der bisherige Default w-24 h-24 bleibt, der Header
aendert sich also nicht. Die Bilder skalieren nun ueber h-full w-full mit
dem Container statt ueber die nie gueltige Klasse "-24".
"Zeitnahme" als Bezeichnung der Funktion (Navigation, Ueberschrift der
Timing-Seite, Buttons) bleibt bestehen — entfernt wurde nur der
Produktname.
Verifiziert: svelte-check ohne Fehler, Login-Seite im Browser geprueft,
Logo in beiden Groessen isoliert gerendert.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
/dashboard/settings/flags war nur über einen Link im Leerzustand
verlinkt — sobald ein Team einen Flag-Typ hat, verschwand der einzige
Weg dorthin. Neuer Navigationspunkt "Einstellungen" im Dashboard-Menü.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NBMBfip6BAG8VV9raSf6vu
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
- Ersetze native confirm() durch app.confirm.request() mit themingfähigem Dialog
- Erweitere Fehlermeldung beim Löschen mit Hinweis auf Marker-Abhängigkeiten
- Validiere Hex-Farben (#rrggbb) vor dem Speichern
- Konsistenz mit Projektmuster (events, runs, riders, times)
Die Flag-Verwaltungsseite ermöglicht Team-Admins und -Besitzern, die Marker-Typen
für Trails zu erstellen, bearbeiten und zu löschen. Einfache Mitglieder sehen die
Flags nur. Hinweistexte informieren über Berechtigungen und ermöglichen Nicht-Admins,
die Benutzeroberfläche zu verstehen.
DOMPurify filtert trail.description vor {@html}, da nur Paten/Admins das
editor-Feld setzen dürfen, ungefiltert aber Skriptcode bei allen
Team-Mitgliedern ausführen könnte. Der Sanitizer läuft browser-gated, da
DOMPurify serverseitig kein DOM hat. Zusätzlich Key in der
Status-Buttons-Schleife ergänzt.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- TrailMap: IntersectionObserver für WebGL-Kontexte (max 8-16 gleichzeitig)
→ Karte erst laden, wenn sichtbar, rootMargin 200px für frühes Laden
- Trail-Liste: formatKm zeigt 0 m als "0,0 km" statt "–"
- Trail-Anlegen: Enter im Namensfeld triggert save(), saving-Guard hinzugefügt
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Übersichtsseite zeigt alle Trails des Teams als Grid mit Kartvorschau,
Status-Badge und Kennzahlen. Dialog für Trail-Erstellung mit GPX-Upload
im nächsten Schritt.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Die vier Trail-Stores (trails, trailVersions, trailFlags, trailMarkers)
werden im Dashboard-Layout per Context bereitgestellt, laden ihre Daten
beim Mount, abonnieren Realtime-Updates und werden beim Unmount wieder
aufgeräumt. Zusätzlich ergänzt ein Navigationseintrag „Trails" mit dem
Route-Icon aus lucide-svelte.
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>