Aller au contenu

API — Administration

Base URL

http://localhost:8010/api/v1

Authentification requise

Tous les endpoints admin nécessitent un token JWT valide (Authorization: Bearer <token>) et le rôle admin. En cas de rôle insuffisant, le serveur retourne 403 Forbidden.


Dashboard

GET /admin/dashboard — Tableau de bord KPIs

Retourne les indicateurs clés, les tendances et les clubs en attente.

{
  "data": {
    "kpis": {
      "total_users": 150,
      "total_games": 42,
      "total_clubs": 8,
      "activity_rate": 65.3,
      "pending_clubs": 2
    },
    "registration_trend": {
      "2025-07": 10,
      "2025-08": 15,
      "2025-09": 20
    },
    "games_trend": {
      "2025-07": 5,
      "2025-08": 8,
      "2025-09": 12
    },
    "level_distribution": [
      { "name": "Débutant", "min": 1, "max": 2, "count": 30 },
      { "name": "Intermédiaire", "min": 3, "max": 5, "count": 50 }
    ],
    "pending_clubs_list": [
      {
        "id": 1,
        "name": "Padel Club Paris",
        "city": "Paris",
        "created_at": "2025-12-01T10:00:00Z"
      }
    ]
  }
}

Niveaux de jeu

GET /admin/game-levels — Lister les niveaux

Retourne la liste de tous les niveaux de jeu triés par sort_order.

{
  "data": [
    {
      "id": 1,
      "name": "Débutant",
      "min_value": 1,
      "max_value": 2,
      "sort_order": 1,
      "created_at": "2025-01-01T00:00:00Z",
      "updated_at": "2025-01-01T00:00:00Z"
    }
  ]
}

POST /admin/game-levels — Créer un niveau

Champ Type Obligatoire Description
name string ✅ Nom unique du niveau
min_value integer ✅ Valeur minimale de la plage
max_value integer ✅ Valeur maximale de la plage
sort_order integer ❌ Ordre d'affichage
{
  "data": {
    "id": 4,
    "name": "Expert+",
    "min_value": 9,
    "max_value": 10,
    "sort_order": 4
  }
}
{
  "message": "The given data was invalid.",
  "errors": {
    "name": ["The name has already been taken."]
  }
}

PUT /admin/game-levels/{id} — Modifier un niveau

Mêmes champs que la création (tous optionnels).

{
  "data": {
    "id": 1,
    "name": "Débutant modifié",
    "min_value": 1,
    "max_value": 3,
    "sort_order": 1
  }
}

DELETE /admin/game-levels/{id} — Supprimer un niveau

{ "message": "Niveau de jeu supprimé avec succès." }

POST /admin/game-levels/restore-defaults — Restaurer les défauts

Supprime tous les niveaux et recrée ceux par défaut.

{
  "data": [
    { "id": 10, "name": "Débutant", "min_value": 1, "max_value": 2, "sort_order": 1 }
  ]
}

Utilisateurs

GET /admin/users — Lister les utilisateurs

Paramètre Type Description
search string Recherche par nom, prénom ou email
role string Filtre par rôle : player, club_manager, admin
min_level integer Filtre par niveau minimum
max_level integer Filtre par niveau maximum
page integer Numéro de page (défaut : 1)
per_page integer Éléments par page (défaut : 15)
{
  "data": [
    {
      "id": 1,
      "first_name": "Jean",
      "last_name": "Dupont",
      "email": "jean@example.com",
      "role": "player",
      "city": "Paris",
      "level": { "id": 1, "name": "Débutant" },
      "reliability_score": 85,
      "created_at": "2025-01-15T10:00:00Z"
    }
  ],
  "meta": {
    "current_page": 1,
    "last_page": 5,
    "per_page": 15,
    "total": 72
  }
}

GET /admin/users/{id} — Détail d'un utilisateur

{
  "data": {
    "id": 1,
    "first_name": "Jean",
    "last_name": "Dupont",
    "email": "jean@example.com",
    "role": "player",
    "city": "Paris",
    "level": { "id": 1, "name": "Débutant" },
    "reliability_score": 85,
    "email_verified_at": "2025-01-15T10:00:00Z",
    "created_at": "2025-01-15T10:00:00Z"
  },
  "statistics": {
    "total_games": 12,
    "wins": 8,
    "losses": 4,
    "clubs_managed": 0
  }
}

