ajoute l'API publique /api/v1 (bloc B, premier chantier)

Catalogue en lecture seule (labs, banque de quiz officielle, cours) -
choix d'Adam pour la première version, zéro donnée d'élève. Laravel
Sanctum, un jeton Bearer par développeur créé depuis /jetons-api (un
prof), portée catalogue:lire seulement. Quota par jeton (pas par
compte ni par IP) dans Redis via un limiteur nommé, 60 requêtes/minute.
Documentation : spécification OpenAPI 3.0 et page publique /api/docs.

Désactive /sanctum/csrf-cookie (config/sanctum.php) : l'API est en
jeton Bearer seulement, jamais en cookie de SPA.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Adam Belkacemi 2026-10-14 01:23:23 +02:00
parent 3b961209f5
commit ecf3dfb21d
22 changed files with 874 additions and 2 deletions

View file

@ -1075,3 +1075,26 @@ Deux décisions d'Adam pour finir la liste « avant le pilote ».
**Suite**
Les 4 points « avant le pilote » sont traités (2 résolus, 2 sciemment reportés avec l'accord d'Adam). Semaine 8 du bloc A : pilote avec une vraie classe — à organiser avec Adam (ce n'est pas une tâche de code).
## 2026-10-14 — Bloc B, premier chantier : l'API publique (/api/v1)
Le pilote (semaine 8) attend qu'Adam l'organise ; il demande de continuer en attendant. Premier chantier du bloc B (poste kDrive) listé au CLAUDE.md : une API publique. Avant de coder, j'ai demandé ce qu'elle doit exposer en premier — choix d'Adam : le catalogue en lecture seule (labs, banque de quiz officielle, cours), zéro donnée d'élève.
**Fait**
- Laravel Sanctum installé : un jeton Bearer par développeur, créé par un prof depuis `/jetons-api` (le jeton en clair n'est montré qu'une fois, même règle que le code secret d'un élève). Jeton à portée (`ability` Sanctum) `catalogue:lire` seulement — pas d'accès par défaut à autre chose si l'API grandit un jour.
- `routes/api.php`, préfixe `/v1` : `GET /labs`, `/labs/{identifiant}`, `/quiz`, `/quiz/{id}`, `/cours`, `/cours/{identifiant}`. Les quiz exposés sont seulement ceux de la banque officielle (partagés **et** avec un thème) : jamais les questions ni les réponses, seulement les métadonnées (titre, thème, nombre de questions) — un quiz partagé par un prof entre collègues reste interne à l'application.
- Quota par jeton (pas par compte ni par IP) dans Redis : un limiteur nommé `api` (`AppServiceProvider`), 60 requêtes/minute, clé = l'identifiant du jeton Sanctum. `CACHE_STORE=redis` était déjà la config de production (Horizon, sessions) : rien à ajouter côté infra.
- Documentation : spécification OpenAPI 3.0 (`public/openapi/v1.yaml`) et une page publique `/api/docs` (exemples `curl`, réponse type).
- Désactivé la route `/sanctum/csrf-cookie` (`config/sanctum.php`, `routes => false`) : elle n'a pas de sens ici, l'API est en jeton Bearer seulement, jamais en cookie de SPA — sa présence faisait d'ailleurs échouer le test qui vérifie que toute page publique répond 200 (elle répond 204, une page sans contenu, ce qui est correct mais pas un code que ce test attendait).
- 9 nouveaux tests Pest (109 au total) : pas de jeton → 401, jeton sans la bonne portée → 403, jeton révoqué → 401, contenu correct de chaque point d'accès, un quiz privé ou sans thème renvoie 404, les en-têtes de limite de débit sont présents, un prof crée/voit une fois/révoque son jeton, ne peut pas révoquer celui d'un autre prof.
**Comprendre**
Le choix qui limite le plus le risque ici : exposer seulement ce qui est déjà pensé comme public ou quasi-public dans l'application (le catalogue), jamais une donnée d'élève, même en lecture. Ça permet de vraiment montrer le savoir-faire attendu pour le poste kDrive (jeton, versionnage, quotas, documentation, tests) sans ouvrir de nouvelle surface RGPD à surveiller.
**Vérifié sur le serveur réel** (prof jetable, supprimé ensuite) : jeton créé depuis `/jetons-api`, affiché une seule fois ; `GET /api/v1/labs` sans jeton → 401, avec jeton → 200 avec les en-têtes `X-RateLimit-*` (60/59) et les vraies compétences du lab.yaml ; `/api/v1/cours` liste sans le contenu, `/api/v1/cours/{id}` avec ; `/api/v1/quiz` renvoie les 8 quiz de la banque officielle avec leur thème, jamais leurs questions ; lab inconnu → 404 ; jeton révoqué depuis la page → 401 immédiatement. `/api/docs` et `/openapi/v1.yaml` répondent. Rien touché chez Adam.
**Suite**
Prochain chantier du bloc B : cache Redis sur les lectures lourdes, avec mesure avant/après dans Grafana.