# Flutter Desktop-App – Phase 0: MVP- und API-Spezifikation

Stand: 30.07.2026  
Geltung: Release 1 der eigenständigen Flutter-Desktop-App für Windows, macOS und Linux.

## 1. Verbindlicher MVP-Umfang

Die erste Version ist eine **online-first Flutter-App ohne WebView**. Sie verwendet die Produktions-API, speichert keine fachlichen Daten dauerhaft offline und bildet ausschließlich die folgenden Bereiche ab:

| Bereich | Release-1-Umfang | Nicht Bestandteil von Release 1 |
| --- | --- | --- |
| Anmeldung | Login, Sitzung wiederherstellen, Logout, Passwort vergessen/zurücksetzen | Registrierung und Kontoaktivierung als eigener Folgeentscheid |
| Vereinskontext | Verein wählen, Rechte laden, zuletzt gewählten Verein merken | Verein anlegen, Beitrittsfreigaben verwalten |
| Startseite | Nächstes Training, nächstes Spiel, Anzahl ungelesener Hinweise, Schnellzugriffe | frei konfigurierbare Dashboards |
| Kalender | Trainings-, Spiel- und Vereinsereignisse lesen; Monats-/Listenansicht | Ereignisse anlegen oder bearbeiten |
| Spielplan | Saison, Mannschaft/Liga, Spiele und Ergebnisse lesen | CSV-Import, Tabellenabruf, Spielerzuordnung |
| Mitglieder | Suche, Liste und datensparsame Detailansicht | Bearbeiten, Bildverwaltung, SEPA, Transfer |
| Training | Trainingszeiten, Gruppen und Statistik lesen | Trainingstagebuch, Anwesenheit und Aktivitäten bearbeiten |
| Mein Verein | Persönliche Übersicht, Inbox und eigene Terminantworten, sofern im Vereinskontext verfügbar | Profiländerung und Bestellabläufe als Folge-Release |

Der MVP liefert damit für alle Rollen eine verlässliche tägliche Übersicht. Schreibende Verwaltungs- und Trainerabläufe folgen erst, wenn die lesenden Kernansichten auf allen Zielplattformen stabil sind.

## 2. Rollen- und Sichtbarkeitsmatrix

Die Berechtigungen kommen ausschließlich vom Backend (`GET /api/permissions/:clubId`). Die folgende Matrix definiert nur die Desktop-Navigation; sie ersetzt niemals eine Serverprüfung.

| Bereich | Einfaches Mitglied | Trainer | Vereinsverwaltung |
| --- | --- | --- | --- |
| Startseite / Mein Verein | ja | ja | ja |
| Kalender | wenn mindestens eine passende Leseberechtigung vorliegt | ja | ja |
| Spielplan | mit `schedule.read` | mit `schedule.read` | mit `schedule.read` |
| Mitglieder | nur eigene, persönliche Daten im MVP | mit `members.read` | mit `members.read` |
| Training / Statistik | eigene bzw. freigegebene Ansicht | mit Trainings-/Statistikrecht | mit Trainings-/Statistikrecht |
| Verwaltungsnavigation | nein | nur freigegebene Trainerbereiche | nur freigegebene Verwaltungsbereiche |

**Navigationsregel:** Fehlt eine Berechtigung, erscheint der Bereich nicht im Hauptmenü. Ein direkter Aufruf zeigt einen neutralen „Kein Zugriff“-Zustand. Ein `403` des Servers wird nie als Clientfehler behandelt.

## 3. Verifizierter API-Vertrag für Release 1

Basis: `backend/server.js`, die zugehörigen Route-Dateien sowie `docs/api_contract.md`.

### Authentifizierung und Kontext

| Vorgang | Endpunkt | MVP-Verwendung |
| --- | --- | --- |
| Anmeldung | `POST /api/auth/login` | Payload `{ email, password, rememberMe }`; Antwort enthält `token` und `expiresAt`. |
| Sitzung prüfen | `GET /api/session/status` | beim App-Start nach Wiederherstellung des Tokens. |
| Abmelden | `POST /api/auth/logout` | Token serverseitig invalidieren, danach lokal löschen. |
| Vereine | `GET /api/clubs` und `GET /api/clubs/:clubId` | Vereinsauswahl und Überschrift. |
| Rechte | `GET /api/permissions/:clubId` | Menü und Feature-Gates aktualisieren. |

### Fachliche Leseansichten