Clubs

GET /admin/clubs — Lister les clubs

Paramètre Type Description
search string Recherche par nom ou ville
status string Filtre par statut : pending, validated, suspended
page integer Numéro de page (défaut : 1)
per_page integer Éléments par page (défaut : 15)
{
  "data": [
    {
      "id": 1,
      "name": "Padel Club Paris",
      "city": "Paris",
      "address": "123 Rue du Padel",
      "status": "pending",
      "logo_url": null,
      "owner": {
        "id": 10,
        "first_name": "Sophie",
        "last_name": "Martin"
      },
      "created_at": "2025-12-01T10:00:00Z"
    }
  ],
  "meta": {
    "current_page": 1,
    "last_page": 1,
    "per_page": 15,
    "total": 2
  }
}

GET /admin/clubs/{id} — Détail d'un club

{
  "data": {
    "id": 1,
    "name": "Padel Club Paris",
    "city": "Paris",
    "address": "123 Rue du Padel",
    "status": "validated",
    "description": "Club de padel premium",
    "phone": "01 23 45 67 89",
    "email": "contact@padelclubparis.com",
    "website": "https://padelclubparis.com",
    "owner": { "id": 10, "first_name": "Sophie", "last_name": "Martin" },
    "terrains": [],
    "created_at": "2025-12-01T10:00:00Z"
  }
}

POST /admin/clubs — Créer un club

Champ Type Obligatoire Description
name string ✅ Nom du club
address string ✅ Adresse
city string ✅ Ville
description string ❌ Description
phone string ❌ Téléphone
email string ❌ Email de contact
website string ❌ Site web
{
  "data": { "id": 3, "name": "Nouveau Club", "status": "validated" }
}

PUT /admin/clubs/{id} — Modifier un club

Mêmes champs que la création (tous optionnels).

DELETE /admin/clubs/{id} — Supprimer un club

{ "message": "Club supprimé avec succès." }

POST /admin/clubs/{id}/approve — Approuver un club

Change le statut d'un club pending vers validated.

{ "message": "Club approuvé avec succès." }

POST /admin/clubs/{id}/reject — Rejeter un club

Change le statut d'un club pending vers suspended.

{ "message": "Club rejeté." }

POST /admin/clubs/{id}/suspend — Suspendre un club

Change le statut d'un club validated vers suspended.

{ "message": "Club suspendu." }

Paramètres

GET /admin/settings — Récupérer tous les paramètres

{
  "data": {
    "cgu": {
      "key": "cgu",
      "value": "<p>Conditions générales d'utilisation...</p>",
      "type": "text"
    },
    "privacy_policy": {
      "key": "privacy_policy",
      "value": "<p>Politique de confidentialité...</p>",
      "type": "text"
    },
    "legal_mentions": {
      "key": "legal_mentions",
      "value": "<p>Mentions légales...</p>",
      "type": "text"
    },
    "faq": {
      "key": "faq",
      "value": [
        { "question": "Comment créer une partie ?", "answer": "..." }
      ],
      "type": "json"
    },
    "match_reminder_delay": {
      "key": "match_reminder_delay",
      "value": "2",
      "type": "number"
    }
  }
}

PUT /admin/settings — Mettre à jour les paramètres

Mise à jour en batch : envoyer uniquement les clés à modifier.

{
  "settings": {
    "cgu": "<p>Nouveau contenu CGU</p>",
    "match_reminder_delay": "24"
  }
}
{ "message": "Paramètres mis à jour avec succès." }

Route publique

GET /settings/{key} — Paramètre public

Accessible sans authentification. Clés autorisées : cgu, privacy_policy, legal_mentions, faq.

{
  "data": {
    "key": "cgu",
    "value": "<p>Conditions générales...</p>",
    "type": "text"
  }
}
{ "message": "Paramètre non trouvé." }

Logs système

GET /admin/logs — Lister les fichiers de log

Retourne la liste des fichiers de log journaliers disponibles sur le serveur.

{
  "data": [
    {
      "date": "2026-03-10",
      "size": 245760,
      "size_human": "240.0 KB",
      "entries_count": 142
    },
    {
      "date": "2026-03-09",
      "size": 512000,
      "size_human": "500.0 KB",
      "entries_count": 310
    }
  ]
}

