Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
4.1 KiB
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 paroidc_subpuisemail, 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).