All checks were successful
Deploy tt-tagebuch / deploy (push) Successful in 54s
- Changed file permissions from 644 to 755 for various files in the mobile-app and mobile-app_legacy_rn_expo directories, ensuring executable permissions where necessary. - Added a new SQL migration script to the backend to introduce missing columns for club billing and invoice settings in the clubs table, maintaining synchronization with the current Sequelize model.
6.4 KiB
Executable File
6.4 KiB
Executable File
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)
- Vereinsuebergreifendes Shared-Match-Datenmodell einfuehren.
- Match-Finder fuer Name, Datum, Startzeit implementieren.
- Einladung erstellen (Zielverein aus Vereinsliste + Freitext).
- Einladung im System speichern.
- E-Mail-Benachrichtigung an hinterlegte Personen des Zielvereins versenden.
- Einladung annehmen: Shared-Match fuer beide Vereine erstellen.
- Einladung ablehnen: Einladung loeschen.
- Socket-Sync fuer beide Vereine bei Aenderungen am Shared-Match.
Datenmodell
Neue Tabellen
friendly_match_sharedidhome_club_idguest_club_iddatestart_timematch_name(oder Home/Gast-Namenstruktur)location_*Feldermatch_system,singles_count,doubles_count,winning_setshome_participants,guest_participantsresult_details,home_match_points,guest_match_pointsis_completedcreated_by_user_idcreated_from_invitation_idcreated_at,updated_at
friendly_match_invitationidfrom_club_idto_club_idproposed_dateproposed_start_timeproposed_match_namemessage(Freitext)status(pending,accepted)created_by_user_idcreated_at,updated_at
Indizes und Constraints
- Index auf
friendly_match_shared (home_club_id, date, start_time). - Index auf
friendly_match_shared (guest_club_id, date, start_time). - Index auf
friendly_match_invitation (to_club_id, status, proposed_date). - Verhindern, dass ein Verein sich selbst einlaedt (
from_club_id != to_club_id).
Backend API
Finder
GET /api/friendly-matches/find- Query-Parameter:
clubId,name,date,startTime. - Exakt-Matches und Kandidaten mit
confidencezurueckgeben.
- Query-Parameter:
Einladungen
POST /api/friendly-match-invitations/:clubId- Payload:
toClubId,date,startTime,matchName,message.
- Payload:
GET /api/friendly-match-invitations/:clubId/incomingGET /api/friendly-match-invitations/:clubId/outgoingPOST /api/friendly-match-invitations/:clubId/:invitationId/acceptPOST /api/friendly-match-invitations/:clubId/:invitationId/decline
Shared Matches
GET /api/friendly-matches/shared/:clubIdPUT /api/friendly-matches/shared/:clubId/:matchIdPATCH /api/friendly-matches/shared/:clubId/:matchId/players- Optional:
DELETE /api/friendly-matches/shared/:clubId/:matchId
Rechte und Zugriff
- Zugriff pruefen: User muss in beteiligtem Verein freigeschaltet sein.
- Schreibrechte auf Shared-Match nur mit
schedule.write. - Einladung annehmen/ablehnen nur fuer
to_club_id.
E-Mail-Versand
- Empfaengerermittlung:
user_club(approved=true) +user.emailfuer Zielverein. - Neue Mailfunktion in
emailServicefuer Einladung. - Inhalt: einladender Verein, Matchdaten, Freitext, Aktion (annehmen/ablehnen in App).
- Fehlerbehandlung: Einladung bleibt erhalten, falls Mailversand fehlschlaegt (mit Log).
Matching-Logik (Name/Datum/Startzeit)
- Normalisierung von Namen (trim, lowercase, Sonderzeichenbereinigung).
- Datum exakt matchen.
- Startzeit exakt matchen (MVP).
- Teamnamen in beide Richtungen pruefen (home/guest vertauscht).
confidence-Stufen definieren (exact,high,medium).
Socket-Sync
- Neue Socket-Events definieren:
friendly:invitation:createdfriendly:invitation:acceptedfriendly:invitation:declinedfriendly:shared:match:updatedfriendly:shared:match:deleted
- Bei Shared-Match-Aenderung an beide Club-Raeume senden (
club-<home>,club-<guest>). - Frontend und Mobile auf neue Events subscriben.
Frontend (Web)
- Bereich "Einladungen" (Eingehend/Ausgehend) in Freundschaftsspielen.
- Dialog "Verein einladen": Zielverein aus bestehender Vereinsliste + Freitext.
- Buttons fuer annehmen/ablehnen in eingehenden Einladungen.
- Finder-UI fuer Name/Datum/Startzeit.
- Shared-Match-Kennzeichnung in Liste und Detaildialog.
- Socket-Event-Handling fuer Echtzeitupdates beider Vereine.
Mobile (Android + Shared)
- API-Endpoints in
MatchesApierweitern. - 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.
- 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?