# StreakFit — Contrat d'API (v1) Base API : `https://api.streakfit.nfteam.ovh`. Front : `https://streakfit.nfteam.ovh`. **Auth = Sanctum SPA par COOKIE de session** (pas de token exposé au front). Cookie de session sur `.streakfit.nfteam.ovh`. `SANCTUM_STATEFUL_DOMAINS=streakfit.nfteam.ovh`, `SESSION_DOMAIN=.streakfit.nfteam.ovh`, CORS `supports_credentials=true`, origine autorisée = le front. **Toute la logique est back.** Le front ne fait que : GET `/sanctum/csrf-cookie`, envoyer le cookie XSRF, afficher. ## Auth (couche functional/users) - `GET /sanctum/csrf-cookie` — pose le cookie XSRF (Sanctum). - `POST /register` `{name,email,password}` → 201, ouvre la session. Crée User (locale/units par défaut) + Streak vide. - `POST /login` `{email,password}` → 200 `{user}`, ouvre la session. - `POST /logout` → 204. - `GET /auth/oidc/redirect` → 302 vers pocket-id (authorization code + PKCE). État en session. - `GET /auth/oidc/callback?code&state` → échange le code (OIDC_ISSUER=https://pocket.nfteam.ovh, client via env OIDC_CLIENT_ID/SECRET, redirect OIDC_REDIRECT_URI), lie/crée le user par `oidc_sub` puis `email`, ouvre la session, **302 vers APP_FRONT_URL**. - `GET /api/me` (auth) → `{ user:{id,name,email,locale,units,timezone,avatar_url}, streak:{current,longest,freezes} }`. ## Exercices (public, lecture seule — couche exercises) - `GET /api/exercises?search=&body_part=&equipment=&target=&category=&per_page=` → pagination `{ data:[{id,name,slug,body_part,equipment,target,image_url,gif_url}], meta:{current_page,last_page,total} }`. - `GET /api/exercises/{id}?locale=fr|pt-BR|en` → `{id,name,slug,body_part,category,equipment,target,muscle_group, secondary_muscles[], instructions:[...étapes dans la locale (pt-BR→fallback en/fr)], image_url, gif_url, attribution}`. - `GET /api/exercises/facets` → valeurs distinctes pour filtres `{body_parts[],equipments[],targets[],categories[]}`. ## Routines (auth, scopées user — couche routines) CRUD REST : `GET/POST /api/routines`, `GET/PUT/DELETE /api/routines/{id}`. Routine = `{id,name,description,is_public,estimated_minutes, exercises:[{exercise_id,position,sets,target_reps,rest_seconds,tempo,target_weight,notes, exercise:{id,name,image_url,target}}]}`. POST/PUT accepte `exercises[]` (sync du pivot routine_exercises). ## Programmes (auth — couche programs) CRUD REST : `/api/programs`. Program = `{id,name,description,duration_weeks,days_per_week, slots:[{week,weekday,routine_id,label}]}`. ## Séances / tracking (auth — couche tracking) - `POST /api/sessions` `{routine_id?,title?}` → démarre une séance (status=active) → `{session}`. - `GET /api/sessions/{id}` → séance + setLogs. - `POST /api/sessions/{id}/sets` `{exercise_id,set_number,reps?,weight?,rpe?,duration_seconds?,distance_meters?,is_warmup?}` → log un set → `{set_log}`. - `POST /api/sessions/{id}/complete` `{ended_at?}` → passe status=completed (déclenche WorkoutCompleted → streak). → `{session, streak, unlocked_achievements[]}`. - `GET /api/history?per_page=` → séances completed paginées. - `GET /api/metrics` / `POST /api/metrics` `{measured_on,weight?,body_fat?,notes?}` — mensurations. ## Dashboard (LE cœur — couche streaks, controller view-model) - `GET /api/dashboard` (auth) → objet prêt-à-afficher : ``` { streak: { current, longest, freezes_available, last_active_date, flame_level (0..5 selon current), active_today (bool) }, week: { goal_sessions, done_sessions, days:[{date,done,source}] }, // 7 derniers jours recent_sessions: [ {id,title,started_at,total_volume,set_count} ], achievements: [ {key,earned_at,label} ], suggestion: { type:'routine'|'rest', routine_id?, label } // proposition prochaine séance } ``` - `GET /api/achievements` → liste complète des badges de l'user. ## Conventions - Tout scopé par `auth()->id()` (access-control lomkit ou policies) sauf exercices (public). - Réponses JSON camelCase OU snake_case — rester COHÉRENT (snake_case, comme ci-dessus). - Erreurs : 401 non authentifié, 403 non autorisé, 422 validation (format Laravel `{message,errors}`). - Pagination Laravel standard (`meta`, `links`).