feat: Implement Windows runner for Flutter desktop app
All checks were successful
Deploy tt-tagebuch / deploy (push) Successful in 57s

- Added runner.exe.manifest for DPI awareness and compatibility settings.
- Created utils.cpp and utils.h for console management and command line argument handling.
- Developed win32_window.cpp and win32_window.h for high DPI-aware window management.
- Established basic window creation, message handling, and theme updating.
- Added documentation for Flutter desktop app implementation plan and MVP specifications.
This commit is contained in:
Torsten Schulz (local)
2026-07-30 10:01:54 +02:00
parent ee526dc3f2
commit b404c289bb
78 changed files with 4826 additions and 0 deletions

View File

@@ -0,0 +1,128 @@
# Flutter Desktop-App Umsetzungsplan
## Ziel und Leitentscheidung
Eine eigenständige, plattformübergreifende **Flutter-/Dart-Desktop-App** für Windows, macOS und Linux. Sie rendert ihre Oberflächen selbst mit Flutter **keine WebView und keine eingebettete Vue-Webseite**.
Die bestehende Express-/MySQL-Anwendung bleibt die gemeinsame Server- und API-Plattform. Web- und Desktop-App arbeiten deshalb mit denselben Vereinsdaten, Benutzern und Berechtigungen.
**Abgrenzung:** Das Vue-Frontend wird nicht portiert oder eingebettet. Es dient nur als fachliche Referenz für Abläufe und API-Nutzung.
## Zielarchitektur
```text
Flutter Desktop-App (Dart)
├── eigene native Flutter-Oberfläche
├── REST-Client → https://tt-tagebuch.de/api
├── sicherer Token-Speicher des Betriebssystems
└── später: Socket.IO, Benachrichtigungen, Datei-/Druckfunktionen
Bestehendes Node/Express-Backend
├── JWT-Authentifizierung und Berechtigungsprüfung
├── MySQL-Datenbank
└── bestehende REST- und Socket.IO-Schnittstellen
```
### Technische Festlegungen
- Neues Projekt im Repository: `backend/desktop-app/`.
- Flutter stable und Dart; Windows, macOS und Linux von Beginn an als Build-Ziele aktivieren.
- `go_router` für Navigation, `flutter_riverpod` für App-Zustand und `Dio` für HTTP.
- Datenmodelle, Repositorys und API-Client von Widgets trennen; DTOs nicht direkt in der UI verwenden.
- API-URL ausschließlich per `--dart-define` bzw. Build-Konfiguration setzen, nie fest in Quellcode oder Installer einbauen.
- JWT in `flutter_secure_storage` ablegen. Bei `401` Token entfernen und zur Anmeldung wechseln; Netzwerkfehler führen nicht zum Logout.
- Requests senden den vom Backend unterstützten Header `Authorization: Bearer <token>`; kompatibel bleibt auch der Web-Header `authcode`.
- Berechtigungen immer vom Backend erzwingen lassen. Die Flutter-Navigation blendet fehlende Rechte nur für eine bessere Bedienung aus.
- Deutsch als erste Sprache; Übersetzungen von Beginn an über Flutter-Lokalisierung strukturieren.
## Phasen und To-dos
### Phase 0 API und Produktumfang festziehen
- [x] Desktop-MVP verbindlich auf **Login, Vereinskontext, Kalender, Spielplan, Mitglieder und Trainingsübersicht** begrenzen.
- [x] Rollen für das MVP festlegen: einfaches Mitglied, Trainer und Vereinsverwaltung; pro Rolle die sichtbaren Bereiche definieren.
- [x] Die verwendeten Endpunkte und Payloads gegen `docs/api_contract.md` und die echten Routen prüfen.
- [x] Fehlende oder uneinheitliche API-Antworten als eigene Backend-Tickets erfassen, statt sie in der App zu umgehen.
- [x] Gemeinsame Fehlercodes und Lade-/Leerezustände für die App festlegen.
- [x] Datenschutz- und Offline-Anforderungen entscheiden: zunächst online-first, lokale Daten nur als Cache.
### Phase 1 Projektfundament
- [x] Flutter-Projekt in `backend/desktop-app/` erzeugen und eine nachvollziehbare README mit Voraussetzungen erstellen.
- [x] Paketstruktur anlegen: `core/`, `features/`, `data/`, `domain/`, `presentation/`.
- [x] Build-Konfigurationen `development`, `staging` und `production` mit `API_BASE_URL` per Dart-Define einrichten.
- [x] App-Theme, Typografie, responsive Desktop-Layout und zentrale Design-Tokens anlegen.
- [x] Navigation mit öffentlichem Bereich und geschütztem App-Bereich aufsetzen.
- [x] Fehlerbehandlung, Logging ohne personenbezogene Daten und zentrale Ladeindikatoren implementieren.
- [x] CI-Grundgerüst für Formatierung, Analyse und Tests anlegen.
### Phase 2 Anmeldung, Sitzung und Vereinskontext
- [ ] Login gegen `POST /api/auth/login` implementieren, inklusive „angemeldet bleiben“.
- [ ] Token sicher speichern, beim Start wiederherstellen und Sitzung mit `GET /api/session/status` prüfen.
- [ ] Logout über `POST /api/auth/logout` implementieren und lokale Zugangsdaten zuverlässig löschen.
- [ ] Passwort-vergessen- und Passwort-zurücksetzen-Flows als native Formulare ergänzen.
- [ ] Vereinsliste über `GET /api/clubs` laden und aktiven Verein persistent auswählen.
- [ ] Berechtigungen über `GET /api/permissions/:clubId` laden und die Navigation rollenabhängig aufbauen.
- [ ] Unit- und Integrationstests für Login, Tokenablauf, 401 und Vereinswechsel schreiben.
### Phase 3 Desktop-MVP: persönliche Organisation
- [ ] Startseite mit nächstem Training, nächstem Spiel, offenen Hinweisen und Schnellzugriffen erstellen.
- [ ] Kalenderansicht für Trainings-, Vereins- und Spieltermine umsetzen.
- [ ] Spielplan mit Saison- und Mannschaftsauswahl sowie korrekter Berliner Zeitzonenanzeige umsetzen.
- [ ] Mitgliederliste mit Suche und einer datensparsamen Detailansicht implementieren.
- [ ] Trainingsübersicht mit Gruppen, Zeiten und Trainingsstatistik für berechtigte Rollen implementieren.
- [ ] Für einfaches Mitglied den Bereich „Mein Verein“ mit persönlichen Terminen und Informationen priorisieren.
- [ ] Leere Zustände, fehlende Berechtigungen, langsame Verbindung und Serverfehler in allen MVP-Ansichten testen.
### Phase 4 Vereins- und Trainerfunktionen
- [ ] Trainingstagebuch inklusive Anwesenheit, Aktivitäten und Gruppen als native Arbeitsansicht umsetzen.
- [ ] Mitgliederverwaltung mit Bearbeiten, Bild-/Datei-Upload und Rechteprüfung erweitern.
- [ ] Sammlungsbestellungen als gemeinsames Modul einplanen und implementieren: Wünsche, Artikelstatus, Rückfragen, Preise, Bestätigung und Zahlungsstatus.
- [ ] Mannschaften, Spielberichte/Ergebnisse und Turniere in fachlich getrennten Features ergänzen.
- [ ] Rechnungen, Kommunikation, Aufgaben und Archiv erst nach einem eigenen UX-Entwurf als weitere Feature-Wellen ergänzen.
- [ ] Socket.IO für die Bereiche aktivieren, in denen aktuelle Daten tatsächlich einen Mehrwert bringen; REST bleibt die verlässliche Basis.
### Phase 5 echte Desktop-Mehrwerte
- [ ] Systembenachrichtigungen für Terminänderungen, Rückfragen und neue Vereinsnachrichten einführen.
- [ ] Tray-Icon mit „Heute“, Synchronisationsstatus und Schnellaktionen ergänzen.
- [ ] Native Datei-Auswahl, Downloads, PDF-Export und Druckabläufe implementieren.
- [ ] Fensterzustand, zuletzt gewählter Verein und bevorzugte Ansicht lokal speichern.
- [ ] Offline-Cache für lesende Kernansichten konzipieren; Konfliktregeln vor schreibender Offline-Unterstützung festlegen.
- [ ] Signierte Installer für Windows, macOS und Linux sowie eine sichere Update-Strategie vorbereiten.
### Phase 6 Qualität, Release und Betrieb
- [ ] Widget-Tests für jede neue Ansicht und Repository-/API-Tests für kritische Datenflüsse ergänzen.
- [ ] Integrationstests für Anmeldung, Vereinswechsel, Kalender und Spielplan aufsetzen.
- [ ] Smoke-Tests auf Windows, macOS und Linux durchführen; dabei Skalierung, Tastaturnavigation und Zeitzonen prüfen.
- [ ] Accessibility prüfen: Fokusführung, Kontraste, Screenreader-Beschriftungen und vollständig bedienbare Tastaturwege.
- [ ] Release-Kanäle (intern/stabil), Versionsnummern, Fehlerberichte und Datenschutztexte definieren.
- [ ] Pilot mit einem Verein durchführen und erst danach die nächste Paritätswelle freigeben.
## Reihenfolge nach dem MVP
1. Persönliche Funktionen: Mein Verein, Kalender, Spielplan und Benachrichtigungen.
2. Trainer-Arbeitsabläufe: Trainingstagebuch, Anwesenheit, Gruppen und Trainingselemente.
3. Vereinsverwaltung: Mitglieder, Kommunikation, Sammlungsbestellungen, Aufgaben und Dokumente.
4. Komplexe Spezialfunktionen: Turniere, Rechnungen, Importe, externe myTischtennis-/click-TT-Abläufe und Offline-Schreiben.
## Kritische vorhandene Referenzen
- `backend/server.js` zentrale API-Routen.
- `backend/middleware/authMiddleware.js` und `backend/services/authService.js` JWT- und Sitzungsverhalten.
- `docs/api_contract.md` aktueller API-Katalog.
- `docs/socket_contract.md` spätere Live-Updates.
- `frontend/src/router.js` fachliche Web-Bereiche und Berechtigungen als Referenz, nicht als UI-Vorlage.
- `docs/simple-user-plan.md` und `docs/collective-orders-plan.md` bereits geplante Nutzer- und Bestellabläufe.
## Abnahmekriterien für Release 1
- Die App ist eine eigenständige Flutter-Anwendung ohne WebView.
- Login, sicherer Sitzungsspeicher und Logout funktionieren gegen die Produktions-API.
- Ein Nutzer sieht ausschließlich die für seine Vereinsrolle erlaubten Bereiche.
- Kalender, Spielplan, Mitglieder und Trainingsübersicht funktionieren auf allen drei Desktop-Plattformen.
- `flutter analyze` und `flutter test` laufen fehlerfrei; je Plattform gibt es mindestens einen erfolgreichen manuellen Smoke-Test.

View File

@@ -0,0 +1,101 @@
# 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.