| Bereich | Endpunkt | Hinweise |
| --- | --- | --- |
| Persönliche Übersicht | `GET /api/clubmembers/dashboard/:clubId` | Für „Mein Verein“ und Startseite; Antwortschema vor Phase 3 als DTO festschreiben. |
| Inbox | `GET /api/clubmembers/inbox/:clubId` | Ungelesene Hinweise und Nachrichten. |
| Terminantwort | `PUT /api/clubmembers/dashboard/:clubId/events/:eventId/response` | einzige MVP-Schreibaktion für das Mitglied. |
| Kalenderereignisse | `GET /api/calendar-events/:clubId?year=YYYY` | Vereinsereignisse. |
| Kalender-/Feiertage | `GET /api/calendar/club/:clubId/holidays?year=YYYY` | ergänzende Kalenderdaten. |
| Spielplan | `GET /api/matches/leagues/:clubId/matches?seasonid=:id` | nur bei `schedule.read`; Anzeige immer in `Europe/Berlin`. |
| Ligen | `GET /api/matches/leagues/current/:clubId` | Auswahl für Spielplan. |
| Teams | `GET /api/club-teams/club/:clubId?seasonid=:id` | Mannschaftsauswahl. |
| Mitglieder | `GET /api/clubmembers/get/:clubId/:showAll` | nur bei `members.read`; Standardwert `showAll=false`. |
| Trainingsgruppen | `GET /api/training-groups/:clubId` | nur bei verfügbarer Leseberechtigung. |
| Trainingszeiten | `GET /api/training-times/:clubId` | nur bei verfügbarer Leseberechtigung. |
| Trainingsstatistik | `GET /api/training-stats/:clubId` | nur bei `statistics.read`. |

### Verbindliche Request- und Fehlerregeln

- Jeder authentifizierte Request sendet `authcode: <JWT>`; optional zusätzlich `userid`, wenn es für einen bestehenden Endpunkt benötigt wird.
- `Authorization: Bearer <JWT>` wird nicht als alleiniger Standard eingesetzt, bis alle Controller einheitlich auf den authentifizierten Request-Kontext zugreifen.
- `401`: gespeicherten Token entfernen und zur Anmeldung wechseln.
- `403`: Zugriff verweigert anzeigen, Token behalten und Navigation bei nächster Rechteaktualisierung korrigieren.
- Netzwerkfehler, Timeout oder `5xx`: kein Logout, klare Wiederholen-Aktion und ggf. Anzeige gecachter Daten.
- Kein Request und kein Log darf Passwort, JWT, E-Mail-Adresse oder vollständige Mitgliederdaten protokollieren.

## 4. Erfasste Backend-Tickets vor/parallel zu Phase 1

| Priorität | Ticket | Befund / Akzeptanzkriterium |
| --- | --- | --- |
| P0 | Auth-Header vereinheitlichen | `calendarController.js` und `calendarEventController.js` lesen aktuell nur `req.headers.authcode`, obwohl `authMiddleware.js` auch Bearer-Tokens akzeptiert. Einen zentralen Token-/User-Kontext verwenden; danach funktionieren beide Headerformen in allen geschützten Routen gleich. |
| P0 | Dashboard-DTO dokumentieren | Antwort von `GET /api/clubmembers/dashboard/:clubId` mit stabilen Feldern für nächste Termine, Inbox-Zähler und persönliches Mitglied dokumentieren und per Test absichern. |
| P1 | Kalender-Read-Contract absichern | Response-Modelle von Kalenderereignissen, Feiertagen und importierten Spielen mit Beispielpayloads dokumentieren; Datum/Zeit als ISO-Wert mit klarer Zeitzonenregel. |
| P1 | Berechtigungen je MVP-Endpunkt prüfen | Für Trainingszeiten/-gruppen und das Member-Dashboard explizit serverseitige Vereins- und Rechteprüfungen testen; Navigation allein ist keine Sicherheit. |
| P2 | Einheitliches Fehlerformat | Kalender- und ältere Controller schrittweise an das dokumentierte Fehlerformat `{ success, code, params, error, message }` angleichen. |

## 5. Datenschutz- und Offline-Entscheidung

- **Online-first:** Release 1 benötigt eine Verbindung zur API für alle Fachinformationen.
- Lokal bleiben ausschließlich: verschlüsselter JWT, nicht sensible App-Einstellungen (Theme, Fensterzustand, letzter Verein) sowie ein kurzlebiger, löschbarer Lesecache.
- Keine Passwörter, Zahlungsdaten, Mitgliedsfotos, SEPA-Daten oder vollständigen Mitgliederlisten offline speichern.
- Bei fehlender Verbindung zeigt die App klar „Offline – Datenstand von …“ und deaktiviert Aktionen, die eine API-Anfrage benötigen.
- Offline-Schreiben, Konfliktauflösung und Hintergrundsynchronisation gehören ausdrücklich nicht zu Release 1.

## 6. Definition of Ready für Phase 1

- MVP-Umfang und Rollenmatrix dieses Dokuments sind akzeptiert.
- P0-Backend-Tickets sind umgesetzt oder der Flutter-Client verwendet vorübergehend den verbindlichen `authcode`-Header.
- Eine Testumgebung mit HTTPS-API und einem Testkonto je MVP-Rolle steht bereit.
- API-Base-URL für Entwicklung, Staging und Produktion ist festgelegt.