GET /admin/logs/{date} — Consulter les entrées d'un fichier

Retourne les entrées de log d'un fichier journalier, avec filtrage et pagination.

Paramètre Type Description
date path Date au format YYYY-MM-DD
search query Filtrer par mot-clé dans le message
level query Filtrer par niveau (emergency, alert, critical, error, warning, notice, info, debug)
page query Numéro de page (défaut : 1)
per_page query Entrées par page (défaut : 50, max : 200)
sort query Tri : asc ou desc (défaut : desc)
{
  "data": [
    {
      "timestamp": "2026-03-10 14:30:22",
      "level": "error",
      "message": "Database connection timeout after 5000ms",
      "context": {
        "exception": "PDOException",
        "connection": "pgsql"
      },
      "extra": {}
    },
    {
      "timestamp": "2026-03-10 14:25:00",
      "level": "info",
      "message": "User logged in successfully",
      "context": {},
      "extra": {}
    }
  ],
  "meta": {
    "current_page": 1,
    "last_page": 3,
    "per_page": 50,
    "total": 142
  }
}
{ "message": "Log file not found for this date." }
{ "message": "Invalid date format. Expected YYYY-MM-DD." }

Sécurité

Le paramètre date est validé pour empêcher toute tentative de path traversal. Seuls les fichiers laravel-YYYY-MM-DD.log du répertoire storage/logs/ sont accessibles.


Analytics

POST /analytics/track — Enregistrer une visite (public)

Endpoint public

Cet endpoint ne nécessite pas d'authentification. Il est protégé par un rate limit de 60 requêtes/minute par IP.

Enregistre une visite de page de manière anonyme (sans lien avec un utilisateur).

{
  "session_id": "550e8400-e29b-41d4-a716-446655440000",
  "page_path": "/clubs/3",
  "referrer": "https://google.com",
  "duration_seconds": 45
}
Champ Type Requis Description
session_id string oui UUID de session (max 64 car.)
page_path string oui Chemin de la page (max 500 car.)
referrer string non URL référente
duration_seconds integer non Durée de visite en secondes (0–86400)
{ "message": "ok" }
{ "message": "Too Many Attempts." }

Données collectées automatiquement

Le backend déduit automatiquement : type d'appareil (User-Agent), pays (Accept-Language), hash anonyme de l'IP.


GET /admin/analytics/overview — KPIs globaux

Retourne les indicateurs clés de fréquentation pour une période donnée.

Paramètre Type Description
period query today, 7d, 30d, 90d (défaut : 7d)
{
  "data": {
    "unique_visitors": 342,
    "page_views": 1250,
    "avg_duration": 127.3,
    "bounce_rate": 35.2
  }
}

GET /admin/analytics/top-pages — Pages les plus visitées

Paramètre Type Description
period query today, 7d, 30d, 90d (défaut : 7d)
limit query Nombre max de résultats (défaut : 10, max : 50)
{
  "data": [
    {
      "page_path": "/",
      "views": 450,
      "unique_visitors": 280,
      "avg_duration": 95.2
    },
    {
      "page_path": "/clubs",
      "views": 220,
      "unique_visitors": 150,
      "avg_duration": 180.5
    }
  ]
}

GET /admin/analytics/trend — Courbe de visites

Paramètre Type Description
period query today, 7d, 30d, 90d (défaut : 30d)
granularity query day, week, month (défaut : day)
{
  "data": [
    { "date": "2026-03-08", "visits": 180, "unique_visitors": 95 },
    { "date": "2026-03-09", "visits": 210, "unique_visitors": 120 },
    { "date": "2026-03-10", "visits": 195, "unique_visitors": 110 }
  ]
}

GET /admin/analytics/devices — Répartition par appareil

Paramètre Type Description
period query today, 7d, 30d, 90d (défaut : 7d)
{
  "data": {
    "desktop": 180,
    "mobile": 120,
    "tablet": 25
  }
}

GET /admin/analytics/sources — Sources de trafic

Paramètre Type Description
period query today, 7d, 30d, 90d (défaut : 7d)
{
  "data": [
    { "source": "Direct", "visits": 150, "percentage": 46.2 },
    { "source": "https://google.com", "visits": 100, "percentage": 30.8 },
    { "source": "https://facebook.com", "visits": 75, "percentage": 23.1 }
  ]
}