# Konzeptplan: Vereinsuebergreifende Freundschaftsspiele ## Ziel - Ein gemeinsames Freundschaftsspiel-Objekt fuer zwei Vereine (statt zwei isolierter Eintraege). - Auffindbarkeit bestehender Spiele ueber Name, Datum und Startzeit. - Einladungsprozess (anbieten, annehmen, ablehnen). - Live-Synchronisierung zwischen beiden Vereinen per Socket. ## Produktumfang (MVP) - [x] Vereinsuebergreifendes Shared-Match-Datenmodell einfuehren. - [x] Match-Finder fuer Name, Datum, Startzeit implementieren. - [x] Einladung erstellen (Zielverein aus Vereinsliste + Freitext). - [x] Einladung im System speichern. - [x] E-Mail-Benachrichtigung an hinterlegte Personen des Zielvereins versenden. - [x] Einladung annehmen: Shared-Match fuer beide Vereine erstellen. - [x] Einladung ablehnen: Einladung loeschen. - [x] Socket-Sync fuer beide Vereine bei Aenderungen am Shared-Match. ## Datenmodell ### Neue Tabellen - [x] `friendly_match_shared` - [x] `id` - [x] `home_club_id` - [x] `guest_club_id` - [x] `date` - [x] `start_time` - [x] `match_name` (oder Home/Gast-Namenstruktur) - [x] `location_*` Felder - [x] `match_system`, `singles_count`, `doubles_count`, `winning_sets` - [x] `home_participants`, `guest_participants` - [x] `result_details`, `home_match_points`, `guest_match_points` - [x] `is_completed` - [x] `created_by_user_id` - [x] `created_from_invitation_id` - [x] `created_at`, `updated_at` - [x] `friendly_match_invitation` - [x] `id` - [x] `from_club_id` - [x] `to_club_id` - [x] `proposed_date` - [x] `proposed_start_time` - [x] `proposed_match_name` - [x] `message` (Freitext) - [x] `status` (`pending`, `accepted`) - [x] `created_by_user_id` - [x] `created_at`, `updated_at` ### Indizes und Constraints - [x] Index auf `friendly_match_shared (home_club_id, date, start_time)`. - [x] Index auf `friendly_match_shared (guest_club_id, date, start_time)`. - [x] Index auf `friendly_match_invitation (to_club_id, status, proposed_date)`. - [x] Verhindern, dass ein Verein sich selbst einlaedt (`from_club_id != to_club_id`). ## Backend API ### Finder - [x] `GET /api/friendly-matches/find` - [x] Query-Parameter: `clubId`, `name`, `date`, `startTime`. - [x] Exakt-Matches und Kandidaten mit `confidence` zurueckgeben. ### Einladungen - [x] `POST /api/friendly-match-invitations/:clubId` - [x] Payload: `toClubId`, `date`, `startTime`, `matchName`, `message`. - [x] `GET /api/friendly-match-invitations/:clubId/incoming` - [x] `GET /api/friendly-match-invitations/:clubId/outgoing` - [x] `POST /api/friendly-match-invitations/:clubId/:invitationId/accept` - [x] `POST /api/friendly-match-invitations/:clubId/:invitationId/decline` ### Shared Matches - [x] `GET /api/friendly-matches/shared/:clubId` - [x] `PUT /api/friendly-matches/shared/:clubId/:matchId` - [x] `PATCH /api/friendly-matches/shared/:clubId/:matchId/players` - [x] Optional: `DELETE /api/friendly-matches/shared/:clubId/:matchId` ## Rechte und Zugriff - [x] Zugriff pruefen: User muss in beteiligtem Verein freigeschaltet sein. - [x] Schreibrechte auf Shared-Match nur mit `schedule.write`. - [x] Einladung annehmen/ablehnen nur fuer `to_club_id`. ## E-Mail-Versand - [x] Empfaengerermittlung: `user_club` (approved=true) + `user.email` fuer Zielverein. - [x] Neue Mailfunktion in `emailService` fuer Einladung. - [x] Inhalt: einladender Verein, Matchdaten, Freitext, Aktion (annehmen/ablehnen in App). - [x] Fehlerbehandlung: Einladung bleibt erhalten, falls Mailversand fehlschlaegt (mit Log). ## Matching-Logik (Name/Datum/Startzeit) - [x] Normalisierung von Namen (trim, lowercase, Sonderzeichenbereinigung). - [x] Datum exakt matchen. - [x] Startzeit exakt matchen (MVP). - [x] Teamnamen in beide Richtungen pruefen (home/guest vertauscht). - [x] `confidence`-Stufen definieren (`exact`, `high`, `medium`). ## Socket-Sync - [x] Neue Socket-Events definieren: - [x] `friendly:invitation:created` - [x] `friendly:invitation:accepted` - [x] `friendly:invitation:declined` - [x] `friendly:shared:match:updated` - [x] `friendly:shared:match:deleted` - [x] Bei Shared-Match-Aenderung an beide Club-Raeume senden (`club-`, `club-`). - [x] Frontend und Mobile auf neue Events subscriben. ## Frontend (Web) - [x] Bereich "Einladungen" (Eingehend/Ausgehend) in Freundschaftsspielen. - [ ] Dialog "Verein einladen": Zielverein aus bestehender Vereinsliste + Freitext. - [x] Buttons fuer annehmen/ablehnen in eingehenden Einladungen. - [ ] Finder-UI fuer Name/Datum/Startzeit. - [x] Shared-Match-Kennzeichnung in Liste und Detaildialog. - [x] Socket-Event-Handling fuer Echtzeitupdates beider Vereine. ## Mobile (Android + Shared) - [x] API-Endpoints in `MatchesApi` erweitern. - [x] State-Manager fuer Einladungen und Shared-Matches erweitern. - [ ] UI fuer Einladungen (eingehend/ausgehend) einbauen. - [ ] Finder-UI fuer Name/Datum/Startzeit einbauen. - [ ] Shared-Match-Bearbeitung fuer beide Vereine synchronisieren. - [x] Socket-Events fuer Friendly-Shared-Flow verarbeiten. ## Migration und Abwaertskompatibilitaet - [ ] Bestehende `friendly_match`-Eintraege unveraendert weiter lesbar halten. - [ ] Schrittweise Migration/Koexistenzstrategie dokumentieren. - [ ] Optionales Mapping alter Einzel-Eintraege auf Shared-Matches definieren. ## Tests ### Backend - [ ] Unit-Tests fuer Match-Finder. - [ ] Unit-Tests fuer Einladung (create/accept/decline). - [ ] Integrations-Tests fuer Shared-Match-CRUD. - [ ] Berechtigungstests (falscher Verein, fehlende Rechte). ### Frontend/Mobile - [ ] UI-Tests fuer Einladung erstellen/anzeigen/entscheiden. - [ ] UI-Tests fuer Finder. - [ ] Realtime-Tests mit zwei gleichzeitig eingeloggten Vereinen. ### End-to-End - [ ] Verein A laedt Verein B ein. - [ ] E-Mail wird versendet. - [ ] Verein B nimmt an, Shared-Match entsteht. - [ ] Aenderung in Verein A erscheint sofort in Verein B und umgekehrt. - [ ] Ablehnung loescht Einladung vollstaendig. ## Rollout in Phasen - [ ] Phase 1: Datenmodell + Read-APIs. - [ ] Phase 2: Einladung + E-Mail. - [ ] Phase 3: Accept/Decline + Shared-Match-Erzeugung. - [ ] Phase 4: Shared-Match-Edit + Socket-Sync. - [ ] Phase 5: Finder + UX-Polish + E2E-Hardening. ## Offene Entscheidungen - [ ] Mehrfache parallele Einladungen fuer gleiche Daten erlauben oder verhindern? - [ ] Match-Name als einzelnes Feld oder Home/Gast getrennt fuehren? - [ ] Konfliktstrategie bei gleichzeitiger Bearbeitung (Last-Write-Wins vs. Versionierung)? - [ ] Ablehnung immer hard delete oder auditierbar speichern?