API — Parties (Games)¶
Ce document décrit les endpoints de l'API REST pour la gestion des parties de padel (domain Game).
Base URL
Tous les endpoints sont préfixés par /api/v1.
Endpoints publics¶
GET /games — Lister les parties publiques ouvertes¶
Retourne la liste paginée des parties publiques (visibility=public) en statut open ou full, programmées dans le futur.
| Paramètre | Type | Description |
|---|---|---|
type | string | Filtre par type : friendly ou competitive |
environment | string | Filtre : indoor, semi_covered, outdoor |
min_level | float | Filtre : niveau minimum des joueurs |
max_level | float | Filtre : niveau maximum des joueurs |
club_id | integer | Filtre par club |
date_from | string | Date de début (ISO 8601) |
date_to | string | Date de fin (ISO 8601) |
search | string | Recherche textuelle (club, ville, lieu) |
page | integer | Numéro de page (défaut : 1) |
per_page | integer | Éléments par page (défaut : 15) |
{
"data": [
{
"id": 1,
"type": "friendly",
"visibility": "public",
"environment": "indoor",
"scheduled_at": "2026-03-15T14:00:00+00:00",
"duration_minutes": 90,
"location_type": "club",
"club": { "id": 1, "name": "Padel Club Paris", "city": "Paris" },
"custom_location": null,
"is_court_booked": false,
"min_level": 3.0,
"max_level": 6.0,
"sets_count": 3,
"status": "open",
"remaining_slots": 3,
"creator": { "id": 1, "first_name": "Jean", "last_name": "Dupont" },
"players": [...],
"created_at": "2026-03-08T10:00:00+00:00"
}
],
"meta": {
"current_page": 1,
"last_page": 1,
"per_page": 15,
"total": 1
}
}
GET /games/{id} — Détail d'une partie¶
Retourne les détails complets d'une partie avec ses relations (créateur, club, joueurs).
{
"data": {
"id": 1,
"type": "friendly",
"visibility": "public",
"environment": "indoor",
"scheduled_at": "2026-03-15T14:00:00+00:00",
"duration_minutes": 90,
"location_type": "club",
"club": { "id": 1, "name": "Padel Club Paris" },
"is_court_booked": false,
"min_level": 3.0,
"max_level": 6.0,
"sets_count": 3,
"status": "open",
"remaining_slots": 3,
"creator": { "id": 1, "first_name": "Jean", "last_name": "Dupont" },
"players": [
{
"id": 1,
"first_name": "Jean",
"last_name": "Dupont",
"avatar_url": null,
"level": 5.0,
"team": null,
"position": null,
"status": "confirmed"
}
]
}
}
Endpoints authentifiés¶
Authentification requise
Tous les endpoints ci-dessous nécessitent un Bearer Token JWT dans le header Authorization.
POST /games — Créer une partie¶
Crée une nouvelle partie. Le créateur est automatiquement inscrit comme participant.
| Champ | Type | Obligatoire | Description |
|---|---|---|---|
type | string | ✅ | friendly ou competitive |
visibility | string | ✅ | public ou private |
environment | string | ✅ | indoor, semi_covered ou outdoor |
scheduled_at | string | ✅ | Date/heure ISO 8601 (dans le futur) |
duration_minutes | integer | ✅ | 60, 90, 120, 150 ou 180 |
location_type | string | ✅ | club ou custom |
club_id | integer | Conditionnel | Requis si location_type=club |
custom_location | string | Conditionnel | Requis si location_type=custom |
is_court_booked | boolean | ✅ | true ou false |
min_level | float | ✅ | Minimum 1.0 |
max_level | float | ✅ | Maximum 10.0, ≥ min_level |
sets_count | integer | ✅ | 1, 2 ou 3 |
GET /games/my — Mes parties¶
Liste les parties de l'utilisateur connecté (créées ou rejointes), triées par date décroissante.
POST /games/{game}/join — Rejoindre une partie¶
Inscrit l'utilisateur à une partie. Si son niveau est hors intervalle, le statut sera pending.
POST /games/{game}/leave — Quitter une partie¶
Retire l'utilisateur d'une partie. La partie repasse en open si elle n'est plus complète.
POST /games/{game}/cancel — Annuler une partie¶
Annule une partie. Réservé au créateur. Impossible si la partie est en cours ou terminée.
Statuts du cycle de vie¶
stateDiagram-v2
[*] --> open : Création
open --> full : 4 joueurs confirmés
full --> open : Un joueur quitte
full --> in_progress : Heure du match (auto)
in_progress --> finished : Fin manuelle ou +3h
finished --> score_validated : 4 joueurs valident
open --> cancelled : Annulation créateur
full --> cancelled : Annulation créateur | Statut | Description |
|---|---|
open | En attente de joueurs (< 4 confirmés) |
full | 4 joueurs inscrits, en attente du match |
in_progress | Match en cours |
finished | Match terminé, en attente de score |
score_validated | Score validé par les 4 joueurs |
cancelled | Annulé par le créateur |
Architecture backend¶
app/Domain/Game/
├── DTOs/
│ └── CreateGameDTO.php # Objet immuable de transfert
├── Repositories/
│ └── GameRepositoryInterface.php
└── Services/
└── GameService.php # Logique métier (créer, rejoindre, quitter, annuler)
app/Infrastructure/Repositories/
└── EloquentGameRepository.php # Implémentation Eloquent
app/Http/Controllers/Api/V1/
└── GameController.php # 7 actions avec annotations OpenAPI
app/Http/Requests/Game/
├── CreateGameRequest.php # Validation création
└── JoinGameRequest.php # Validation inscription
app/Http/Resources/
└── GameResource.php # Transformation JSON
Schéma de base de données¶
Table games¶
| Colonne | Type | Description |
|---|---|---|
id | bigint PK | Identifiant |
type | enum | friendly, competitive |
visibility | enum | public, private |
environment | enum | indoor, semi_covered, outdoor |
scheduled_at | timestamp | Date/heure du match |
duration_minutes | integer | Durée en minutes |
location_type | enum | club, custom |
club_id | FK nullable | Référence vers clubs |
custom_location | varchar | Adresse libre |
is_court_booked | boolean | Terrain réservé ? |
min_level | decimal(3,1) | Niveau minimum |
max_level | decimal(3,1) | Niveau maximum |
sets_count | integer | Nombre de sets |
status | enum | Statut du cycle de vie |
creator_id | FK | Référence vers users |
Table game_players (pivot)¶
| Colonne | Type | Description |
|---|---|---|
id | bigint PK | Identifiant |
game_id | FK | Référence vers games |
user_id | FK | Référence vers users |
team | enum null | A, B |
position | enum null | left, right |
status | enum | confirmed, pending |
joined_at | timestamp | Date d'inscription |