Cas d'utilisation — Parties¶
Terminologie
On utilise le terme "partie" (pas "match"). Format uniquement 2v2 (4 joueurs).
UC-PARTIE-001 · Créer une partie¶
Acteur : Joueur authentifié
Précondition : Utilisateur connecté
Flux principal¶
- Le joueur accède à « Créer une partie »
- Il choisit le type : Amicale ou Compétitive
- Il choisit la visibilité : Publique ou Privée
- Il choisit l'environnement : Intérieur, Semi-couvert ou Extérieur
- Il sélectionne la date et l'heure
- Il choisit le lieu : club référencé ou lieu libre (adresse)
- Il indique si la piste est déjà réservée (OUI/NON) — ou réserve via l'app si le club le permet
- Il sélectionne la durée (60, 90, 120, 150 ou 180 min)
- Il définit l'intervalle de niveau accepté (min–max, ex : 3.0 – 5.5)
- Il configure le nombre de sets (1, 2 ou 3)
- (Optionnel — Pré-remplissage des équipes) Il choisit sa position (équipe + côté) et/ou ajoute des invités (joueurs hors-app) avec leur nom et position
- Il valide → la partie est créée, le créateur est inscrit automatiquement (avec la position choisie si pré-remplie)
- (Si privée) Il invite des joueurs par lien ou par pseudo/email
UC-PARTIE-002 · Rejoindre une partie publique¶
Acteur : Joueur authentifié
Précondition : Partie en statut « Ouverte », places disponibles
Flux principal — niveau dans l'intervalle¶
- Le joueur recherche des parties (filtres + géolocalisation)
- Il consulte les détails (lieu, heure, joueurs inscrits, niveau, sets, type, environnement)
- Son niveau est dans l'intervalle → il clique sur « Rejoindre la partie »
- La modale de sélection de position s'ouvre :
- Titre : « Choisir votre position »
- Vue terrain avec 4 emplacements répartis entre Équipe A et Équipe B
- Chaque emplacement indique la position (Gauche — Revés / Droite — Drive) et le joueur occupant le cas échéant
- Les positions prises affichent le nom du joueur (ex : « Marie M. ») ou de l'invité (badge « Invité ») et sont non cliquables (grisées)
- Les positions libres affichent une icône
+et sont cliquables
- Le joueur clique sur un emplacement libre → celui-ci se met en surbrillance, le bouton « Confirmer ma position » s'active
- Le joueur confirme → requête
POST /api/v1/games/{id}/joinavec{ team, position }→ il est inscrit - La modale se ferme, le terrain se met à jour en temps réel
- Les autres joueurs sont notifiés
Raccourci — Clic direct sur le terrain¶
- Depuis l'écran de détail, un non-participant peut cliquer sur un emplacement libre du terrain (icône
+avec libellé « Libre ») - Cela déclenche directement l'inscription avec la position sélectionnée, sans ouvrir la modale
Flux alternatif — Annulation¶
- Le joueur ouvre la modale puis clique sur « Annuler » → la modale se ferme sans effet
Flux alternatif — niveau hors intervalle¶
- Son niveau est en dehors de l'intervalle → il voit « Demander à participer »
- Un message l'informe que son niveau est hors intervalle et qu'une demande sera envoyée
- Il envoie la demande → l'organisateur reçoit une notification (
participation_request) - L'organisateur consulte la liste des demandes via
GET /api/v1/games/{id}/pending-requests - L'organisateur accepte via
POST /api/v1/games/{id}/players/{userId}/approve→ le joueur passe en statutconfirmedet reçoit une notification (participation_approved) - L'organisateur refuse via
POST /api/v1/games/{id}/players/{userId}/reject→ le joueur est retiré de la partie et reçoit une notification (participation_rejected)
UC-PARTIE-003 · Composer les équipes¶
Acteur : Joueurs inscrits (partie Complète) / Créateur
Précondition : 4 joueurs inscrits
Flux — composition manuelle (changement de position)¶
- Un joueur inscrit clique sur « Changer de position » depuis l'écran de détail
- La modale de sélection de position s'ouvre (même modale que pour rejoindre)
- La position actuelle du joueur est marquée avec un badge « Occupée »
- Les positions prises par d'autres joueurs sont grisées (non cliquables)
- Le joueur sélectionne un emplacement libre → « Confirmer ma position » s'active
- Il confirme → requête
PATCH /api/v1/games/{id}/positionavec{ team, position }→ la position est mise à jour - Le terrain se met à jour en temps réel
Flux — tirage au sort¶
- Le créateur voit un bouton « Tirage au sort » sur l'écran de détail
- Il clique dessus → requête
POST /api/v1/games/{id}/draw - L'application répartit aléatoirement les 4 joueurs (équipes + positions)
- Le terrain se met à jour en temps réel
- Les joueurs peuvent toujours modifier manuellement après le tirage
Conditions d'affichage des actions¶
| Bouton | Condition d'affichage |
|---|---|
| « Rejoindre la partie » | Non participant, partie ouverte, places disponibles, niveau dans l'intervalle |
| « Demander à participer » | Non participant, partie ouverte, places disponibles, niveau hors intervalle |
| Bannière « Demande en attente » + « Annuler ma demande » | Participant avec statut pending (hors invitation privée) |
| « Changer de position » | Participant inscrit (confirmed), partie pas encore « En cours » |
| « Tirage au sort » | Créateur de la partie uniquement |
Séquence API — sélection de position¶
sequenceDiagram
participant J as Joueur
participant UI as Frontend
participant API as API
J->>UI: Clique "Rejoindre la partie"
UI->>UI: Ouvre modale positions
J->>UI: Sélectionne emplacement libre
J->>UI: Confirme
UI->>API: POST /games/{id}/join { team, position }
API->>API: Vérifie niveau, place dispo, position libre
alt Niveau dans l'intervalle
API-->>UI: 200 { data: game, pending: false }
UI->>UI: Ferme modale, met à jour terrain
else Niveau hors intervalle
API-->>UI: 200 { data: game, pending: true }
UI->>UI: Toast « Demande envoyée ! », affiche bannière d'attente
end UC-PARTIE-003b · Ajouter/retirer un invité¶
Acteur : Créateur de la partie
Précondition : Partie en statut « Ouverte », places disponibles
Flux — ajouter un invité¶
- Le créateur accède au détail de la partie (ou à l'étape de pré-remplissage lors de la création)
- Il sélectionne un emplacement libre et active le mode « Invité »
- Il saisit le nom de l'invité (max 100 caractères)
- →
POST /api/v1/games/{id}/guestsavec{ guest_name, team, position } - L'invité apparaît sur le terrain avec un badge « Invité » et la couleur accent
Flux — retirer un invité¶
- Le créateur clique sur l'emplacement occupé par un invité
- Il confirme la suppression →
DELETE /api/v1/games/{id}/guests/{slotId} - L'emplacement redevient libre
UC-PARTIE-004 · Saisir et valider le score¶
Acteur : N'importe quel joueur du match
Précondition : Partie en statut « Terminée »
sequenceDiagram
participant J1 as Joueur 1
participant API as API
participant J2 as Joueur 2
participant J3 as Joueur 3
participant J4 as Joueur 4
J1->>API: Saisit le score (ex: 6-3, 6-4)
API->>API: Valide le format padel
API->>J2: Notification "Score à valider"
API->>J3: Notification "Score à valider"
API->>J4: Notification "Score à valider"
J2->>API: Valide ✅
J3->>API: Valide ✅
J4->>API: Valide ✅
API->>API: Score officiel → recalcul niveau
API-->>J1: Partie archivée, niveau mis à jour Flux alternatif — contestation¶
- Un joueur conteste → il propose un score alternatif
- Nouveau cycle de validation pour les 4 joueurs
Règle de timeout¶
- Si un joueur ne valide pas sous 24 heures → le score est automatiquement validé
UC-PARTIE-005 · Quitter une partie¶
Acteur : Joueur inscrit
Précondition : Partie en statut « Ouverte » ou « Complète »
- Le joueur clique sur « Quitter la partie »
- Il est retiré de la liste des participants
- La partie repasse en statut « Ouverte » si elle n'est plus complète
- Le créateur et les autres participants sont notifiés (in-app, push, email)
UC-PARTIE-006 · Inviter un joueur à une partie privée¶
Acteur : Créateur de la partie
Précondition : Partie privée en statut « Ouverte » ou « Complète », utilisateur est le créateur
Flux principal — Invitation par email¶
- Le créateur accède au détail de la partie
- Il clique sur « Inviter un joueur »
- La modale d'invitation s'ouvre avec deux options : par email ou par lien
- Il saisit l'email du joueur et clique sur « Envoyer »
- API
POST /api/v1/games/{id}/invitationsavec{ email } - L'invitation est créée avec statut « En attente » et un token unique (validité : 48h)
- Si l'email correspond à un utilisateur existant → notification in-app
Flux alternatif — Lien partageable¶
- Le créateur clique sur l'onglet « Lien » dans la modale
- Il clique sur « Générer un lien »
- API
POST /api/v1/games/{id}/invite-link→ retourne un token - Le lien est affiché avec un bouton « Copier le lien »
- Le créateur partage le lien (WhatsApp, SMS, etc.)
UC-PARTIE-007 · Accepter / Refuser une invitation¶
Acteur : Joueur invité
Précondition : Invitation en statut « En attente », non expirée
Flux principal — Acceptation¶
- Le joueur reçoit une notification d'invitation
- Il accède à ses invitations en attente (
GET /api/v1/invitations/pending) - Il clique sur « Accepter »
- API
POST /api/v1/games/{gameId}/invitations/{id}/accept - Le joueur est inscrit à la partie
- Le créateur est notifié (« X a accepté votre invitation »)
Flux alternatif — Refus¶
- Le joueur clique sur « Refuser »
- API
POST /api/v1/games/{gameId}/invitations/{id}/decline - Le créateur est notifié (« X a décliné votre invitation »)
Flux alternatif — Lien d'invitation¶
- Le joueur clique sur un lien d'invitation (route
/join/:token) - S'il est authentifié → API
POST /api/v1/games/join-by-link/{token} - Il est inscrit à la partie et redirigé vers le détail
- Si le lien est expiré ou déjà utilisé → message d'erreur
UC-PARTIE-008 · Rechercher des parties avec filtres avancés et géolocalisation¶
Acteur : Joueur (authentifié ou non pour la recherche publique)
Précondition : Aucune
Flux principal¶
- Le joueur accède à la page « Rechercher des parties » (
/player/matches) - Il voit la liste des parties publiques ouvertes (triées par date)
- Il peut basculer entre la vue liste et la vue carte (Leaflet)
- Il peut utiliser les filtres avancés :
- Type : Amicale / Compétitive
- Environnement : Intérieur, Semi-couvert, Extérieur
- Plage de dates : date de début / date de fin
- Niveau : niveau min / niveau max
- Recherche textuelle : nom de club, ville ou lieu personnalisé
- Il peut activer la géolocalisation pour :
- Afficher la distance de chaque partie (en km)
- Filtrer par rayon (5, 10, 20, 50, 100 km)
- Trier par distance au lieu de la date
- API
GET /api/v1/games?latitude=X&longitude=Y&radius=Z&sort_by=distance&type=...
Flux alternatif — Vue carte¶
- Le joueur clique sur l'icône « Carte »
- Les parties géolocalisées sont affichées sur une carte Leaflet
- Chaque marqueur ouvre un popup avec le résumé de la partie et un bouton « Rejoindre »
- Le joueur peut cliquer sur le popup pour accéder au détail de la partie
Règles métier¶
- La distance est calculée avec la formule de Haversine (PostgreSQL)
- Pour les parties en club : coordonnées du club
- Pour les parties en lieu libre :
custom_latitude/custom_longitude - Le rayon par défaut est 50 km (recommandations), configurable pour la recherche
UC-PARTIE-009 · Parties recommandées¶
Acteur : Joueur authentifié
Précondition : Utilisateur connecté
Flux principal¶
- Le joueur accède à la page d'accueil (
/player/home) - Une section « Parties recommandées » affiche des parties adaptées à son profil
- API
GET /api/v1/games/recommended?latitude=X&longitude=Y
Critères de recommandation¶
- Niveau compatible : le niveau du joueur est dans l'intervalle
[min_level, max_level]de la partie - Non créateur : les parties créées par l'utilisateur sont exclues
- Non inscrit : les parties déjà rejointes sont exclues
- Proximité : si coordonnées fournies, les parties dans un rayon de 50 km sont privilégiées
- Clubs favoris : les parties dans les clubs favoris de l'utilisateur sont affichées en priorité
- Tri : clubs favoris → distance → date