stammtisch-hersbruck/TODO.md
Daniel Michelberger 4fa0de8753 feat: Logo pro Team, auch als Wasserzeichen im Seitenhintergrund
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
2026-09-02 15:42:04 +02:00

6.2 KiB

Offene Punkte

Stand: 2026-09-02. Was hier steht, ist bewusst nicht erledigt — entweder weil es eine Entscheidung braucht oder weil es außerhalb des Repos passiert.

Entscheidungen

Trail-Status: dürfen Mitglieder melden?

Anzeige und Herkunft (status_changed, status_by) sind fertig. Ändern darf den Status weiterhin nur, wer Pate oder Team-Admin ist — trails.updateRule lässt nichts anderes zu.

Sollen alle Teammitglieder melden dürfen, braucht es eine Regel, die genau ein Feld freigibt: team.users.id ?= @request.auth.id kombiniert mit @request.body.<feld>:isset = false für jedes andere Feld. Das funktioniert, wird aber lang und bricht still, sobald ein Feld dazukommt. Deshalb erst nach ausdrücklicher Entscheidung.

Fahrer: Kader oder Event-Teilnehmer?

riders.event bindet einen Fahrer an genau ein Event. Ein in den Einstellungen angelegter Fahrer ohne Event steht deshalb nur im Verzeichnis und taucht in keiner Zeitnahme auf; der Dialog hat dafür ein optionales Event-Feld.

Ein echter Team-Kader, aus dem man Fahrer in Events übernimmt, wäre eine n:m-Beziehung — also eine Schema-Änderung, keine Oberflächenfrage.

Mitglied per E-Mail einladen

Die alte Einladung über eine E-Mail-Suche ist entfallen und durch „Mitglied anlegen" ersetzt. Sie konnte nie funktionieren: users.listRule gibt nur den eigenen Datensatz frei, die Suche lief immer ins Leere.

Ein bestehendes fremdes Konto in ein Team zu holen braucht eine offenere listRule (z. B. @request.auth.id != ""). Das erlaubt allerdings, alle Konten der Instanz aufzulisten — deshalb bewusst nicht ohne Rücksprache.

Ausfahrten: geplant, noch nicht gebaut

Ausfahrten werden nicht zu einem zweiten Konzept neben Events, sondern Events bekommen Schalter. Ein Bikepark-Ausflug mit gestoppten Läufen ist beides zugleich; eine Trennung wäre willkürlich und würde Datum, Rechte und Oberfläche doppelt führen.

Geplant, in dieser Reihenfolge:

  1. events.timing (bool). Runs und Zeitnahme erscheinen nur, wenn gesetzt. Der wöchentliche Stammtisch braucht sie nicht.

  2. Teilnahme als eigene Collection event_participants (Event, Person, Status, Zeitpunkt) — nicht als Liste am Event, sonst hängen Status und Zeitpunkt nirgends, und Gäste ohne Konto passen nicht hinein.

    events.participation steuert, wie man hineinkommt:

    Wert Bedeutung
    offen Jedes Teammitglied trägt sich selbst ein
    bestaetigung Anmeldung möglich, Ersteller oder Team-Admin bestätigt
    geschlossen Nur Ersteller oder Team-Admin trägt Teilnehmer ein
  3. Serien (event_series): Regel, Zeitraum und Vorlage; daraus entstehen echte Einzeltermine. Bewusst nicht ein Datensatz mit Wiederholungsregel, aus dem Termine nur gerechnet werden — sobald „wer kommt am 12.?" oder „diese Woche fällt aus" beantwortet werden soll, braucht jeder Termin einen eigenen Datensatz.

Offen: Sind Teilnehmer Nutzerkonten oder Fahrer? Für den Stammtisch wären es Konten, für eine gemeinsame Ausfahrt eher Fahrer (die es auch ohne Konto gibt). Beides zugleich geht, macht die Collection aber breiter.

Vor dem nächsten Deploy

PUBLIC_CARTO_API_KEY in Coolify setzen

Die Kartenkacheln kommen von CARTO. Der Schlüssel muss den Browser erreichen, deshalb das PUBLIC_-Präfix — ohne das reicht SvelteKit ihn nicht weiter.

Gelesen wird er über $env/dynamic/public, das heißt: Die Variable muss in der Laufzeitumgebung des node build-Prozesses stehen, nicht nur zur Buildzeit. In Coolify als normale Umgebungsvariable eintragen genügt. Fehlt sie, laufen die Kacheln ohne Schlüssel weiter — die Karte bleibt also sichtbar.

Migrationen greifen beim nächsten Start

Sechs neue Migrationen liegen in backend/pb_migrations/:

  • 1754500500_riders_user_and_admin_rules.js
  • 1754500600_events_dates_instead_of_status.js
  • 1754500700_trail_status_meta.js
  • 1754500800_trail_markers_custom.js
  • 1754500900_users_superadmin.js
  • 1754501000_teams_logo.js

Solange sie nicht gelaufen sind, scheitert alles, was auf den neuen Regeln aufbaut. Am deutlichsten beim Anlegen eines Mitglieds oder eines Fahrer-Logins: „Only superusers can perform this action" — genau das sagt die noch unveraenderte users.createRule (null = nur Superuser).

Achtung: Die mittlere entfernt events.status samt seiner Werte. Das ist so gewollt (Events werden datiert statt bewertet), aber es ist ein Datenverlust und nicht zurückzunehmen.

Ebenfalls neu: Fahrer anlegen, ändern und löschen darf ab dann nur noch die Teamleitung. Mitglieder ohne Admin-Rolle verlieren diese Möglichkeit auch auf der Event-Seite.

Typen einmal neu erzeugen

frontend/src/lib/types.d.ts wurde bei den letzten Schema-Änderungen von Hand ergänzt (riders.user, trails.status_by/status_changed, events.starts/ends statt status). Grund: pocketbase-typegen braucht native sqlite3-Bindings, die in der Arbeitsumgebung nicht gebaut werden durften.

cd frontend && npm run generate-pocketbase-types

Die Datei sollte danach unverändert bleiben. Tut sie es nicht, gilt das Ergebnis des Generators.

Logo des Stammtischs zuordnen

teams.logo gibt es ab 1754501000. Solange nichts hinterlegt ist, zeigt die App weiterhin das Wappen aus static/ — für den Stammtisch Hersbruck sieht es also unverändert aus. Wer es als Datei am Team haben will, lädt es nach dem Deploy unter Einstellungen → Team → Logo hoch.

Kleinigkeiten

  • Der Melder eines Trail-Markers („wer") zeigt bis zum Deploy „Unbekannt". Die gelockerte users.viewRule kommt mit 1754500500.
  • Die Rolle Superadmin existiert seit 1754500900 und ist für stammtisch@dne.name gesetzt, gibt in der App aber noch keine besonderen Rechte. Sie ist bewusst nur in PocketBase vergebbar: Die updateRule der users-Collection schließt superadmin vom Selbstsetzen aus. Sobald klar ist, was sie dürfen soll, kommen die Regeln dazu.
  • Flag-Typen bleiben teamspezifisch. Ein neues Team bekommt beim Anlegen den hartkodierten Standardsatz aus trailFlags.svelte.ts, den es danach frei ändern kann. Eine appweite Verwaltung gibt es damit bewusst nicht.
  • NAMING.md und frontend/static/pedaler.svg liegen bewusst nur lokal.