diff --git a/README.md b/README.md index d2ed756..0a16ed3 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,16 @@
-# đŸ‹ïž ATHLY +# ATHLY -**Application mobile de fitness gamifiĂ©e — React Native + Node.js** +**Application mobile de fitness gamifiĂ©e. React Native, Expo, Node.js, MongoDB** ![React Native](https://img.shields.io/badge/React_Native-0.81.5-61DAFB?style=flat-square&logo=react) ![Expo](https://img.shields.io/badge/Expo-54-000020?style=flat-square&logo=expo) -![Node.js](https://img.shields.io/badge/Node.js-22.x-339933?style=flat-square&logo=node.js) +![Node.js](https://img.shields.io/badge/Node.js-20.x-339933?style=flat-square&logo=node.js) ![MongoDB](https://img.shields.io/badge/MongoDB-Atlas-47A248?style=flat-square&logo=mongodb) -![License](https://img.shields.io/badge/License-ISC-blue?style=flat-square) +![License](https://img.shields.io/badge/License-GPLv3-blue?style=flat-square) -> Transformez chaque sĂ©ance d'entraĂźnement en expĂ©rience de jeu. XP, streaks, quĂȘtes quotidiennes, trophĂ©es et rituels de rĂ©cupĂ©ration — progresser n'a jamais Ă©tĂ© aussi addictif. +Athly transforme chaque sĂ©ance d'entraĂźnement en expĂ©rience de jeu. XP, niveaux, streaks, quĂȘtes quotidiennes, plus de 60 trophĂ©es, 17 titres RPG, coffres Ă  ouvrir, amis, groupes de streak collective et lobby multijoueur : progresser n'a jamais Ă©tĂ© aussi complet.
@@ -20,25 +20,27 @@ ``` Athly/ -├── front/ ← Application mobile React Native (Expo) -└── back/ ← API REST Node.js / Express / MongoDB + front/ Application mobile et PWA, React Native (Expo) + back/ API REST, Node.js, Express, MongoDB + docs/ Documentation transverse (architecture de sĂ©curitĂ©) ``` -Les deux sous-projets ont chacun leur propre README dĂ©taillĂ© : -- [đŸ“± Documentation Front-end](front/README.md) — architecture, composants, gamification -- [⚙ Documentation Back-end](back/README.md) — API REST, modĂšles, tests +Chaque sous-projet a son propre README dĂ©taillĂ© : + +- [Documentation Front-end](front/README.md) : fonctionnalitĂ©s, architecture, gamification, navigation +- [Documentation Back-end](back/README.md) : API REST complĂšte, modĂšles de donnĂ©es, tests --- ## PrĂ©requis | Outil | Version minimale | -|-------|-----------------| -| Node.js | ≄ 18 | -| npm | ≄ 9 | +|-------|--------------------| +| Node.js | 18 ou supĂ©rieur | +| npm | 9 ou supĂ©rieur | | Expo Go (tĂ©lĂ©phone) | derniĂšre version | | Compte MongoDB Atlas | cluster M0 gratuit suffit | -| Compte SMTP | Brevo, Gmail, Yahoo
 | +| Compte SMTP | Brevo, ou Ă©quivalent | --- @@ -51,79 +53,74 @@ git clone https://github.com/ClemLy/Athly.git cd Athly ``` -### 2. Configurer le back-end +### 2. Configurer le backend ```bash cd back npm install - -# CrĂ©er le fichier de variables d'environnement cp .env.example .env -# → Ouvrir .env et remplir les valeurs (voir section ci-dessous) +# Ouvrir .env et remplir les valeurs, voir la section Variables d'environnement ``` -### 3. Configurer le front-end +### 3. Configurer le frontend ```bash cd ../front npm install - -# CrĂ©er le fichier de variables d'environnement cp .env.example .env -# → Renseigner l'IP locale de votre machine (voir section ci-dessous) +# Renseigner l'URL du backend, voir la section suivante ``` --- ## Variables d'environnement +Le dĂ©tail complet de chaque variable, avec son usage exact, se trouve dans les fichiers `.env.example` de chaque sous-projet. RĂ©sumĂ© minimal pour dĂ©marrer : + ### `back/.env` ```env -# Serveur PORT=4000 NODE_ENV=development - -# MongoDB Atlas — remplacer par votre URI de connexion MONGO_URI=mongodb+srv://:@.mongodb.net/athly - -# JWT — gĂ©nĂ©rer avec : node -e "console.log(require('crypto').randomBytes(64).toString('hex'))" -JWT_SECRET=votre_secret_jwt_long_et_aleatoire +JWT_SECRET=secret_long_et_aleatoire JWT_EXPIRES_IN=1d - -# SMTP — exemple avec Brevo SMTP_HOST=smtp-relay.brevo.com SMTP_PORT=587 SMTP_USER=votre_login_brevo SMTP_PASS=votre_cle_api_brevo SMTP_FROM=noreply@votre-domaine.com +# Optionnel, pour activer la connexion Google : +GOOGLE_CLIENT_IDS= +# Optionnel, pour restreindre le CORS en production : +CORS_ORIGINS= ``` ### `front/.env` ```env -# Adresse IP locale de votre machine (pas localhost — React Native ne le rĂ©sout pas) -# Sur Windows : ipconfig | grep IPv4 -# Sur macOS/Linux : ifconfig | grep "inet " +# Adresse IP locale de la machine, pas localhost : React Native sur un +# tĂ©lĂ©phone physique ne peut pas rĂ©soudre localhost. API_URL=http://VOTRE_IP_LOCALE:4000/api - -# ClĂ© de stockage du token JWT (SecureStore) TOKEN_KEY=athly_token - APP_ENV=development +# Optionnel, pour activer le bouton Google (un Client ID par plateforme) : +GOOGLE_EXPO_CLIENT_ID= +GOOGLE_IOS_CLIENT_ID= +GOOGLE_ANDROID_CLIENT_ID= +GOOGLE_WEB_CLIENT_ID= ``` -> **Trouver votre IP locale :** -> - Windows : `ipconfig` → chercher "Adresse IPv4" -> - macOS / Linux : `ifconfig` ou `ip addr` → chercher l'adresse en `192.168.x.x` +Trouver son IP locale : `ipconfig` sous Windows, `ifconfig` ou `ip addr` sous macOS et Linux. --- ## Lancer l'application -Ouvrir **deux terminaux** : +Ouvrir deux terminaux. + +**Terminal 1, backend** -**Terminal 1 — Back-end** ```bash cd back npm run dev @@ -131,108 +128,145 @@ npm run dev # VĂ©rification : curl http://localhost:4000/health ``` -**Terminal 2 — Front-end** +**Terminal 2, frontend** + ```bash cd front npm start -# Expo affiche un QR code → scanner avec Expo Go sur votre tĂ©lĂ©phone +# Expo affiche un QR code Ă  scanner avec Expo Go ``` -> Le tĂ©lĂ©phone et la machine doivent ĂȘtre sur **le mĂȘme rĂ©seau Wi-Fi**. +Le tĂ©lĂ©phone et la machine doivent ĂȘtre sur le mĂȘme rĂ©seau Wi-Fi. --- ## Architecture globale ``` -┌─────────────────────────────────────────────────────┐ -│ TÉLÉPHONE (Expo Go) │ -│ │ -│ React Native App │ -│ ├── AuthContext (JWT via SecureStore) │ -│ ├── WorkoutLogsContext (AsyncStorage — source vĂ©rité│ -│ ├── QuestContext · TutorialContext · ToastContext │ -│ └── 8 services front (stats, quĂȘtes, auth
) │ -│ │ -│ Axios → http://192.168.x.x:4000/api │ -└──────────────────────────┬──────────────────────────┘ - │ rĂ©seau local -┌──────────────────────────▌──────────────────────────┐ -│ NODE.JS API (port 4000) │ -│ │ -│ Routes → Controllers → Services → Mongoose │ -│ ├── /api/auth (register, login, OTP, reset) │ -│ ├── /api/users (profil, RGPD) │ -│ ├── /api/workouts (CRUD, draft, finalize) │ -│ └── /api/exercises (performances, historique) │ -│ │ -│ MongoDB Atlas (cloud) Brevo SMTP │ -└─────────────────────────────────────────────────────┘ +TĂ©lĂ©phone ou navigateur (Expo Go, PWA) + React Native / React Native Web + AuthContext (JWT via SecureStore) + UserContext, WorkoutLogsContext, QuestContext, + SavedWorkoutsContext, CustomExercisesContext, + TutorialContext, ToastContext + 17 services front, exposĂ©s via un barrel unique + + Axios -> http://votre-serveur:4000/api + +API Node.js (port 4000) + Routes -> Controllers -> Services -> Mongoose + /api/auth inscription, connexion, OTP, Google, rĂ©initialisation + /api/users profil, cadre Ă©quipĂ©, vitrines, synchronisation XP, RGPD + /api/workouts sĂ©ances, brouillons, finalisation, anti-triche + /api/exercises performances, historique, classement + /api/friends amis, demandes, classement, profil public + /api/inventory coffres, objets, cosmĂ©tiques Uniques + /api/groups groupes de streak collective + /api/rewards trophĂ©es serveur, anniversaire + /api/referral parrainage + /api/profile titres RPG + /api/lobby lobby multijoueur + /api/activity flux d'activitĂ© et rĂ©actions + /api/weight historique de poids + /api/debug outillage God Mode, bloquĂ© en production + + MongoDB Atlas Brevo SMTP Google OAuth (optionnel) ``` -**RĂ©partition des responsabilitĂ©s :** +### RĂ©partition des responsabilitĂ©s | FonctionnalitĂ© | Stockage | Calcul | -|---------------|----------|--------| -| Authentification | MongoDB (back) | back | -| Profil utilisateur | MongoDB (back) | back | -| Logs de sĂ©ances | AsyncStorage (front) | front | -| XP, streak, niveau | AsyncStorage (front) | front | -| QuĂȘtes quotidiennes | AsyncStorage (front) | front | -| Rituels de rĂ©cupĂ©ration | AsyncStorage (front) | front | -| Sync sĂ©ances | MongoDB (best-effort) | front → back | +|-----------------|----------|--------| +| Authentification | MongoDB (backend) | backend | +| Profil utilisateur | MongoDB (backend) | backend | +| Social, groupes, lobby, inventaire, titres | MongoDB (backend) | backend | +| Logs de sĂ©ances | AsyncStorage (frontend) | frontend | +| XP, streak, niveau local | AsyncStorage (frontend) | frontend | +| QuĂȘtes quotidiennes, rituels | AsyncStorage (frontend) | frontend | +| Synchronisation de l'XP totale | MongoDB, best effort | frontend calcule, backend fait autoritĂ© | --- -## Build APK (Android) +## Build (Android et PWA) -Pour gĂ©nĂ©rer un APK de production via EAS Build : +### APK Android via EAS Build ```bash cd front - -# Installer EAS CLI (une seule fois) npm install -g eas-cli eas login - -# Build production eas build --platform android --profile production ``` -Le profil `production` dans `eas.json` pointe vers l'API dĂ©ployĂ©e sur Render (`https://athly-api.onrender.com`). Pour viser votre propre backend, modifier `API_URL` dans la section `env` du profil `production` de `eas.json`. +Le profil `production` dans `front/eas.json` pointe vers l'API dĂ©ployĂ©e. Pour cibler un autre backend, modifier `API_URL` dans la section `env` de ce profil. + +### PWA web + +```bash +cd front +npm run build:web +# expo export --platform web, puis copie du service worker +``` --- ## Tests -**Back-end** +**Backend** + ```bash cd back npm test ``` -73 tests : formule XP/niveau (24), anti-cheat serveur (13), intĂ©gritĂ© des schĂ©mas Mongoose (36). Les tests unitaires tournent sans connexion MongoDB. -**Front-end** +26 fichiers de tests, exĂ©cutĂ©s contre une instance MongoDB en mĂ©moire, sans dĂ©pendance rĂ©seau externe. Couvre l'authentification, le profil, les sĂ©ances, le social, les groupes, l'inventaire, les trophĂ©es, les titres, le lobby multijoueur et l'ensemble des formules de gamification. + +**Frontend** + ```bash cd front npm test ``` +3 suites Jest sur les modules de donnĂ©es et services purs. + +--- + +## IntĂ©gration continue + +Le workflow GitHub Actions (`.github/workflows/ci.yml`) exĂ©cute deux jobs indĂ©pendants, filtrĂ©s par dossier modifiĂ© : + +- Backend : lint, vĂ©rification syntaxique, audit de sĂ©curitĂ© npm, suite de tests complĂšte, sans base de donnĂ©es externe. +- Frontend : audit de sĂ©curitĂ© npm, build de la PWA (`expo export --platform web`), pour dĂ©tecter tout composant natif incompatible avec le web. + --- ## DĂ©ploiement | Composant | Plateforme | Notes | -|-----------|-----------|-------| -| Back-end | Render (Free tier) | Cold-start ~20s — absorbĂ© par le timeout Axios 30s du front | +|-----------|------------|-------| +| Backend | Render (tier gratuit) | DĂ©marrage Ă  froid d'environ 20 secondes, absorbĂ© par le timeout Axios du front | | Base de donnĂ©es | MongoDB Atlas M0 | Gratuit | -| Emails | Brevo SMTP | Tier gratuit : 300 emails/jour | -| App mobile | EAS Build | APK Android via `eas build --profile production` | +| Emails | Brevo SMTP | Tier gratuit Ă  300 emails par jour | +| Application mobile | EAS Build | APK Android via `eas build --profile production` | +| PWA | Build statique | `npm run build:web`, Ă  hĂ©berger sur tout service de fichiers statiques | + +--- + +## SĂ©curitĂ© + +Le dĂ©tail complet des protections (headers HTTP, rate limiting, validation, assainissement anti-injection, tolĂ©rance aux pannes) est documentĂ© dans [docs/ARCHITECTURE-SECURITE.md](docs/ARCHITECTURE-SECURITE.md). + +--- + +## Licence + +DistribuĂ© sous licence GNU GPLv3. Voir le fichier [LICENSE](LICENSE). ---
-Athly · React Native + Expo · Node.js + Express · MongoDB Atlas +Athly : React Native + Expo, Node.js + Express, MongoDB Atlas
diff --git a/back/README.md b/back/README.md index c109bb1..554d8b6 100644 --- a/back/README.md +++ b/back/README.md @@ -1,1212 +1,759 @@
-# ⚙ ATHLY — API Backend +# ATHLY : API Backend -**Node.js · Express · MongoDB · JWT · Nodemailer** +**Node.js, Express, MongoDB, JWT, Google OAuth, Nodemailer** -![Node.js](https://img.shields.io/badge/Node.js-22.x-339933?style=flat-square&logo=node.js) +![Node.js](https://img.shields.io/badge/Node.js-20.x-339933?style=flat-square&logo=node.js) ![Express](https://img.shields.io/badge/Express-5.2.1-000000?style=flat-square&logo=express) ![MongoDB](https://img.shields.io/badge/MongoDB-Mongoose_9-47A248?style=flat-square&logo=mongodb) -![JWT](https://img.shields.io/badge/Auth-JWT_+_OTP-orange?style=flat-square) +![JWT](https://img.shields.io/badge/Auth-JWT_+_OTP_+_Google-orange?style=flat-square) ![Jest](https://img.shields.io/badge/Tests-Jest_30-C21325?style=flat-square&logo=jest) -> API REST pour l'application mobile Athly. GĂšre l'authentification (JWT + OTP email), les profils utilisateurs, les sĂ©ances d'entraĂźnement et la synchronisation des performances. +API REST pour l'application mobile Athly. GĂšre l'authentification (mot de passe, OTP email, Google OAuth), les profils, les sĂ©ances d'entraĂźnement, ainsi que l'ensemble du systĂšme social et de gamification (amis, groupes de streak, coffres, titres, trophĂ©es, lobby multijoueur, parrainage).
--- -## 📋 Table des matiĂšres - -1. [Vue d'ensemble](#-vue-densemble) -2. [Stack technique](#-stack-technique) -3. [Installation & lancement](#-installation--lancement) -4. [Variables d'environnement](#-variables-denvironnement) -5. [Structure du projet](#-structure-du-projet) -6. [Architecture](#-architecture) -7. [Authentification](#-authentification) -8. [Documentation API](#-documentation-api) - - [Auth — `/api/auth`](#1-auth--apiauth) - - [Utilisateurs — `/api/users`](#2-utilisateurs--apiusers) - - [SĂ©ances — `/api/workouts`](#3-sĂ©ances--apiworkouts) - - [Exercices — `/api/exercises`](#4-exercices--apiexercises) -9. [ModĂšles de donnĂ©es](#-modĂšles-de-donnĂ©es) -10. [Services & logique mĂ©tier](#-services--logique-mĂ©tier) -11. [Tests](#-tests) -12. [IntĂ©gration continue (CI)](#-intĂ©gration-continue-ci) -13. [SĂ©curitĂ©](#-sĂ©curitĂ©) +## Table des matiĂšres + +1. [Vue d'ensemble](#vue-densemble) +2. [Stack technique](#stack-technique) +3. [Installation et lancement](#installation-et-lancement) +4. [Variables d'environnement](#variables-denvironnement) +5. [Structure du projet](#structure-du-projet) +6. [Architecture](#architecture) +7. [Authentification](#authentification) +8. [Documentation de l'API](#documentation-de-lapi) +9. [ModĂšles de donnĂ©es](#modĂšles-de-donnĂ©es) +10. [Services et logique mĂ©tier](#services-et-logique-mĂ©tier) +11. [Catalogues de donnĂ©es](#catalogues-de-donnĂ©es) +12. [Formules de gamification](#formules-de-gamification) +13. [Tests](#tests) +14. [IntĂ©gration continue](#intĂ©gration-continue) +15. [SĂ©curitĂ©](#sĂ©curitĂ©) --- -## 🎯 Vue d'ensemble +## Vue d'ensemble -L'API Athly est un backend **Node.js + Express + MongoDB** indispensable au fonctionnement de l'application mobile. L'authentification (connexion, inscription, vĂ©rification email) passe obligatoirement par ce backend. Une fois connectĂ©, les donnĂ©es de progression (logs, XP, quĂȘtes) sont calculĂ©es et stockĂ©es cĂŽtĂ© client (AsyncStorage) ; le backend reçoit les sĂ©ances finalisĂ©es en best-effort pour la persistance cloud. +L'API Athly est un backend Node.js, Express et MongoDB. L'authentification (inscription, connexion, vĂ©rification email, connexion Google, rĂ©initialisation de mot de passe) passe obligatoirement par ce backend. Une fois connectĂ©, les donnĂ©es de progression immĂ©diate (logs de sĂ©ances, XP calculĂ©, quĂȘtes, rituels) sont calculĂ©es et stockĂ©es cĂŽtĂ© client dans AsyncStorage pour la fluiditĂ©, tandis que le backend fait autoritĂ© pour tout ce qui touche Ă  la persistance cloud, au multijoueur et aux fonctionnalitĂ©s sociales : profil, inventaire, coffres, titres, trophĂ©es, amis, groupes de streak et lobby multijoueur. ### RĂŽle du backend | Fonction | Description | -|----------|-------------| -| **Authentification** | Inscription, connexion JWT, vĂ©rification email OTP, reset password | -| **Profil utilisateur** | DonnĂ©es physiques, objectifs, Ă©quipements, XP/niveau | -| **SĂ©ances** | CrĂ©ation, finalisation, historique des workouts | -| **Performances** | Enregistrement des sĂ©ries, historique par exercice | -| **Exercices externes** | Proxy vers l'API WGER (catalogue 1000+ exercices) | -| **Email transactionnel** | Codes OTP via SMTP Yahoo (Nodemailer) | - ---- - -## 🛠 Stack technique +|----------|--------------| +| Authentification | Inscription, connexion par mot de passe, connexion Google OAuth, vĂ©rification email par OTP, rĂ©initialisation de mot de passe | +| Profil utilisateur | DonnĂ©es physiques, objectifs, Ă©quipements, XP et niveau, cadre de profil Ă©quipĂ©, RGPD | +| SĂ©ances | CrĂ©ation, brouillon, finalisation, historique, anti-triche serveur | +| Performances | Enregistrement des sĂ©ries par exercice, historique de progression, classement par exercice | +| Synchronisation XP | RĂ©ception de l'XP totale calculĂ©e cĂŽtĂ© client, recalcul du niveau et du rang, ratchet anti-rĂ©gression | +| Inventaire et coffres | Ouverture de coffres, utilisation d'objets, rĂ©clamation de cosmĂ©tiques Uniques | +| Amis et classement | Demandes d'amis, liste, recherche par tag, classement XP, profil public | +| Groupes de streak | Groupe de 5 membres maximum, invitations, streak collective, action Secouer | +| Titres RPG | Catalogue de 17 titres dĂ©blocables, Ă©quipement | +| TrophĂ©es | Catalogue serveur, synchronisation des trophĂ©es locaux, anniversaire, parrainage | +| Lobby multijoueur | CrĂ©ation de lobby, invitations, statut prĂȘt, bonus d'XP de groupe | +| Flux d'activitĂ© | RĂ©actions entre amis (bravo, respect, hue, jaloux) sur des Ă©vĂ©nements marquants | +| Poids | Historique de pesĂ©es | +| Email transactionnel | Codes OTP et notifications via SMTP (Brevo) | +| Notifications push | Enregistrement du token Expo, envoi via expo-server-sdk | +| Outillage de test (God Mode) | Endpoints rĂ©servĂ©s au dĂ©veloppement pour simuler des Ă©tats de jeu | + +--- + +## Stack technique | Couche | Technologie | Version | |--------|-------------|---------| -| Runtime | Node.js | ≄ 18 | +| Runtime | Node.js | 20.x (CI), 18+ en local | | Framework HTTP | Express | 5.2.1 | -| ODM | Mongoose | 9.0.0 | -| Base de donnĂ©es | MongoDB Atlas | — | -| Authentification | JSON Web Token | 9.0.3 | -| Hash passwords | bcrypt | 6.0.0 | -| Email | Nodemailer (SMTP) | 8.0.10 | -| Validation | Joi | 18.0.2 | +| ODM | Mongoose | 9.7.3 | +| Base de donnĂ©es | MongoDB Atlas (production), mongodb-memory-server (tests) | | +| Authentification par mot de passe | JSON Web Token | 9.0.3 | +| Authentification sociale | google-auth-library | 10.x | +| Hash des mots de passe | bcrypt | 6.0.0 | +| Email | Nodemailer (SMTP) | 9.0.3 | +| Notifications push | expo-server-sdk | 6.x | +| Validation | Joi | 18.2.3 | | SĂ©curitĂ© HTTP | Helmet | 8.0.0 | +| Rate limiting | express-rate-limit | 8.x | | CORS | cors | 2.8.5 | | Logging | Morgan | 1.10.0 | -| Variables d'env | dotenv | 17.2.3 | -| Tests | Jest + Supertest | 30.2.0 | +| Variables d'environnement | dotenv | 17.2.3 | +| Tests | Jest, Supertest, mongodb-memory-server | 30.4.2 | | Dev | Nodemon | 3.1.11 | --- -## 🚀 Installation & lancement +## Installation et lancement ### PrĂ©requis -- Node.js ≄ 18 -- Un cluster MongoDB (local ou Atlas) -- Un compte SMTP pour l'envoi d'emails (Yahoo, Gmail, etc.) +- Node.js 18 ou supĂ©rieur +- Un cluster MongoDB (Atlas ou local) pour la production. Les tests n'en nĂ©cessitent pas : ils dĂ©marrent leur propre instance en mĂ©moire. +- Un compte SMTP pour l'envoi d'emails (Brevo recommandĂ©, tier gratuit Ă  300 emails par jour) +- Optionnel : des Client IDs Google OAuth si la connexion Google doit ĂȘtre active ### Étapes ```bash -# 1. Cloner le dĂ©pĂŽt git clone https://github.com/ClemLy/Athly.git cd Athly/back -# 2. Installer les dĂ©pendances npm install -# 3. Configurer les variables d'environnement cp .env.example .env -# Éditer .env (voir section suivante) - -# 4. Lancer en dĂ©veloppement (avec hot-reload) -npm run dev +# Éditer .env, voir la section Variables d'environnement ci-dessous -# 5. Lancer en production -npm start +npm run dev # dĂ©veloppement, avec rechargement Ă  chaud (nodemon) +npm start # production ``` ### VĂ©rifier que le serveur tourne ```bash curl http://localhost:4000/health -# → {"status":"OK","uptime":42.3} +# {"status":"OK","uptime":42.3} ``` --- -## 🔑 Variables d'environnement +## Variables d'environnement -CrĂ©er un fichier `.env` Ă  la racine du projet : +Toutes les variables sont documentĂ©es avec leur usage exact dans `.env.example`. RĂ©sumĂ© : ```env # Serveur PORT=4000 NODE_ENV=development -# MongoDB +# MongoDB (obligatoire au dĂ©marrage) MONGO_URI=mongodb+srv://:@.mongodb.net/?retryWrites=true&w=majority -# JWT -JWT_SECRET=votre_secret_jwt_tres_long_et_aleatoire +# JWT (obligatoire au dĂ©marrage) +JWT_SECRET=secret_long_et_aleatoire JWT_EXPIRES_IN=1d -# Email SMTP (exemple avec Yahoo) -SMTP_HOST=smtp.mail.yahoo.com -SMTP_PORT=465 -SMTP_USER=votre.adresse@yahoo.fr -SMTP_PASS=votre_app_password_yahoo -``` - -> **Important :** Ne jamais committer le `.env` — il est dans `.gitignore`. Les credentials SMTP doivent ĂȘtre des **app passwords** (pas votre mot de passe principal). - ---- - -## 📁 Structure du projet - -``` -back-projet-final-ClemLy/ -├── server.js # Point d'entrĂ©e : listen() -├── app.js # Config Express, routes, middlewares -├── package.json -├── jest.config.js # Configuration Jest -├── eslint.config.mjs # Configuration ESLint -│ -├── config/ -│ ├── db.js # Connexion Mongoose (connectDB) -│ └── env.js # Validation et export des variables d'env -│ -├── controllers/ # Handlers HTTP (entrĂ©e/sortie) -│ ├── auth.controller.js # register, login, verifyEmail, forgotPassword
 -│ ├── user.controller.js # getMe, updateMe, deleteAccount -│ ├── workout.controller.js # CRUD sĂ©ances, draft, finalize, complete -│ └── exercise.controller.js # createRecord, getHistory, getByWorkout -│ -├── services/ # Logique mĂ©tier (pur, testable) -│ ├── auth.service.js # CrĂ©ation compte, OTP, JWT -│ ├── user.service.js # Profil, XP/level, suppression cascade -│ ├── workout.service.js # Calculs volume, XP sĂ©ance, draft/finalize -│ ├── exercise.service.js # Records, historique progressions -│ ├── email.service.js # Templates HTML + envoi SMTP -│ └── wger.service.js # Proxy API WGER (exercices externes) -│ -├── models/ # SchĂ©mas Mongoose -│ ├── User.js -│ ├── Workout.js -│ └── ExerciseRecord.js -│ -├── routes/ # DĂ©claration des routes -│ ├── auth.routes.js -│ ├── user.routes.js -│ ├── workout.routes.js -│ └── exercise.routes.js -│ -├── middleware/ -│ ├── auth.middleware.js # VĂ©rification JWT (protect) -│ ├── validate.middleware.js # Validation Joi (validateBody) -│ ├── error.middleware.js # Gestionnaire d'erreurs global -│ └── not-found.middleware.js # 404 handler -│ -├── validators/ # SchĂ©mas Joi -│ ├── auth.validator.js -│ ├── user.validator.js -│ ├── workout.validator.js -│ └── exercise.validator.js -│ -├── tests/ -│ ├── levelHelpers.test.js # Formule XP/niveau — 24 tests (unitaires) -│ ├── workoutAnticheat.test.js # Anti-cheat serveur — 13 tests (mocks Mongoose) -│ ├── modelsIntegrity.test.js # IntĂ©gritĂ© des schĂ©mas Mongoose — 36 tests -│ ├── auth.test.js -│ ├── user.test.js -│ ├── workout.test.js -│ ├── exercise.test.js -│ └── health.test.js -│ -├── utils/ -│ └── levelHelpers.js # Source de vĂ©ritĂ© XP/niveau (xpForLevel, levelFromXP) -│ -└── scripts/ - └── populateWorkouts.js # Seed de donnĂ©es de test -``` - ---- - -## 🏗 Architecture +# Refresh token (optionnel, non utilisĂ© par l'implĂ©mentation actuelle) +REFRESH_TOKEN_SECRET= +REFRESH_TOKEN_EXPIRES_IN=7d + +# Email SMTP (exemple Brevo) +SMTP_HOST=smtp-relay.brevo.com +SMTP_PORT=587 +SMTP_USER=votre_login_brevo +SMTP_PASS=votre_cle_api_brevo +SMTP_FROM=noreply@votre-domaine.com + +# Google OAuth (optionnel : sans valeur, POST /api/auth/google rĂ©pond 501) +# Liste sĂ©parĂ©e par des virgules : un Client ID par plateforme front +# (iOS, Android, Web, Expo Go), car le claim "aud" du token contient +# exactement celui qui l'a Ă©mis. +GOOGLE_CLIENT_IDS= + +# CORS (production uniquement) +# Allowlist des origines web autorisĂ©es, sĂ©parĂ©es par des virgules. +# Les requĂȘtes sans header Origin (app mobile native) ne sont pas concernĂ©es. +# Non dĂ©finie : comportement permissif en dĂ©veloppement, avertissement en production. +CORS_ORIGINS= +``` + +Ne jamais committer le fichier `.env` : il est dans `.gitignore`. Les identifiants SMTP doivent ĂȘtre des clĂ©s d'application dĂ©diĂ©es, jamais un mot de passe de compte personnel. + +--- + +## Structure du projet + +``` +back/ + server.js Point d'entrĂ©e : connexion DB puis listen() + app.js Configuration Express : middlewares, montage des routes + eslint.config.mjs + jest.config.js + + config/ + db.js Connexion Mongoose (connectDB) + env.js Lecture et validation des variables d'environnement + + models/ 8 schĂ©mas Mongoose + User.js + Workout.js + ExerciseRecord.js + Friendship.js + StreakGroup.js + WorkoutLobby.js + ActivityEvent.js + WeightHistory.js + + controllers/ 14 fichiers, handlers HTTP + auth.controller.js + user.controller.js + workout.controller.js + exercise.controller.js + friend.controller.js + inventory.controller.js + groupStreak.controller.js + reward.controller.js + referral.controller.js + title.controller.js + workoutLobby.controller.js + weight.controller.js + activity.controller.js + debug.controller.js + + services/ 9 fichiers, logique mĂ©tier pure et testable + auth.service.js + user.service.js + workout.service.js + exercise.service.js + email.service.js + push.service.js + chest.service.js + inventory.service.js + activity.service.js + + routes/ 14 fichiers, dĂ©claration des endpoints + validators/ 7 fichiers, schĂ©mas Joi + middleware/ + auth.middleware.js VĂ©rification JWT (protect) + devOnly.middleware.js Bloque une route en production (404) + validate.middleware.js Validation Joi du corps de requĂȘte + sanitize.middleware.js Assainissement anti-injection NoSQL + rateLimit.middleware.js Limiteurs global et authentification + error.middleware.js Gestionnaire d'erreurs global + not-found.middleware.js 404 handler + + data/ + titleCatalog.js 17 titres RPG dĂ©blocables + localTrophyCatalog.js Miroir des 40 trophĂ©es locaux du front, plus le trophĂ©e Souverain Absolu + shakeMessages.js Messages alĂ©atoires du bouton Secouer + + utils/ + levelHelpers.js Source de vĂ©ritĂ© XP et niveau (xpForLevel, levelFromXP, getRankForLevel) + profanityFilter.js Filtre de pseudos + + tests/ 26 fichiers de tests, voir la section Tests + scripts/ + populateWorkouts.js Seed de donnĂ©es de test + jest-staged.js UtilisĂ© par lint-staged +``` + +--- + +## Architecture ### Flux d'une requĂȘte ``` -Client (React Native) - │ - â–Œ +Client (React Native / PWA) + | + v Express Router - │ - ├─→ Middleware auth.middleware (JWT protect) - │ └─ VĂ©rifie Bearer token → req.user = payload - │ - ├─→ Middleware validate.middleware (Joi) - │ └─ Valide req.body contre le schĂ©ma - │ - â–Œ + | + +--> Middleware auth.middleware (JWT protect) + | VĂ©rifie le Bearer token, injecte req.user + | + +--> Middleware validate.middleware (Joi) + | Valide req.body contre le schĂ©ma de la route + | + v Controller - │ Handler HTTP : valide entrĂ©es, appelle service, retourne rĂ©ponse - â–Œ + | Handler HTTP : lit la requĂȘte, appelle le service, formate la rĂ©ponse + v Service - │ Logique mĂ©tier pure, indĂ©pendante d'Express - â–Œ + | Logique mĂ©tier pure, indĂ©pendante d'Express + v Model (Mongoose) - │ - â–Œ - MongoDB Atlas + | + v + MongoDB ``` +SĂ©paration stricte : les routes ne font que dĂ©clarer method plus path plus middleware plus controller. Les controllers ne contiennent aucune requĂȘte Mongoose directe pour la logique complexe (dĂ©lĂ©gation au service), Ă  l'exception de quelques controllers qui restent volontairement compacts pour des opĂ©rations simples de lecture ou d'Ă©criture directe (par exemple `activity.controller.js`, `weight.controller.js`). Les services ne connaissent jamais `req` ou `res`. + ### Gestion des erreurs -Toutes les erreurs non gĂ©rĂ©es remontent au middleware `error.middleware.js` qui normalise le format : +Toutes les erreurs non gĂ©rĂ©es remontent au middleware `error.middleware.js`, qui normalise la rĂ©ponse : ```json { - "status": "error", + "success": false, "message": "Description de l'erreur", - "code": 400 + "status": 400 } ``` +### RĂ©silience + +- `unhandledRejection` est loguĂ© sans tuer le process. +- `uncaughtException` dĂ©clenche un arrĂȘt propre (log puis exit, l'orchestrateur redĂ©marre). +- ArrĂȘt gracieux sur SIGTERM et SIGINT : drain des requĂȘtes en cours, fermeture de la connexion MongoDB, garde-fou de 10 secondes. +- MongoDB se reconnecte automatiquement en cas de coupure (Mongoose), les Ă©vĂ©nements sont loguĂ©s. +- Les opĂ©rations sensibles Ă  la concurrence (par exemple la consommation du dernier objet d'inventaire) utilisent des mises Ă  jour atomiques (`findOneAndUpdate` conditionnel avec `$inc`), pas de lecture puis Ă©criture. + +Voir `docs/ARCHITECTURE-SECURITE.md` Ă  la racine du dĂ©pĂŽt pour le dĂ©tail complet des protections et de la tolĂ©rance aux pannes. + --- -## 🔐 Authentification +## Authentification -### Flux complet d'inscription +### Inscription par email ``` POST /api/auth/register - └─ CrĂ©e le compte (isVerified: false) - └─ GĂ©nĂšre un code OTP 6 chiffres (valide 10 min) - └─ Envoie un email avec le code - │ - â–Œ + CrĂ©e le compte (isVerified: false) + GĂ©nĂšre un code OTP Ă  6 chiffres, valide 10 minutes + Envoie un email avec le code + GĂ©nĂšre un code de parrainage et un discriminant Ă  4 chiffres + POST /api/auth/verify-email - └─ VĂ©rifie le code OTP - └─ isVerified → true - └─ Retourne JWT token (connexion automatique) + VĂ©rifie le code OTP + isVerified passe Ă  true + Retourne le token JWT (connexion automatique) ``` -### Flux de reset password +### Connexion Google ``` -POST /api/auth/forgot-password - └─ GĂ©nĂšre un code reset (valide 15 min) - └─ Envoie l'email - │ - â–Œ -POST /api/auth/reset-password - └─ VĂ©rifie le code - └─ Hash le nouveau password (bcrypt) - └─ Invalide le code +POST /api/auth/google + VĂ©rifie l'idToken auprĂšs de Google (audience parmi GOOGLE_CLIENT_IDS) + CrĂ©e le compte au premier login (isVerified: true d'office, email garanti par Google) + Retourne le token JWT ``` -### Protection brute-force - -- Maximum **5 tentatives** de vĂ©rification OTP avant blocage -- Les codes OTP expirent automatiquement (10 min vĂ©rif, 15 min reset) -- Mongoose TTL index sur `codeExpires` - -### Utiliser le token JWT +Sans `GOOGLE_CLIENT_IDS` configurĂ© cĂŽtĂ© serveur, la route rĂ©pond 501 plutĂŽt que de faire planter le dĂ©marrage du serveur. -Toutes les routes protĂ©gĂ©es nĂ©cessitent : +### RĂ©initialisation de mot de passe ``` -Authorization: Bearer -``` - -Le token expire selon `JWT_EXPIRES_IN` (dĂ©faut : `1d`). - ---- - -## 📖 Documentation API - -**Base URL :** `http://votre-serveur:4000/api` - ---- +POST /api/auth/forgot-password + GĂ©nĂšre un code de rĂ©initialisation, valide 15 minutes + Envoie l'email + RĂ©pond toujours 200, mĂȘme si l'email n'existe pas (ne rĂ©vĂšle jamais l'existence d'un compte) -### 1. Auth — `/api/auth` +POST /api/auth/reset-password + VĂ©rifie le code + Hash le nouveau mot de passe + Invalide le code +``` -Toutes ces routes sont **publiques** (pas de JWT requis). +### Protection contre le brute-force ---- +- Maximum 5 tentatives de vĂ©rification OTP avant blocage (nĂ©cessite un nouveau code). +- Les codes OTP expirent automatiquement (10 minutes pour la vĂ©rification, 15 minutes pour la rĂ©initialisation). +- Le rate limiter d'authentification limite Ă  20 requĂȘtes par 15 minutes, avec une clĂ© combinant IP et email ciblĂ©. -#### `POST /api/auth/register` - -CrĂ©er un nouveau compte utilisateur. +### Utiliser le token JWT -**Body** -```json -{ - "pseudo": "AthlĂšteExemple", - "email": "athlete@mail.com", - "password": "motdepasse123" -} ``` - -**RĂ©ponse 201** -```json -{ - "message": "Compte créé. VĂ©rifiez votre email.", - "email": "athlete@mail.com" -} +Authorization: Bearer ``` -**Erreurs** -| Code | Cause | -|------|-------| -| 400 | Email dĂ©jĂ  utilisĂ© | -| 422 | Validation Joi Ă©chouĂ©e (email invalide, password trop court) | +Expiration selon `JWT_EXPIRES_IN` (dĂ©faut 1 jour). Algorithme Ă©pinglĂ© HS256, jamais de log du token ou des headers d'authentification. --- -#### `POST /api/auth/login` +## Documentation de l'API -Connexion et rĂ©cupĂ©ration du token JWT. +URL de base : `http://votre-serveur:4000/api` -**Body** -```json -{ - "email": "athlete@mail.com", - "password": "motdepasse123" -} -``` - -**RĂ©ponse 200** -```json -{ - "message": "Connexion rĂ©ussie.", - "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", - "user": { - "_id": "64f2a...", - "pseudo": "AthlĂšteExemple", - "email": "athlete@mail.com", - "isVerified": true, - "xp": 2400, - "level": 8 - } -} -``` +Sauf mention contraire, toutes les routes ci-dessous nĂ©cessitent `Authorization: Bearer `. -**Erreurs** -| Code | Cause | -|------|-------| -| 401 | Mauvais email ou password | -| 403 | Email non vĂ©rifiĂ© | +### 1. Authentification : `/api/auth` (public) ---- - -#### `POST /api/auth/verify-email` +| MĂ©thode | Route | Description | +|---------|-------|--------------| +| POST | `/register` | CrĂ©er un compte, envoie un OTP de vĂ©rification | +| POST | `/login` | Connexion par email et mot de passe | +| POST | `/google` | Connexion ou crĂ©ation de compte via Google OAuth | +| POST | `/verify-email` | Valider le code OTP reçu par email | +| POST | `/resend-verification` | Renvoyer un nouveau code de vĂ©rification | +| POST | `/forgot-password` | Demander un code de rĂ©initialisation | +| POST | `/reset-password` | RĂ©initialiser le mot de passe avec le code reçu | -VĂ©rifier son email avec le code OTP reçu. +Exemple, connexion rĂ©ussie : -**Body** ```json -{ - "email": "athlete@mail.com", - "code": "847291" -} -``` +POST /api/auth/login +{ "email": "athlete@mail.com", "password": "motdepasse123" } -**RĂ©ponse 200** -```json +200 OK { - "message": "Email vĂ©rifiĂ© avec succĂšs.", + "message": "Connexion rĂ©ussie.", "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", - "user": { ... } + "user": { "_id": "...", "pseudo": "Athlete", "xp": 2400, "level": 8, "rank": "InitiĂ©" } } ``` -**Erreurs** -| Code | Cause | -|------|-------| -| 400 | Code incorrect ou expirĂ© | -| 429 | Trop de tentatives (> 5) | - ---- - -#### `POST /api/auth/resend-verification` - -Renvoyer un nouveau code de vĂ©rification. - -**Body** -```json -{ "email": "athlete@mail.com" } -``` - -**RĂ©ponse 200** -```json -{ "message": "Code renvoyĂ©." } -``` +### 2. Utilisateurs : `/api/users` ---- - -#### `POST /api/auth/forgot-password` +| MĂ©thode | Route | Description | +|---------|-------|--------------| +| GET | `/me` | Profil complet de l'utilisateur connectĂ© | +| PUT | `/me` | Mettre Ă  jour le profil (champs optionnels) | +| PUT | `/me/frame` | Mettre Ă  jour le cadre de profil Ă©quipĂ© (forme et couleur) | +| PUT | `/me/showcase` | Mettre Ă  jour la vitrine de trophĂ©es mis en avant (3 maximum) | +| PUT | `/me/records-showcase` | Mettre Ă  jour les records d'exercices mis en avant (6 maximum) | +| PUT | `/me/push-token` | Enregistrer ou effacer le token de notification push Expo | +| POST | `/me/complete-onboarding` | Marquer le tutoriel interactif comme terminĂ© (idempotent) | +| POST | `/me/sync-xp` | Synchroniser l'XP totale calculĂ©e cĂŽtĂ© client vers le serveur | +| DELETE | `/delete-account` | Supprimer dĂ©finitivement le compte et toutes ses donnĂ©es (RGPD) | -Demander un code de reset de mot de passe. +`POST /me/sync-xp` est le point d'entrĂ©e qui fait du serveur la source de vĂ©ritĂ© pour tout ce qui est contrĂŽlĂ© cĂŽtĂ© backend (dĂ©blocage de coffres au niveau 11, conditions de titres). Il applique un ratchet : l'XP ne redescend jamais, un envoi tardif ou redondant est toujours sans danger. -**Body** ```json -{ "email": "athlete@mail.com" } -``` +POST /api/users/me/sync-xp +{ "xp": 15420 } -**RĂ©ponse 200** -```json -{ "message": "Code de rĂ©initialisation envoyĂ© par email." } +200 OK +{ "success": true, "level": 22, "xp": 15420, "rank": "InitiĂ©", "newlyUnlockedTitles": ["PERFORM_LEVEL_20"] } ``` -> **Note :** Renvoie toujours 200 mĂȘme si l'email n'existe pas (sĂ©curitĂ© — ne rĂ©vĂšle pas si un compte existe). +Suppression de compte : cascade `ExerciseRecord` puis `Workout` puis `User`. ---- +### 3. SĂ©ances : `/api/workouts` -#### `POST /api/auth/reset-password` +| MĂ©thode | Route | Description | +|---------|-------|--------------| +| POST | `/` | CrĂ©er et enregistrer une sĂ©ance dĂ©jĂ  terminĂ©e | +| GET | `/` | Lister toutes les sĂ©ances de l'utilisateur, triĂ©es par date dĂ©croissante | +| GET | `/:id` | DĂ©tail complet d'une sĂ©ance | +| DELETE | `/:id` | Supprimer une sĂ©ance | +| POST | `/draft` | CrĂ©er un brouillon de sĂ©ance | +| PATCH | `/:id/draft` | Mettre Ă  jour un brouillon (auto-save pendant l'entraĂźnement) | +| POST | `/:id/finalize` | Finaliser une sĂ©ance : calcule les totaux et applique l'anti-triche serveur | +| POST | `/:id/complete` | Marquer une sĂ©ance comme complĂ©tĂ©e (variante allĂ©gĂ©e de finalize) | -RĂ©initialiser le mot de passe avec le code reçu. +Anti-triche temporel, appliquĂ© cĂŽtĂ© serveur en miroir du calcul client : -**Body** -```json -{ - "email": "athlete@mail.com", - "code": "391847", - "newPassword": "nouveauMotDePasse456" -} -``` - -**RĂ©ponse 200** -```json -{ "message": "Mot de passe rĂ©initialisĂ© avec succĂšs." } +```javascript +if (shortSession === true || duration < 300) xp = 0 // moins de 5 minutes +else if (duration < 900) xp = round(xp / 10) // 5 Ă  15 minutes +// 15 minutes ou plus : XP plein ``` ---- - -### 2. Utilisateurs — `/api/users` - -Toutes ces routes nĂ©cessitent `Authorization: Bearer `. - ---- +### 4. Exercices : `/api/exercises` -#### `GET /api/users/me` +| MĂ©thode | Route | Description | +|---------|-------|--------------| +| POST | `/` | Enregistrer les performances d'un exercice pour une sĂ©ance | +| GET | `/leaderboard` | Classement des amis sur un exercice donnĂ© | +| GET | `/my-records` | Tous mes records personnels | +| GET | `/history/:name` | Historique de progression d'un exercice (pour les graphes) | +| GET | `/workout/:workoutId` | Tous les records associĂ©s Ă  une sĂ©ance | -RĂ©cupĂ©rer le profil de l'utilisateur connectĂ©. +### 5. Amis : `/api/friends` -**RĂ©ponse 200** -```json -{ - "user": { - "_id": "64f2a...", - "pseudo": "AthlĂšteExemple", - "email": "athlete@mail.com", - "age": 25, - "sexe": "H", - "poids": 80, - "poidsCible": 75, - "taille": 180, - "niveauSportif": "IntermĂ©diaire", - "objectif": "prise de masse", - "rythme": 4, - "equipements": ["HaltĂšres", "Barre", "Poulie"], - "xp": 2400, - "level": 8, - "createdAt": "2024-01-15T10:30:00.000Z" - } -} -``` +| MĂ©thode | Route | Description | +|---------|-------|--------------| +| POST | `/request` | Envoyer une demande d'ami | +| PUT | `/accept/:requestId` | Accepter une demande reçue | +| PUT | `/decline/:requestId` | Refuser une demande reçue | +| DELETE | `/request/:requestId` | Annuler une demande envoyĂ©e | +| DELETE | `/:friendshipId` | Retirer un ami | +| GET | `/list` | Liste de tous mes amis acceptĂ©s | +| GET | `/pending` | Demandes reçues en attente | +| GET | `/search` | Rechercher un utilisateur par tag exact (Pseudo suivi de son discriminant) | +| GET | `/leaderboard` | Classement XP entre amis | +| GET | `/profile/:friendId` | Profil public d'un ami | ---- +Chaque amitiĂ© possĂšde son propre niveau (1 Ă  5), qui progresse avec l'XP d'interactions partagĂ©es (paliers Ă  0, 100, 300, 700 et 1500). -#### `PUT /api/users/me` +### 6. Inventaire : `/api/inventory` -Mettre Ă  jour le profil utilisateur. +| MĂ©thode | Route | Description | +|---------|-------|--------------| +| POST | `/chest/open` | Ouvrir un coffre (consomme une CHEST_KEY) | +| POST | `/item/use` | Utiliser un objet consommable | +| POST | `/claim` | RĂ©clamer un cosmĂ©tique Unique dĂ©bloquĂ© | -**Body** (tous les champs sont optionnels) -```json -{ - "pseudo": "NouveauPseudo", - "age": 26, - "poids": 78, - "poidsCible": 72, - "taille": 180, - "niveauSportif": "AvancĂ©", - "objectif": "force", - "rythme": 5, - "equipements": ["HaltĂšres", "Barre", "Anneaux"] -} -``` +Un coffre s'obtient toutes les 2 heures de sĂ©ance cumulĂ©es, dĂ©bloquĂ© Ă  partir du rang InitiĂ© (niveau 11). Table de drop : commun 60 pour cent, rare 25 pour cent, Ă©pique 12 pour cent, lĂ©gendaire 3 pour cent. -**RĂ©ponse 200** -```json -{ - "message": "Profil mis Ă  jour.", - "user": { ... } -} -``` +### 7. Groupes de streak : `/api/groups` ---- +| MĂ©thode | Route | Description | +|---------|-------|--------------| +| GET | `/my-group` | Mon groupe actuel, invitations en attente | +| POST | `/leave` | Quitter le groupe | +| POST | `/invite` | Inviter un ami dans le groupe | +| PUT | `/respond/:groupId` | Accepter ou refuser une invitation | +| POST | `/:groupId/shake/:memberId` | Secouer un membre en retard (notification push) | +| POST | `/:groupId/check-streak` | VĂ©rifier et mettre Ă  jour la streak collective du jour | -#### `DELETE /api/users/delete-account` +Un groupe compte 5 membres maximum. La streak collective s'incrĂ©mente si tous les membres valident leur journĂ©e. Une streak de groupe de 30 jours Ă  taille maximale dĂ©bloque, une seule fois, le cosmĂ©tique Unique Rouge Sang pour chaque membre. -Supprimer dĂ©finitivement le compte et toutes ses donnĂ©es (RGPD). +### 8. RĂ©compenses : `/api/rewards` -> **Suppression en cascade :** ExerciseRecord → Workout → User +| MĂ©thode | Route | Description | +|---------|-------|--------------| +| POST | `/birthdate` | Enregistrer la date de naissance (verrouillĂ©e aprĂšs la premiĂšre saisie) | +| POST | `/birthday/check` | VĂ©rifier si c'est l'anniversaire du jour et distribuer la rĂ©compense | +| GET | `/achievements` | TrophĂ©es dĂ©bloquĂ©s cĂŽtĂ© serveur (catalogue de 20 entrĂ©es) | +| PUT | `/achievements/sync` | Synchroniser les trophĂ©es dĂ©bloquĂ©s localement cĂŽtĂ© client | +| POST | `/check` | Forcer une réévaluation des conditions de trophĂ©es | -**RĂ©ponse 200** -```json -{ "message": "Compte supprimĂ© avec succĂšs." } -``` +### 9. Parrainage : `/api/referral` ---- +| MĂ©thode | Route | Description | +|---------|-------|--------------| +| POST | `/claim` | Valider un code de parrainage reçu | -### 3. SĂ©ances — `/api/workouts` +RĂ©compense le filleul et le parrain d'un Gel de Streak et d'un Coupon de niveau chacun. Impossible d'utiliser son propre code ou un compte dĂ©jĂ  parrainĂ©. -Toutes ces routes nĂ©cessitent `Authorization: Bearer `. +### 10. Titres RPG : `/api/profile` ---- +| MĂ©thode | Route | Description | +|---------|-------|--------------| +| GET | `/titles` | Mes titres dĂ©bloquĂ©s et le titre actuellement Ă©quipĂ© | +| POST | `/equip-title` | Équiper un titre parmi ceux dĂ©bloquĂ©s | -#### `POST /api/workouts` +Catalogue de 17 titres, dĂ©blocables par des conditions variĂ©es (niveau, records, sĂ©ances en groupe, entraide). -CrĂ©er et enregistrer une sĂ©ance. +### 11. Lobby multijoueur : `/api/lobby` -**Body** -```json -{ - "name": "Push Day — Pectoraux", - "exercises": [ - { - "name": "DĂ©veloppĂ© couchĂ©", - "targetMuscle": "pectoraux", - "equipment": ["Barre", "Banc"], - "sets": [ - { "weight": 80, "reps": 8, "completed": true }, - { "weight": 80, "reps": 7, "completed": true }, - { "weight": 75, "reps": 8, "completed": true } - ] - }, - { - "name": "Pompes inclinĂ©es", - "targetMuscle": "pectoraux", - "equipment": [], - "sets": [ - { "weight": 0, "reps": 15, "completed": true } - ] - } - ], - "durationSeconds": 3240, - "notes": "Bonne sĂ©ance, PR sur le dĂ©veloppĂ© couchĂ© !" -} -``` +| MĂ©thode | Route | Description | +|---------|-------|--------------| +| POST | `/create` | CrĂ©er un lobby | +| GET | `/:id` | État du lobby | +| POST | `/:id/invite` | Inviter un ami | +| POST | `/:id/join` | Rejoindre un lobby existant | +| POST | `/:id/ready` | Se dĂ©clarer prĂȘt | +| POST | `/:id/unready` | Annuler son statut prĂȘt | +| POST | `/:id/finish` | Terminer la sĂ©ance en groupe | -**RĂ©ponse 201** -```json -{ - "message": "SĂ©ance créée.", - "workout": { - "_id": "65a3b...", - "user": "64f2a...", - "name": "Push Day — Pectoraux", - "exercises": [ ... ], - "durationSeconds": 3240, - "totalVolume": 1845, - "setsCompleted": 7, - "xpEarned": 185, - "status": "finished", - "date": "2024-09-15T14:22:00.000Z" - } -} -``` +Bonus d'XP de groupe selon le nombre de participants : 2 membres 15 pour cent, 3 membres 25 pour cent, 4 membres 35 pour cent, 5 membres 50 pour cent. ---- +### 12. Flux d'activitĂ© : `/api/activity` -#### `GET /api/workouts` +| MĂ©thode | Route | Description | +|---------|-------|--------------| +| GET | `/feed` | ÉvĂ©nements rĂ©cents des amis (record battu, coffre lĂ©gendaire) | +| POST | `/:eventId/react` | RĂ©agir Ă  un Ă©vĂ©nement (bravo, respect, hue, jaloux) | -RĂ©cupĂ©rer toutes les sĂ©ances de l'utilisateur connectĂ© (triĂ©es par date dĂ©croissante). +### 13. Poids : `/api/weight` -**RĂ©ponse 200** -```json -{ - "workouts": [ - { - "_id": "65a3b...", - "name": "Push Day", - "date": "2024-09-15T14:22:00.000Z", - "totalVolume": 1845, - "setsCompleted": 7, - "durationSeconds": 3240, - "status": "finished" - }, - ... - ], - "total": 42 -} -``` +| MĂ©thode | Route | Description | +|---------|-------|--------------| +| GET | `/history` | Historique de pesĂ©es | +| POST | `/` | Enregistrer une nouvelle pesĂ©e | ---- +### 14. Outillage de dĂ©veloppement : `/api/debug` (bloquĂ© en production) -#### `GET /api/workouts/:id` +Bloc d'endpoints God Mode utilisĂ©s pour simuler des Ă©tats de jeu pendant le dĂ©veloppement et les tests manuels (synchronisation de niveau, attribution de coffres et d'objets, simulation de parrainage, d'anniversaire, de groupe, d'Ă©vĂ©nements sociaux, d'invitation de lobby, attribution de tous les titres). Chaque route est protĂ©gĂ©e par `devOnly.middleware.js`, qui rĂ©pond 404 dĂšs que `NODE_ENV=production`, pour ne mĂȘme pas rĂ©vĂ©ler leur existence. -RĂ©cupĂ©rer le dĂ©tail complet d'une sĂ©ance. +### SantĂ© -**RĂ©ponse 200** -```json -{ - "workout": { - "_id": "65a3b...", - "name": "Push Day — Pectoraux", - "exercises": [ - { - "name": "DĂ©veloppĂ© couchĂ©", - "targetMuscle": "pectoraux", - "sets": [ - { "weight": 80, "reps": 8, "completed": true }, - ... - ] - } - ], - "totalVolume": 1845, - "setsCompleted": 7, - "xpEarned": 185, - "durationSeconds": 3240, - "notes": "Bonne sĂ©ance !", - "status": "finished", - "date": "2024-09-15T14:22:00.000Z" - } -} ``` - -**Erreurs** -| Code | Cause | -|------|-------| -| 404 | SĂ©ance introuvable ou n'appartient pas Ă  l'utilisateur | - ---- - -#### `DELETE /api/workouts/:id` - -Supprimer une sĂ©ance. - -**RĂ©ponse 200** -```json -{ "message": "SĂ©ance supprimĂ©e." } +GET /health (public) +200 OK { "status": "OK", "uptime": 3600.42 } ``` --- -#### `POST /api/workouts/draft` - -CrĂ©er un brouillon de sĂ©ance (sĂ©ance non commencĂ©e). +## ModĂšles de donnĂ©es -**Body** -```json -{ - "name": "Ma prochaine sĂ©ance Pull", - "exercises": [] -} -``` - -**RĂ©ponse 201** -```json -{ - "workout": { - "_id": "65a3c...", - "status": "draft", - "name": "Ma prochaine sĂ©ance Pull" - } -} -``` +### User ---- +Le modĂšle central. IdentitĂ©, vĂ©rification email, Google OAuth, profil physique, gamification (XP, niveau, rang calculĂ©), inventaire, coffres, titres dĂ©bloquĂ©s et Ă©quipĂ©, cosmĂ©tiques Uniques, onboarding, push token, parrainage, trophĂ©es, vitrine, cadre de profil Ă©quipĂ©. Deux index composĂ©s notables : email unique, et le combo pseudo plus discriminant unique (insensible Ă  la casse), qui permet Ă  deux comptes de partager le mĂȘme pseudo affichĂ© tout en restant identifiables sans ambiguĂŻtĂ© pour l'ajout d'ami. -#### `PATCH /api/workouts/:id/draft` +### Workout -Mettre Ă  jour un brouillon (ajouter des exercices, modifier le nom
). +Une sĂ©ance : liste d'exercices avec leurs sĂ©ries (poids, rĂ©pĂ©titions, complĂ©tĂ©), volume total, sets complĂ©tĂ©s, XP gagnĂ©, durĂ©e, statut (`draft`, `in_progress`, `finished`, `completed`). Porte les mĂ©thodes d'instance `computeTotals()` et `finalize(options)`. -**Body** (champs partiels) -```json -{ - "name": "Pull Day — Dos", - "exercises": [ - { "name": "Tractions", "targetMuscle": "dos" } - ] -} -``` - -**RĂ©ponse 200** -```json -{ "workout": { ... } } -``` +### ExerciseRecord ---- +Performance d'un exercice pour une sĂ©ance donnĂ©e : nom, liste de sĂ©ries (poids et rĂ©pĂ©titions), note, poids recommandĂ© pour la prochaine sĂ©ance. -#### `POST /api/workouts/:id/finalize` +### Friendship -Finaliser une sĂ©ance en cours. Calcule les totaux et attribue de l'XP. +Relation entre deux utilisateurs (`requester`, `recipient`), statut (`pending`, `accepted`, `rejected`), XP et niveau d'amitiĂ© (1 Ă  5). -**Body** (optionnel) -```json -{ - "durationSeconds": 3600, - "notes": "Super sĂ©ance" -} -``` +### StreakGroup -**XP calculĂ© :** `100 + 5 × setsCompleted` +Groupe de streak collective : membres, invitations en attente, streak courante, date de derniĂšre validation, historique des Secouer envoyĂ©s, statut d'attribution du cosmĂ©tique Rouge Sang. -**RĂ©ponse 200** -```json -{ - "message": "SĂ©ance finalisĂ©e.", - "workout": { - "_id": "65a3b...", - "status": "finished", - "totalVolume": 2140, - "setsCompleted": 18, - "xpEarned": 190 - }, - "xpGained": 190, - "newLevel": 9 -} -``` +### WorkoutLobby ---- +Lobby multijoueur : crĂ©ateur, membres avec leur statut individuel (`waiting`, `ready`, `finished`), statut global du lobby (`waiting`, `active`, `completed`), pourcentage de bonus d'XP calculĂ© selon le nombre de membres. -#### `POST /api/workouts/:id/complete` +### ActivityEvent -ComplĂ©ter une sĂ©ance (variante alternative de finalisation). +ÉvĂ©nement du flux d'activitĂ© social (record battu, coffre lĂ©gendaire ouvert) avec ses rĂ©actions (`bravo`, `respect`, `boo`, `jealous`) par ami. -**XP calculĂ© :** `100 + 10 × exercisesWithCompletedSets` +### WeightHistory -**RĂ©ponse 200** -```json -{ - "message": "SĂ©ance complĂ©tĂ©e.", - "xpGained": 140, - "newLevel": 9 -} -``` +Historique de pesĂ©es : poids et date, un enregistrement par entrĂ©e. --- -#### `GET /api/workouts/exercises` +## Services et logique mĂ©tier -RĂ©cupĂ©rer la liste d'exercices depuis l'API WGER, filtrĂ©e par muscle et Ă©quipement. +### auth.service.js -**Query params** -``` -?muscleId=10&equipmentId=3&includeDetails=true -``` +Inscription, connexion par mot de passe, connexion Google, vĂ©rification email, renvoi de code, mot de passe oubliĂ©, rĂ©initialisation. GĂ©nĂšre Ă©galement les codes de parrainage et discriminants uniques utilisĂ©s par `user.service.js`. -**RĂ©ponse 200** -```json -{ - "exercises": [ - { - "id": 192, - "name": "Bench Press", - "videoUrl": "https://wger.de/en/exercise/192/view/bench-press" - }, - ... - ] -} -``` - ---- +### user.service.js -### 4. Exercices — `/api/exercises` +Lecture et mise Ă  jour du profil, mise Ă  jour du cadre Ă©quipĂ©, de la vitrine de trophĂ©es et de records, enregistrement du push token, marquage de l'onboarding, synchronisation de l'XP avec ratchet anti-rĂ©gression, suppression de compte en cascade. -Toutes ces routes nĂ©cessitent `Authorization: Bearer `. +### workout.service.js ---- +CrĂ©ation, lecture, suppression de sĂ©ances, gestion des brouillons, finalisation avec calcul des totaux et application de l'anti-triche temporel serveur. -#### `POST /api/exercises` +### exercise.service.js -Enregistrer les performances d'un exercice pour une sĂ©ance donnĂ©e. +Enregistrement des performances, historique de progression par exercice, classement entre amis sur un exercice donnĂ©. -**Body** -```json -{ - "workout": "65a3b...", - "exerciceNom": "DĂ©veloppĂ© couchĂ©", - "series": [ - { "poids": 80, "repetitions": 8 }, - { "poids": 82.5, "repetitions": 6 }, - { "poids": 80, "repetitions": 7 } - ], - "note": "LĂ©ger PR sur la sĂ©rie 2" -} -``` - -**RĂ©ponse 201** -```json -{ - "record": { - "_id": "65b1c...", - "exerciceNom": "DĂ©veloppĂ© couchĂ©", - "series": [ ... ], - "recommandedNextWeight": 85, - "createdAt": "2024-09-15T14:22:00.000Z" - } -} -``` +### email.service.js ---- +Templates HTML de la marque (fond sombre, logo Athly) pour les codes de vĂ©rification et de rĂ©initialisation, envoyĂ©s via Nodemailer. -#### `GET /api/exercises/history/:name` +### push.service.js -RĂ©cupĂ©rer l'historique de progression d'un exercice (pour les graphes). +Envoi de notifications push via expo-server-sdk, utilisĂ© pour Secouer, les invitations de groupe et de lobby, les rĂ©actions du flux d'activitĂ©. -**Exemple :** `GET /api/exercises/history/DĂ©veloppĂ©%20couchĂ©` +### chest.service.js -**RĂ©ponse 200** -```json -{ - "history": [ - { - "_id": "65b1c...", - "workout": "65a3b...", - "series": [ - { "poids": 80, "repetitions": 8 } - ], - "createdAt": "2024-09-15T14:22:00.000Z" - }, - { - "_id": "65b0a...", - "workout": "65a2d...", - "series": [ - { "poids": 77.5, "repetitions": 8 } - ], - "createdAt": "2024-09-12T09:15:00.000Z" - } - ] -} -``` +Table de drop pondĂ©rĂ©e et tirage alĂ©atoire d'un objet Ă  l'ouverture d'un coffre. ---- +### inventory.service.js -#### `GET /api/exercises/workout/:workoutId` +Logique de consommation atomique des objets d'inventaire, pour Ă©viter toute condition de course sur la derniĂšre unitĂ© disponible. -RĂ©cupĂ©rer tous les records d'exercices associĂ©s Ă  une sĂ©ance spĂ©cifique. +### activity.service.js -**RĂ©ponse 200** -```json -{ - "records": [ - { - "_id": "65b1c...", - "exerciceNom": "DĂ©veloppĂ© couchĂ©", - "series": [ ... ] - }, - { - "_id": "65b1d...", - "exerciceNom": "Dips", - "series": [ ... ] - } - ] -} -``` +Construction et filtrage du flux d'activitĂ© social visible par un utilisateur. --- -#### `GET /health` +## Catalogues de donnĂ©es -Point de terminaison de santĂ© (public, sans auth). +### `data/titleCatalog.js` -**RĂ©ponse 200** -```json -{ - "status": "OK", - "uptime": 3600.42 -} -``` +17 titres RPG dĂ©blocables, avec leurs conditions (niveau, records personnels, sĂ©ances en groupe, participation communautaire). ---- +### `data/localTrophyCatalog.js` -## 🗄 ModĂšles de donnĂ©es +Miroir des mĂ©tadonnĂ©es d'affichage des 40 trophĂ©es locaux dĂ©finis cĂŽtĂ© front, plus le trophĂ©e capstone Souverain Absolu qui se dĂ©bloque automatiquement une fois tous les autres trophĂ©es obtenus. Les conditions de dĂ©blocage sont Ă©valuĂ©es cĂŽtĂ© client (elles dĂ©pendent des logs de sĂ©ances stockĂ©s en AsyncStorage) : ce fichier ne porte que les mĂ©tadonnĂ©es et sert d'allowlist pour la synchronisation. -### User +### `data/shakeMessages.js` -```javascript -{ - // IdentitĂ© - pseudo: String (required, trim), - email: String (required, unique, lowercase), - password: String (required, bcrypt hash), - - // VĂ©rification email - isVerified: Boolean (default: false), - verificationCode: String, - verifyAttempts: Number (default: 0, max: 5), - - // Reset password - resetPasswordCode: String, - codeExpires: Date, // TTL : 10 min (vĂ©rif) / 15 min (reset) - - // Profil physique - age: Number, - sexe: Enum ["H", "F", "Autre"], - poids: Number, // kg - poidsCible: Number, // kg - taille: Number, // cm - niveauSportif: Enum ["DĂ©butant", "IntermĂ©diaire", "AvancĂ©"], - objectif: Enum ["prise de masse", "perte de poids", "entretien", "force"], - rythme: Number, // 1-7 sĂ©ances/semaine - equipements: [String], - - // Gamification - xp: Number (default: 0), - level: Number (default: 1), - - // Timestamps Mongoose - createdAt, updatedAt -} -``` +Messages alĂ©atoires envoyĂ©s par notification push lors d'un Secouer entre membres de groupe. -### Workout +### Catalogue de trophĂ©es serveur -```javascript -{ - user: ObjectId → User (required), - date: Date (default: Date.now), - name: String (default: "SĂ©ance"), - - exercises: [ - { - exerciseId: ObjectId → Exercise (optional), - name: String (required), - targetMuscle: String, - equipment: [String], - sets: [ - { - weight: Number, - reps: Number, - completed: Boolean (default: false), - timestamp: Date - } - ], - notes: String, - videoUrl: String - } - ], - - // MĂ©triques (calculĂ©es Ă  la finalisation) - durationSeconds: Number, - totalVolume: Number, // kg · reps cumulĂ© - setsCompleted: Number, - xpEarned: Number, - notes: String, - - // Statut - status: Enum ["draft", "in_progress", "finished", "completed"], - completedAt: Date, - - // Timestamps Mongoose - createdAt, updatedAt -} - -// MĂ©thodes d'instance -workout.computeTotals() // → {totalVolume, setsCompleted} -workout.finalize(options) // → {totalVolume, setsCompleted, xp} -``` - -### ExerciseRecord - -```javascript -{ - user: ObjectId → User (required), - workout: ObjectId → Workout (required), - - exerciceNom: String (required), - series: [ - { - poids: Number, // kg (0 si bodyweight) - repetitions: Number - } - ], - note: String, - recommandedNextWeight: Number, // suggestion poids prochaine sĂ©ance - - // Timestamps Mongoose - createdAt, updatedAt -} -``` +DĂ©fini directement dans `reward.controller.js` (`ACHIEVEMENT_CATALOG`), 20 entrĂ©es rĂ©parties en trois catĂ©gories : profil (anniversaire, parrainage), social (amitiĂ©, groupe), collection (raretĂ©s d'objets et paliers de coffres ouverts). --- -## 🧠 Services & logique mĂ©tier - -### auth.service.js - -| Fonction | Description | -|----------|-------------| -| `register(pseudo, email, password)` | Hash password, crĂ©e User, gĂ©nĂšre OTP 6 chiffres, envoie email | -| `login(email, password)` | VĂ©rifie identifiants, gĂ©nĂšre JWT, retourne user | -| `verifyEmail(email, code)` | VĂ©rifie OTP, active compte, retourne JWT | -| `resendVerification(email)` | GĂ©nĂšre nouveau code, envoie email | -| `forgotPassword(email)` | GĂ©nĂšre code reset, envoie email | -| `resetPassword(email, code, newPassword)` | VĂ©rifie code, hash nouveau password, invalide code | - -**Constantes :** -```javascript -MAX_OTP_ATTEMPTS = 5 // Tentatives max avant blocage -CODE_TTL_VERIFY = 10 * 60 // 10 minutes (en secondes) -CODE_TTL_RESET = 15 * 60 // 15 minutes -``` - -### user.service.js +## Formules de gamification -| Fonction | Description | -|----------|-------------| -| `getUserProfile(userId)` | Retourne user sans password | -| `updateUser(userId, data)` | Mise Ă  jour profil (whitelist de champs) | -| `deleteAccount(userId)` | Suppression cascade : ExerciseRecord → Workout → User | -| `addExperience(userId, xp)` | `user.xp += xp`, recalcule level = `floor(sqrt(xp / 250))` | +### Courbe XP et niveau -### workout.service.js +Source de vĂ©ritĂ© unique : `utils/levelHelpers.js`, identique Ă  la formule utilisĂ©e cĂŽtĂ© front. -| Fonction | Description | -|----------|-------------| -| `createWorkout(userId, data)` | CrĂ©e et sauvegarde une sĂ©ance | -| `getMyWorkouts(userId)` | Toutes les sĂ©ances, triĂ©es par date desc | -| `getWorkoutById(userId, id)` | DĂ©tail + vĂ©rification ownership | -| `deleteWorkout(userId, id)` | Suppression (ownership check) | -| `createDraft(userId, data)` | Brouillon (status: "draft") | -| `updateDraft(userId, id, patch)` | Mise Ă  jour partielle du brouillon | -| `finalizeWorkout(userId, id, opts)` | Calcule totaux, applique l'anti-cheat, crĂ©dite XP et recalcule le niveau | -| `completeWorkout(userId, id)` | `xp = 100 + 10×exercisesWithSets`, crĂ©dite XP et recalcule le niveau | - -**Anti-cheat temporel (miroir du front-end) :** ```javascript -if (shortSession === true || duration < 300) xp = 0 // < 5 min → 0 XP -else if (duration < 900) xp = round(xp/10) // 5–15 min → XP Ă· 10 -// ≄ 15 min → XP plein -``` +xpForLevel(n) = Math.round(4665 * (1.03 ** min(n, 200) - 1)) +levelFromXP(xp) // recherche binaire inverse, plafonnĂ©e au niveau 200 -**Formule de niveau (harmonisĂ©e avec le front-end) :** -```javascript -// utils/levelHelpers.js — source de vĂ©ritĂ© unique -xpForLevel(n) = Math.round(4665 * (1.03^n - 1)) -levelFromXP(xp) // recherche binaire inverse -// Exemples : ~1 600 XP → L10 · ~85 000 XP → L100 · ~1 150 000 XP → L200 +// RepĂšres : niveau 1 environ 140 XP, niveau 10 environ 1600 XP, +// niveau 100 environ 85 000 XP, niveau 200 environ 1 720 000 XP ``` -### email.service.js - -Templates HTML professionnels (fond dark `#0D1018`, logo Athly) pour : -- **VĂ©rification d'email** : code OTP 6 chiffres en grande police -- **Reset password** : mĂȘme format, texte diffĂ©rent +### Rangs -Utilise Nodemailer avec SSL/TLS sur le port 465. +Dix paliers, du niveau 1 au niveau 200 et au-delĂ  : Novice, InitiĂ© (11), AthlĂšte (31), CompĂ©titeur (51), Warrior (71), Élite (91), MaĂźtre (111), Grand MaĂźtre (141), LĂ©gende (171), ATHLY GOD (200). -### wger.service.js +### Bonus de groupe (lobby multijoueur) -Proxy vers `https://wger.de/api/v2` : - -```javascript -getExercisesByMuscleAndEquipment(muscleId, equipmentId, includeDetails) -// → [{id, name, videoUrl}] -``` +| Membres | Bonus d'XP | +|---------|------------| +| 2 | 15 pour cent | +| 3 | 25 pour cent | +| 4 | 35 pour cent | +| 5 | 50 pour cent | --- -## đŸ§Ș Tests +## Tests ```bash -# Lancer tous les tests -npm test - -# Tests en mode watch -npm test -- --watch - -# Couverture de code -npm test -- --coverage +npm test # suite complĂšte +npm test -- --watch # mode watch +npm test -- --coverage # couverture de code ``` -### Tests unitaires et d'intĂ©gritĂ© (sans base de donnĂ©es) +26 fichiers de tests, exĂ©cutĂ©s contre une instance MongoDB en mĂ©moire (mongodb-memory-server), dĂ©marrĂ©e et arrĂȘtĂ©e automatiquement par `tests/globalSetup.js` et `tests/globalTeardown.js`. Aucune connexion rĂ©seau requise, y compris en intĂ©gration continue. -Ces trois suites tournent sans connexion MongoDB — elles sont la cible principale de la CI. - -#### `tests/levelHelpers.test.js` — 24 tests - -VĂ©rifie la formule XP/niveau dĂ©finie dans `utils/levelHelpers.js` : - -| Groupe | Ce qui est testĂ© | -|--------|-----------------| -| `xpForLevel` | Niveau 0, 1, 10, 100, 200 ; cap >200 ; valeurs nĂ©gatives ; progression strictement croissante | -| `levelFromXP` | 0 XP → L0 ; valeurs nulles/NaN/nĂ©gatives ; bijectivitĂ© `levelFromXP(xpForLevel(n)) === n` pour n ∈ {1,5,10,25,50,75,100,150,200} ; 85 000 XP → L100 | - -#### `tests/workoutAnticheat.test.js` — 13 tests - -VĂ©rifie la logique d'anti-cheat serveur dans `workout.service.js::finalizeWorkout` via `jest.mock()` (aucun appel MongoDB) : - -| ScĂ©nario | XP attendu | -|----------|-----------| -| `durationSeconds = 0` | 0 | -| `durationSeconds = 150` (< 5 min) | 0 | -| `durationSeconds = 299` | 0 | -| `shortSession: true` + 1 800 s | 0 | -| `durationSeconds = 300` (seuil exact) | XP Ă· 10 | -| `durationSeconds = 600` | XP Ă· 10 | -| `durationSeconds = 899` | XP Ă· 10 | -| `durationSeconds = 900` (seuil exact) | XP plein | -| `durationSeconds = 3 600` | XP plein | -| User null (absent en BDD) | pas de crash | -| Workout introuvable | lance une erreur | - -#### `tests/modelsIntegrity.test.js` — 36 tests - -VĂ©rifie l'Ă©tat des schĂ©mas Mongoose sans requĂȘte rĂ©seau : - -| Groupe | Ce qui est testĂ© | -|--------|-----------------| -| Imports rĂ©els | User, Workout, ExerciseRecord s'importent sans erreur | -| ModĂšles fantĂŽmes | UserQuest, RefreshToken, WorkoutLog, RitualLog, UserProgress, Notification → `MODULE_NOT_FOUND` | -| SchĂ©ma User | Champs email/password/xp/level/isVerified ; contrainte unique email ; xp dĂ©faut 0 ; level dĂ©faut 1 | -| SchĂ©ma Workout | Champs user/exercises/xpEarned/durationSeconds/status/notes ; mĂ©thodes `finalize()` et `computeTotals()` ; enum status contient draft/in_progress/finished | -| SchĂ©ma ExerciseRecord | Champs user/workout/exerciceNom/series ; refs User et Workout | - -### Tests d'intĂ©gration HTTP (avec base de donnĂ©es) - -| Fichier | Routes couvertes | -|---------|-----------------| -| `health.test.js` | `GET /health` | -| `auth.test.js` | Register, login, verify-email, forgot/reset password | -| `user.test.js` | `GET/PUT /me`, delete account | -| `workout.test.js` | CRUD sĂ©ances, draft, finalize, complete | -| `exercise.test.js` | Create record, get history, get by workout | - -Ces tests utilisent **Supertest** et nĂ©cessitent un cluster MongoDB accessible (variable `MONGO_URI`). +| Fichier | PĂ©rimĂštre | +|---------|-----------| +| `levelHelpers.test.js` | Formule XP et niveau : bornes, plafond, bijectivitĂ© | +| `workoutAnticheat.test.js` | Anti-triche serveur sur la finalisation de sĂ©ance | +| `modelsIntegrity.test.js` | IntĂ©gritĂ© des 8 schĂ©mas Mongoose | +| `health.test.js` | Point de santĂ© | +| `auth.test.js` | Inscription, connexion, vĂ©rification, mot de passe oubliĂ© | +| `googleAuth.test.js` | Connexion et crĂ©ation de compte via Google OAuth | +| `discriminator.test.js` | UnicitĂ© du combo pseudo et discriminant | +| `user.test.js` | Profil, cadre, vitrines, push token, onboarding, synchronisation XP, suppression de compte | +| `workout.test.js` | CRUD sĂ©ances, brouillon, finalisation, complĂ©tion | +| `exercise.test.js` | Enregistrement de performances, historique, classement | +| `friendship.test.js` | Demandes d'amis, acceptation, refus, retrait, recherche | +| `socialEngine.test.js` | Classement, profil public, niveaux d'amitiĂ© | +| `groupStreak.test.js` | Groupes, invitations, streak collective, Secouer | +| `inventory.test.js` | Ouverture de coffres, consommation atomique, rĂ©clamation de cosmĂ©tiques | +| `reward.test.js` | TrophĂ©es serveur, synchronisation, anniversaire | +| `trophyUnification.test.js` | CohĂ©rence du catalogue combinĂ© local plus serveur | +| `bloodSangRewards.test.js` | Attribution du cosmĂ©tique Unique de groupe | +| `referral.test.js` | Parrainage, rĂ©compenses, garde-fous anti-triche | +| `titles.test.js` | DĂ©blocage et Ă©quipement des titres | +| `activityFeed.test.js` | Flux d'activitĂ© et rĂ©actions | +| `weight.test.js` | Historique de pesĂ©es | +| `workoutLobby.test.js` | Cycle de vie complet du lobby multijoueur | +| `debug.test.js` | Endpoints God Mode, blocage en production | +| `profanityFilter.test.js` | Filtre de pseudos | +| `deepIntegration.test.js` | ScĂ©narios croisĂ©s de bout en bout | --- -## ⚙ IntĂ©gration continue (CI) - -Les tests unitaires et d'intĂ©gritĂ© (`levelHelpers`, `workoutAnticheat`, `modelsIntegrity`) sont conçus pour s'exĂ©cuter **sans base de donnĂ©es** dans n'importe quel environnement CI/CD. - -Exemple de workflow GitHub Actions : +## IntĂ©gration continue -```yaml -name: Tests +Le workflow GitHub Actions (`.github/workflows/ci.yml`) exĂ©cute deux jobs indĂ©pendants, chacun dĂ©clenchĂ© uniquement si son dossier a changĂ© : -on: [push, pull_request] +- **Backend** : installation, lint ESLint, vĂ©rification syntaxique de `server.js`, audit de sĂ©curitĂ© npm sur les dĂ©pendances de production (bloquant Ă  partir du niveau Ă©levĂ©), puis suite de tests complĂšte. Aucune base de donnĂ©es externe n'est requise, la suite Jest dĂ©marre sa propre instance en mĂ©moire. +- **Frontend** : installation avec `--legacy-peer-deps`, audit de sĂ©curitĂ© npm, puis build de la PWA via `expo export --platform web`, qui dĂ©tecte immĂ©diatement tout composant natif non compatible avec le web. -jobs: - unit-tests: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: '22' - cache: 'npm' - - run: npm ci - - run: npx jest tests/levelHelpers.test.js tests/workoutAnticheat.test.js tests/modelsIntegrity.test.js --runInBand --forceExit -``` - -> Les tests d'intĂ©gration HTTP (`auth`, `user`, `workout`, `exercise`) nĂ©cessitent un secret `MONGO_URI` configurĂ© dans les variables d'environnement du runner CI. +Un push qui ne touche que `front/` ne dĂ©clenche pas le job backend, et inversement. --- -## 🔒 SĂ©curitĂ© +## SĂ©curitĂ© | Mesure | ImplĂ©mentation | -|--------|---------------| -| Passwords hashĂ©s | bcrypt avec salt rounds = 10 | -| JWT court-vĂ©cu | Expiration 1 jour (configurable) | -| VĂ©rification email | OTP 6 chiffres, expiration 10 min | +|--------|-----------------| +| Mots de passe hashĂ©s | bcrypt | +| JWT Ă  courte durĂ©e de vie | Expiration configurable, 1 jour par dĂ©faut | +| VĂ©rification email | OTP Ă  6 chiffres, expiration 10 minutes | | Brute-force OTP | Blocage aprĂšs 5 tentatives | -| Headers sĂ©curisĂ©s | Helmet (X-Frame-Options, CSP, HSTS, etc.) | -| CORS | ConfigurĂ© pour les origines autorisĂ©es | -| Validation entrĂ©es | Joi sur tous les body de requĂȘte | -| Ownership check | Chaque workout/record vĂ©rifiĂ© contre `req.user.id` | -| Logs HTTP | Morgan en mode `dev` | +| Headers sĂ©curisĂ©s | Helmet (CSP, HSTS, noSniff, frameguard) | +| CORS | Allowlist via `CORS_ORIGINS`, permissif uniquement en dĂ©veloppement | +| Rate limiting global | 300 requĂȘtes par 15 minutes et par IP sur `/api` | +| Rate limiting authentification | 20 requĂȘtes par 15 minutes, clĂ© IP plus email ciblĂ© | +| Injection NoSQL | Assainissement rĂ©cursif des clĂ©s suspectes avant toute route | +| Validation des entrĂ©es | SchĂ©mas Joi sur toutes les routes Ă  corps de requĂȘte | +| Limite de payload | 1 Mo maximum par requĂȘte | +| VĂ©rification de propriĂ©tĂ© | Chaque sĂ©ance ou record est vĂ©rifiĂ© contre `req.user.id` | +| Cache | `Cache-Control: no-store` sur toutes les rĂ©ponses `/api` | +| Logs HTTP | Morgan, dĂ©sactivĂ© pendant les tests | | Variables sensibles | Jamais en dur, toujours via `.env` | +DĂ©tail complet de l'architecture de sĂ©curitĂ© et de rĂ©silience : `docs/ARCHITECTURE-SECURITE.md` Ă  la racine du dĂ©pĂŽt. + ---
-**Athly API** · Node.js + Express + MongoDB · Authentification JWT + OTP +Athly API : Node.js, Express, MongoDB. Authentification par mot de passe, OTP et Google OAuth.
diff --git a/front/README.md b/front/README.md index 0e59363..b5aee07 100644 --- a/front/README.md +++ b/front/README.md @@ -1,636 +1,539 @@
-# đŸ‹ïž ATHLY — Application Mobile de Fitness GamifiĂ©e +# ATHLY : Application Mobile de Fitness GamifiĂ©e -**Tracker d'entraĂźnement React Native · Stockage local AsyncStorage · Gamification complĂšte** +**React Native, Expo, PWA. Stockage local AsyncStorage, gamification complĂšte, social et multijoueur** ![React Native](https://img.shields.io/badge/React_Native-0.81.5-61DAFB?style=flat-square&logo=react) -![Expo](https://img.shields.io/badge/Expo-54.0.27-000020?style=flat-square&logo=expo) -![TypeScript](https://img.shields.io/badge/JavaScript-ES2022-F7DF1E?style=flat-square&logo=javascript) +![Expo](https://img.shields.io/badge/Expo-54-000020?style=flat-square&logo=expo) +![React Navigation](https://img.shields.io/badge/React_Navigation-7-6b52ae?style=flat-square) ![AsyncStorage](https://img.shields.io/badge/Stockage-AsyncStorage-34D399?style=flat-square) -![Axios](https://img.shields.io/badge/Axios-1.16.0-5A29E4?style=flat-square) +![Axios](https://img.shields.io/badge/Axios-1.18-5A29E4?style=flat-square) -> Athly transforme chaque sĂ©ance d'entraĂźnement en une expĂ©rience de jeu. XP, streaks, quĂȘtes quotidiennes, trophĂ©es, rituels de rĂ©cupĂ©ration — progresser n'a jamais Ă©tĂ© aussi addictif. +Athly transforme chaque sĂ©ance d'entraĂźnement en expĂ©rience de jeu : XP, niveaux, streaks, quĂȘtes quotidiennes, trophĂ©es, titres RPG, coffres Ă  ouvrir, groupes d'amis avec streak collective, lobby multijoueur, et un tutoriel interactif qui accompagne la dĂ©couverte de toutes ces fonctionnalitĂ©s.
--- -## 📋 Table des matiĂšres - -1. [Vue d'ensemble](#-vue-densemble) -2. [FonctionnalitĂ©s](#-fonctionnalitĂ©s) -3. [Stack technique](#-stack-technique) -4. [Architecture](#-architecture) -5. [Installation & lancement](#-installation--lancement) -6. [Variables d'environnement](#-variables-denvironnement) -7. [Structure du projet](#-structure-du-projet) -8. [SystĂšme de gamification](#-systĂšme-de-gamification) -9. [Contextes React](#-contextes-react) -10. [Services](#-services) -11. [Navigation](#-navigation) -12. [Composants clĂ©s](#-composants-clĂ©s) -13. [Backend associĂ©](#-backend-associĂ©) +## Table des matiĂšres + +1. [Vue d'ensemble](#vue-densemble) +2. [FonctionnalitĂ©s](#fonctionnalitĂ©s) +3. [Stack technique](#stack-technique) +4. [Architecture](#architecture) +5. [Installation et lancement](#installation-et-lancement) +6. [Variables d'environnement](#variables-denvironnement) +7. [Structure du projet](#structure-du-projet) +8. [Navigation](#navigation) +9. [Contextes React](#contextes-react) +10. [Services](#services) +11. [Catalogues de donnĂ©es](#catalogues-de-donnĂ©es) +12. [SystĂšme de gamification](#systĂšme-de-gamification) +13. [Tutoriel interactif](#tutoriel-interactif) +14. [ParamĂštres dĂ©veloppeur](#paramĂštres-dĂ©veloppeur) +15. [Tests](#tests) +16. [Backend associĂ©](#backend-associĂ©) --- -## 🎯 Vue d'ensemble +## Vue d'ensemble -Athly est une application mobile de fitness construite avec React Native (Expo). L'application **nĂ©cessite une connexion Internet et un compte** pour fonctionner : l'authentification passe par le backend (JWT). Une fois connectĂ©, toutes les donnĂ©es de progression (logs de sĂ©ances, XP, quĂȘtes, rituels) sont stockĂ©es localement dans AsyncStorage sur l'appareil pour des performances optimales, et synchronisĂ©es avec le backend en best-effort. +Athly est une application mobile construite avec React Native et Expo, Ă©galement buildĂ©e en PWA pour le web. Elle nĂ©cessite une connexion Internet et un compte pour fonctionner : l'authentification (mot de passe, Google OAuth, vĂ©rification email) passe obligatoirement par le backend. Une fois connectĂ©, les donnĂ©es de progression immĂ©diate (logs de sĂ©ances, XP cumulatif, streak, quĂȘtes, rituels) sont calculĂ©es et stockĂ©es localement dans AsyncStorage pour des performances instantanĂ©es, tandis que le backend fait autoritĂ© pour le profil, le social, l'inventaire et le multijoueur. ### Philosophie | Principe | Description | -|----------|-------------| -| **Backend requis** | L'authentification (connexion, inscription, reset password) nĂ©cessite une connexion au backend. Sans rĂ©seau, l'app n'est pas utilisable. | -| **DonnĂ©es locales** | Une fois connectĂ©, les logs de sĂ©ances, XP, quĂȘtes et rituels sont stockĂ©s dans AsyncStorage — les calculs se font entiĂšrement cĂŽtĂ© client. | -| **Sync best-effort** | La finalisation d'une sĂ©ance tente une sync backend, mais l'Ă©chec ne bloque pas l'utilisateur. Les donnĂ©es locales font foi. | -| **Gamification profonde** | Chaque sĂ©ance rapporte des XP, alimente une streak, valide des quĂȘtes et peut dĂ©bloquer des trophĂ©es. | -| **Anti-triche intĂ©grĂ©** | Une sĂ©ance < 5 min ne rapporte aucun XP, ne valide pas les quĂȘtes et n'incrĂ©mente pas la streak. | -| **RĂ©cupĂ©ration active** | Les jours sans sĂ©ance, 5 rituels de rĂ©cupĂ©ration permettent de maintenir la streak (+20 Ă  +100 XP). | +|----------|--------------| +| Backend requis | L'authentification nĂ©cessite une connexion rĂ©seau. Sans elle, l'application n'est pas utilisable. | +| DonnĂ©es de sĂ©ance locales | Logs, XP, streak, quĂȘtes et rituels vivent dans AsyncStorage, les calculs se font entiĂšrement cĂŽtĂ© client. | +| Synchronisation best effort | L'XP totale est poussĂ©e vers le backend (`POST /users/me/sync-xp`) Ă  chaque Ă©vĂ©nement clĂ©, avec ratchet anti-rĂ©gression cĂŽtĂ© serveur. Un Ă©chec rĂ©seau ne bloque jamais l'utilisateur, un retry automatique a lieu au prochain Ă©vĂ©nement. | +| Social et multijoueur sur backend | Amis, groupes de streak, lobby, inventaire, titres et trophĂ©es serveur sont gĂ©rĂ©s en direct par l'API : ils nĂ©cessitent le rĂ©seau. | +| Gamification profonde | Chaque sĂ©ance rapporte de l'XP, alimente une streak, valide des quĂȘtes, peut dĂ©bloquer des trophĂ©es et des titres. | +| Anti-triche intĂ©grĂ© | Une sĂ©ance de moins de 5 minutes ne rapporte aucun XP, ne valide aucune quĂȘte et n'incrĂ©mente pas la streak. Entre 5 et 15 minutes, l'XP est divisĂ© par 10. Le serveur applique la mĂȘme rĂšgle Ă  la finalisation. | +| RĂ©cupĂ©ration active | Les jours sans sĂ©ance, 5 rituels permettent de maintenir la streak. | --- -## ✹ FonctionnalitĂ©s - -### đŸ‹ïž Gestion des sĂ©ances -- **Timer en temps rĂ©el** pendant l'entraĂźnement avec chronomĂštre visible -- **Sets & reps** : saisie poids/reps pour chaque exercice, validation par set -- **Supersets** : regroupement de plusieurs exercices en circuit -- **Notes** par sĂ©ance et par exercice -- **Workout Builder** : crĂ©er des sĂ©ances Ă  partir d'un catalogue de 100+ exercices -- **Exercices personnalisĂ©s** : crĂ©er et gĂ©rer ses propres mouvements (persistĂ©s localement) -- **SĂ©ances favorites** : sauvegarder et rĂ©utiliser ses programmes -- **WorkoutRecapModal** : rĂ©capitulatif complet post-sĂ©ance (volume, XP gagnĂ©, nouveaux PRs, quĂȘtes validĂ©es) - -### đŸ›Ąïž SystĂšme Anti-triche (5 minutes) -- Une sĂ©ance finalisĂ©e en **< 5 minutes** dĂ©clenche une modale d'avertissement -- L'utilisateur peut choisir de **continuer** ou de **forcer la validation** -- En cas de forçage : `xpEarned = 0`, flag `shortSession: true`, **aucune quĂȘte validĂ©e**, **aucun incrĂ©ment de streak** -- **God Mode** : toggle en paramĂštres dĂ©veloppeur pour bypasser le check - -### 🎼 Gamification - -#### XP & Niveaux -- Chaque sĂ©ance rapporte de l'XP calculĂ© sur le volume, le nombre de sets et le multiplicateur de streak -- Courbe de progression **exponentielle** (base 4665, taux 1.03) -- Cap quotidien : **2 sĂ©ances XP/jour** maximum (anti-farming) -- Les rituels de rĂ©cupĂ©ration ne comptent pas dans le cap quotidien - -#### Streak -- La streak s'incrĂ©mente si au moins **1 log valide** (pas `shortSession`) est posĂ© dans la journĂ©e -- Les rituels de rĂ©cupĂ©ration comptent pour la streak -- **8 paliers de multiplicateur** : jusqu'Ă  ×7.0 Ă  730 jours consĂ©cutifs - -#### QuĂȘtes quotidiennes -- **3 quĂȘtes** tirĂ©es parmi 20 templates, dĂ©terministes par la date (reproductibles) -- Exemples : "Faire 25 sĂ©ries", "Terminer en < 45 min", "Travailler les jambes", "Battre un PR" -- ComplĂ©ter les 3 quĂȘtes dĂ©bloque un **bonus de 1000 XP supplĂ©mentaires** -- Les sĂ©ances `shortSession` ne valident **aucune** quĂȘte - -#### TrophĂ©es -- **50+ trophĂ©es** catĂ©gorisĂ©s (RĂ©gularitĂ©, Volume, Force, DiversitĂ©, SpĂ©ciaux) -- Évaluation automatique post-sĂ©ance et au chargement du profil -- **Trophy Room** : galerie avec Ă©tats verrouillĂ©/dĂ©bloquĂ©, animations - -### 🧘 Rituels de RĂ©cupĂ©ration Active -5 rituels disponibles les jours sans sĂ©ance (ou en complĂ©ment) : +## FonctionnalitĂ©s -| Rituel | MĂ©canique | XP | -|--------|-----------|-----| -| **MobilitĂ© & Souplesse** | Timer 5 min | +20 XP | -| **Marche Quotidienne** | Timer 15 min | +100 XP | -| **Respiration & Mental** | Cercle animĂ© inspire/expire · 5 min | +20 XP | -| **Automassage** | 5 zones × 1 min (Mollets → Épaules) | +20 XP | -| **Focus & Culture** | Article Ă  lire · timer 5 min bloquant | +20 XP | - -- 1 rituel maximum par jour calendaire -- Compte pour la streak (mĂȘme valeur qu'une vraie sĂ©ance) -- XP non soumis au cap quotidien de 2 sĂ©ances - -### 📊 Statistiques -- Volume total, sets complĂ©tĂ©s, distribution musculaire (camembert) -- Graphe de progression par exercice (LineChart) -- Historique complet des sĂ©ances avec filtres et tri -- Nouveaux PRs (Personal Records) dĂ©tectĂ©s automatiquement aprĂšs chaque sĂ©ance - -### 🎓 Tutoriel interactif -- SystĂšme **step-by-step** avec overlay semi-transparent -- Met en surbrillance les Ă©lĂ©ments de l'UI ciblĂ©s -- Auto-scroll vers les Ă©lĂ©ments mis en avant -- Chapitres : **Dashboard** (6 Ă©tapes) + **Workout** (6 Ă©tapes) -- Inclut une Ă©tape dĂ©diĂ©e au systĂšme anti-triche et aux rituels - -### đŸ‘€ Profil & Personnalisation -- DonnĂ©es physiques (poids, taille, Ăąge, objectif, rythme) -- Équipements disponibles pour la recommandation d'exercices -- **ThĂšmes de profil** : plusieurs palettes visuelles -- Suppression de compte RGPD (cascade sur toutes les donnĂ©es) +### Gestion des sĂ©ances + +Timer en temps rĂ©el, saisie poids et rĂ©pĂ©titions par sĂ©rie, supersets, notes par sĂ©ance et par exercice, Workout Builder pour gĂ©nĂ©rer une sĂ©ance sur mesure Ă  partir d'un catalogue de plus de 350 exercices, crĂ©ation manuelle exercice par exercice, exercices personnalisĂ©s persistĂ©s localement, sĂ©ances sauvegardĂ©es comme modĂšles rĂ©utilisables (modifiables aprĂšs coup, avec les mĂȘmes critĂšres de gĂ©nĂ©ration prĂ©-remplis), rĂ©capitulatif complet post-sĂ©ance (volume, XP gagnĂ©, nouveaux records, quĂȘtes validĂ©es). + +### Anti-triche + +Une sĂ©ance finalisĂ©e en moins de 5 minutes dĂ©clenche une modale d'avertissement. L'utilisateur peut modifier la sĂ©ance ou forcer la validation : dans ce cas, l'XP gagnĂ© est nul, la sĂ©ance est marquĂ©e `shortSession`, aucune quĂȘte n'est validĂ©e et la streak n'est pas incrĂ©mentĂ©e. Le backend applique la mĂȘme logique Ă  la finalisation, indĂ©pendamment du client. + +### Gamification + +XP et niveaux sur une courbe exponentielle, streak avec 8 paliers de multiplicateur jusqu'Ă  7 fois l'XP de base, 3 quĂȘtes quotidiennes tirĂ©es parmi 20 modĂšles de façon dĂ©terministe par la date (tout le monde a les mĂȘmes quĂȘtes le mĂȘme jour), rangs de Novice Ă  ATHLY GOD, catalogue de plus de 60 trophĂ©es rĂ©parti en 9 catĂ©gories, 17 titres RPG dĂ©blocables et Ă©quipables sous le pseudo. + +### Coffres et inventaire + +Un coffre toutes les 2 heures de sĂ©ance cumulĂ©es, dĂ©bloquĂ© au rang InitiĂ© (niveau 11). Ouverture avec animation, table de drop par raretĂ© (commune, rare, Ă©pique, lĂ©gendaire, unique), objets consommables (boissons d'XP, gels de streak, boosts de multiplicateur, coupons de niveau), cosmĂ©tiques Unique Rouge Sang rĂ©clamables sous conditions rares. + +### Social + +Ajout d'ami par tag unique façon Discord, aperçu de profil avant envoi de la demande, classement XP entre amis, classement par exercice, profil public consultable, niveaux d'amitiĂ© progressifs, flux d'activitĂ© avec rĂ©actions (bravo, respect, hue, jaloux) sur les records et coffres lĂ©gendaires des amis. + +### Groupes de streak + +Groupe de 5 membres maximum, invitations, streak collective (validĂ©e si tous les membres valident leur journĂ©e), mĂ©tĂ©o des sĂ©ances en direct (statut prĂȘt, actif, validĂ© de chaque membre), bouton Secouer pour relancer un retardataire par notification, Hall of Shame si la streak casse, rĂ©compense cosmĂ©tique Unique Ă  30 jours de streak collective Ă  taille maximale. + +### Lobby multijoueur + +Invitation d'amis pour dĂ©marrer une sĂ©ance ensemble, chacun sur son propre appareil, bonus d'XP de groupe croissant selon le nombre de participants (15 Ă  50 pour cent). + +### Statistiques + +Volume total, sets complĂ©tĂ©s, rĂ©partition musculaire en camembert, graphe de progression par exercice, suivi de poids avec objectif et rappel hebdomadaire, historique complet des sĂ©ances avec filtres, dĂ©tection automatique des nouveaux records personnels. + +### Profil et personnalisation + +DonnĂ©es physiques, Ă©quipements disponibles, cadre de profil personnalisable (forme et couleur), thĂšmes visuels dĂ©bloquĂ©s par la progression, vitrine de trophĂ©es et de records mis en avant, roadmap des rangs, cĂ©lĂ©bration d'anniversaire, systĂšme de parrainage avec rĂ©compenses pour les deux parties, suppression de compte RGPD en cascade. + +### Tutoriel interactif + +SystĂšme de spotlight en huit chapitres qui met en surbrillance les Ă©lĂ©ments rĂ©els de l'interface, avec dĂ©monstrations en direct, auto-scroll vers les Ă©lĂ©ments ciblĂ©s, et persistance de la complĂ©tion Ă  la fois localement et cĂŽtĂ© serveur pour une cohĂ©rence entre appareils. --- -## 🛠 Stack technique +## Stack technique | Couche | Technologie | Version | |--------|-------------|---------| | Framework | React Native | 0.81.5 | -| Environnement | Expo | ~54.0.27 | -| Navigation | React Navigation | 7.x | +| Runtime React | React | 19.1.0 | +| Environnement | Expo | 54.x | +| Navigation | React Navigation (native, bottom-tabs, stack, native-stack) | 7.x | | Stockage local | AsyncStorage | 2.2.0 | -| Token sĂ©curisĂ© | Expo SecureStore | ~15.0.8 | -| HTTP client | Axios | ^1.16.0 | -| Animations | Lottie React Native | ~7.3.1 | -| Graphiques | React Native Chart Kit | ^6.12.2 | -| SVG | React Native SVG | 15.12.1 | -| IcĂŽnes | @expo/vector-icons (Ionicons) | ^15.0.3 | -| Haptics | Expo Haptics | ~15.0.8 | -| Gradients | Expo Linear Gradient | ~15.0.8 | -| Gestures | React Native Gesture Handler | ~2.28.0 | +| Token sĂ©curisĂ© | Expo SecureStore | 15.x | +| HTTP client | Axios | 1.18 | +| Animations | Lottie React Native | 7.3.1 | +| Graphiques | React Native Chart Kit | 6.12 | +| SVG | React Native SVG | 15.12 | +| IcĂŽnes | Expo Vector Icons (Ionicons) | 15.x | +| Haptique | Expo Haptics | 15.x | +| DĂ©gradĂ©s | Expo Linear Gradient | 15.x | +| Gestes | React Native Gesture Handler | 2.28 | +| Notifications | Expo Notifications | 0.32 | +| Authentification Google | Expo Auth Session | 7.x | +| Support web | React Native Web | 0.19 | +| Variables d'environnement | react-native-dotenv | 3.x | +| Tests | Jest, Babel Jest | 29.x | --- -## 🏗 Architecture +## Architecture + +### RĂ©partition backend et stockage local + +``` +NĂ©cessite le backend, rĂ©seau requis + - Connexion, inscription, rĂ©initialisation de mot de passe, connexion Google + - Profil utilisateur, cadre Ă©quipĂ©, vitrines + - Amis, groupes de streak, lobby multijoueur, inventaire, coffres + - Titres RPG, trophĂ©es serveur, parrainage, anniversaire + - Synchronisation de l'XP totale (best effort, ne bloque jamais) + +StockĂ© localement (AsyncStorage) + - Logs de sĂ©ances, XP cumulatif, streak + - QuĂȘtes quotidiennes et Ă©tat du bonus + - Rituels de rĂ©cupĂ©ration + - Exercices personnalisĂ©s, sĂ©ances sauvegardĂ©es + - Progression et complĂ©tion du tutoriel interactif + - ParamĂštres dĂ©veloppeur (God Mode, bypass anti-triche) +``` -### RĂ©partition backend / stockage local +### Arbre de providers ``` -┌───────────────────────────────────────────────────────────────┐ -│ NÉCESSITE LE BACKEND (rĂ©seau requis) │ -│ ‱ Connexion / Inscription / Reset password │ -│ ‱ RĂ©cupĂ©ration du profil utilisateur │ -│ ‱ Catalogue d'exercices WGER │ -│ ‱ Sync sĂ©ances (best-effort, ne bloque pas si KO) │ -└───────────────────────────────────────────────────────────────┘ - -┌───────────────────────────────────────────────────────────────┐ -│ STOCKÉ LOCALEMENT (AsyncStorage) │ -│ ‱ Logs de sĂ©ances, XP cumulatif, streak │ -│ ‱ QuĂȘtes quotidiennes et Ă©tat bonus │ -│ ‱ Rituels de rĂ©cupĂ©ration │ -│ ‱ Exercices personnalisĂ©s, sĂ©ances favorites │ -│ ‱ ParamĂštres dĂ©veloppeur (God Mode, bypass
) │ -└───────────────────────────────────────────────────────────────┘ - -┌─────────────────────────────────────────────────────┐ -│ COMPOSANT UI │ -└────────────────────┬────────────────────────────────┘ - │ -┌────────────────────▌────────────────────────────────┐ -│ CONTEXT (Ă©tat global React) │ -│ WorkoutLogsContext · QuestContext · TutorialContext │ -└───────────┬─────────────────────────┬───────────────┘ - │ read/write │ best-effort -┌───────────▌──────────┐ ┌─────────▌──────────────┐ -│ AsyncStorage │ │ API Backend │ -│ (source de vĂ©ritĂ© │ │ (auth + sync) │ -│ pour les logs) │ │ │ -└──────────────────────┘ └────────────────────────-┘ +NavigationContainer + TutorialProvider + UserProvider + WorkoutLogsProvider + SavedWorkoutsProvider + CustomExercisesProvider + QuestProvider + AuthStack (non connectĂ©) + ou BottomTabs (connectĂ©), avec en overlay : + BirthdayCelebration, LevelUpCelebration, + ActivityFeedModal, WeightReminderCheck, LobbyInviteCheck ``` -### Finalisation d'une sĂ©ance (WorkoutInProgressContext) +### Finalisation d'une sĂ©ance ``` handleTerminate() - │ - ├── elapsed < 5 min && !bypassAnticheat ? - │ └── ShortSessionWarningModal - │ ├── "Modifier" → retour sĂ©ance - │ └── "Forcer" → finalizeWithLog({ shortSession: true }) - │ - └── finalizeWithLog({ durationSeconds, notes, ... }) - │ - ├── buildLogFromWorkout() // calcul XP, volume, muscleDistribution - ├── shortSession ? xpEarned = 0 : normal - ├── workoutLogs.create(log) // AsyncStorage (toujours) - ├── !shortSession → questContext.checkAndUpdateQuests() - └── bundle.actions.finalize() // sync backend (best-effort) + elapsed < 5 minutes et bypass non activĂ© + -> ShortSessionWarningModal + Modifier : retour Ă  la sĂ©ance + Forcer : finalise avec shortSession = true + + finalizeWithLog(...) + buildLogFromWorkout() calcule XP, volume, rĂ©partition musculaire + shortSession ? xpEarned = 0 : calcul normal avec multiplicateur de streak + workoutLogs.create(log) Ă©criture AsyncStorage, toujours exĂ©cutĂ©e + !shortSession -> questContext.checkAndUpdateQuests() + actions.finalize() synchronisation backend, best effort + xpSync.service -> POST /users/me/sync-xp avec le nouveau total ``` --- -## 🚀 Installation & lancement +## Installation et lancement ### PrĂ©requis -- Node.js ≄ 18 -- npm ou yarn +- Node.js 18 ou supĂ©rieur - Expo CLI (`npm install -g expo-cli`) -- Expo Go sur votre tĂ©lĂ©phone (iOS ou Android) **ou** un Ă©mulateur +- Expo Go sur un tĂ©lĂ©phone, ou un simulateur iOS ou Android, ou un navigateur pour la version web ### Étapes ```bash -# 1. Cloner le dĂ©pĂŽt git clone https://github.com/ClemLy/Athly.git cd Athly/front -# 2. Installer les dĂ©pendances npm install -# 3. Configurer les variables d'environnement cp .env.example .env -# Éditer .env avec l'URL de votre backend (voir section suivante) - -# 4. Lancer le serveur de dĂ©veloppement -npm start +# Éditer .env avec l'URL de votre backend, voir la section suivante -# Alternatives ciblĂ©es -npm run android # Lancer sur Ă©mulateur Android -npm run ios # Lancer sur simulateur iOS (macOS requis) -npm run web # Lancer dans le navigateur +npm start # Metro bundler, QR code Expo Go +npm run android # Ă©mulateur Android +npm run ios # simulateur iOS, macOS requis +npm run web # navigateur +npm run build:web # build PWA de production (expo export puis copie du service worker) ``` -Expo affichera un QR code Ă  scanner avec Expo Go sur votre tĂ©lĂ©phone. - --- -## 🔑 Variables d'environnement - -CrĂ©er un fichier `.env` Ă  la racine de `athly-app/` : +## Variables d'environnement ```env -# URL de l'API backend (remplacer par votre IP locale en dĂ©veloppement) +# URL de l'API backend. En dĂ©veloppement local, utiliser l'IP de la machine +# sur le rĂ©seau local, jamais "localhost" : un tĂ©lĂ©phone physique ne peut pas +# le rĂ©soudre. API_URL=http://VOTRE_IP_LOCALE:4000/api -# ClĂ© de stockage du token JWT dans SecureStore +# ClĂ© de stockage du token JWT dans Expo SecureStore TOKEN_KEY=athly_token -# Environnement (development | production) +# development ou production APP_ENV=development + +# Client IDs Google OAuth (un par plateforme, type d'application diffĂ©rent +# pour chacun). Tant qu'ils ne sont pas renseignĂ©s, le bouton Google reste +# dĂ©sactivĂ© cĂŽtĂ© client. +GOOGLE_EXPO_CLIENT_ID= +GOOGLE_IOS_CLIENT_ID= +GOOGLE_ANDROID_CLIENT_ID= +GOOGLE_WEB_CLIENT_ID= ``` -> **Important :** En dĂ©veloppement local, utilisez votre adresse IP sur le rĂ©seau local (pas `localhost` — React Native ne peut pas rĂ©soudre `localhost` sur tĂ©lĂ©phone physique). +Trouver son IP locale : `ipconfig` sous Windows, `ifconfig` ou `ip addr` sous macOS et Linux. --- -## 📁 Structure du projet +## Structure du projet ``` -athly-app/ -├── index.js # Point d'entrĂ©e Expo -├── App.js # Root : providers + navigation -├── app.json # Configuration Expo -├── .env # Variables d'environnement -│ -├── assets/ -│ ├── icon.png, adaptive-icon.png, splash-icon.png -│ ├── logo-orange.png, logo-violet.png -│ └── animations/ -│ └── confetti.json # Animation Lottie (quĂȘte bonus) -│ -└── src/ - ├── api/ - │ └── api.js # Instance Axios (JWT auto-inject, 401 handler) - │ - ├── context/ # État global React (9 contextes) - │ ├── AuthContext.js - │ ├── UserContext.js - │ ├── WorkoutInProgressContext.js - │ ├── WorkoutLogsContext.js - │ ├── CustomExercisesContext.js - │ ├── SavedWorkoutsContext.js - │ ├── QuestContext.js - │ ├── TutorialContext.js - │ └── ToastContext.js - │ - ├── screens/ # 23 Ă©crans - │ ├── Auth/ # AuthScreen, Login, Register, Verify, ForgotPassword - │ ├── Home/ # HomeScreen - │ ├── Workouts/ # WorkoutScreen, Builder, List, Detail, ExerciseStats
 - │ ├── Profile/ # Profile, Edit, Settings, RankRoadmap, TrophyRoom - │ └── Stats/ # StatsScreen - │ - ├── components/ # 47 composants rĂ©utilisables - │ ├── home/ # DailyQuestsCard, RecoveryRitualsCard, QuickStatsRow
 - │ ├── workouts/ # SetTable, AddExerciseSheet, ShortSessionWarningModal
 - │ ├── cards/ # ExerciseCard, WorkoutItem, StatBox
 - │ ├── profile/ # TrophyGrid, EmberParticles - │ ├── tutorial/ # TutorialOverlay - │ └── ui/ # AppToast - │ - ├── services/ # Logique mĂ©tier - │ ├── stats.service.js # XP, streak, logs AsyncStorage (source de vĂ©ritĂ©) - │ ├── quest.service.js # 20 templates · 3 quĂȘtes/jour dĂ©terministes - │ ├── auth.service.js # API auth - │ ├── workout.service.js # API workouts - │ ├── customExercises.service.js - │ └── savedWorkouts.service.js - │ - ├── hooks/ # Custom hooks - │ ├── useWorkoutState.js # Reducer pattern pour l'Ă©tat sĂ©ance - │ ├── useEffortTimer.js # ChronomĂštre sĂ©ance - │ ├── useDevSettings.js # ParamĂštres dĂ©veloppeur (God Mode, bypass
) - │ └── useExerciseSorting.js - │ - ├── data/ # DonnĂ©es statiques - │ ├── exerciseCatalog.js # 100+ exercices avec muscles cibles - │ ├── trophyCatalog.js # 50+ dĂ©finitions de trophĂ©es - │ ├── tutorialChapters.js # Étapes du tutoriel - │ ├── workoutTemplates.js # Programmes prĂ©dĂ©finis - │ ├── ritualTypes.js # 5 rituels de rĂ©cupĂ©ration - │ └── profileThemes.js # ThĂšmes visuels du profil - │ - ├── navigation/ - │ ├── index.js # AppNavigator (Auth vs App) - │ ├── AuthStack.js - │ ├── BottomTabs.js # 5 onglets - │ ├── WorkoutStack.js - │ └── ProfileStack.js - │ - ├── constants/ - │ ├── theme.js # Design tokens (Colors, MUSCLE_GROUP_COLORS) - │ └── exerciseFilters.js # Mapping muscles/Ă©quipements - │ - └── styles/ - └── global.js # Styles utilitaires partagĂ©s +front/ + index.js Point d'entrĂ©e Expo + App.js Composant racine, wrapping des providers + app.json Configuration Expo, y compris la PWA + eas.json Profils de build EAS + web/index.html Shell HTML pour le build web + + assets/ + + src/ + api/ + api.js Instance Axios : injection du JWT, gestion du 401 + + context/ 9 contextes React + AuthContext.js + UserContext.js + WorkoutInProgressContext.js + WorkoutLogsContext.js + CustomExercisesContext.js + SavedWorkoutsContext.js + QuestContext.js + TutorialContext.js + ToastContext.js + + screens/ 21 Ă©crans + Auth/ Login, Register, EmailVerification, ForgotPassword + Home/ HomeScreen + Workouts/ WorkoutList, Workout, Builder, ManualCreator, + ExerciseDetail, ExerciseStats, EditExercise, + CustomExercises + Social/ SocialScreen, FriendProfileScreen + Stats/ StatsScreen + Profile/ Profile, EditProfile, Settings, RankRoadmap, + TrophyRoom, Inventory + + components/ OrganisĂ©s par domaine + home/ Cartes du tableau de bord, rituels de rĂ©cupĂ©ration + workouts/ Feuille d'ajout d'exercice, lobby multijoueur, + modale de sauvegarde, avertissement anti-triche + cards/ Cartes d'exercices rĂ©utilisables + profile/ Cadre d'avatar, vitrine de trophĂ©es, cĂ©lĂ©brations + social/ Modales d'amis, de groupe, flux d'activitĂ© + inventory/ Modale d'ouverture de coffre + stats/ Graphiques, calendrier, historique + tutorial/ Overlay du tutoriel interactif + common/ Modales partagĂ©es, barrel d'export + inputs/, ui/, web/ Composants transverses + + services/ Barrel d'export unique, 17 fichiers + stats.service.js XP, streak, logs AsyncStorage, source de vĂ©ritĂ© locale + quest.service.js ModĂšles de quĂȘtes, sĂ©lection dĂ©terministe du jour + auth.service.js, workouts.service.js, savedWorkouts.service.js, + customExercises.service.js, social.service.js, inventory.service.js, + reward.service.js, title.service.js, weight.service.js, + xpSync.service.js, onboarding.service.js, profile.service.js, + lobby.service.js, debug.service.js, haptics.service.js, + notificationService.js + + hooks/ Barrel d'export unique + useWorkoutState.js Pattern reducer pour l'Ă©tat de sĂ©ance en cours + useEffortTimer.js ChronomĂštre de sĂ©ance + useDevSettings.js ParamĂštres God Mode + useExerciseSorting.js + useAvatarFrame.js + useFeaturedTrophies.js + useGoogleAuth.js + + data/ Catalogues statiques + exerciseCatalog.js Plus de 350 exercices avec muscles ciblĂ©s + trophyCatalog.js Catalogue local de trophĂ©es et filtres + backendTrophyCategories.js Correspondance des catĂ©gories serveur + tutorialChapters.js 8 chapitres du tutoriel interactif + workoutTemplates.js Programmes prĂ©dĂ©finis + ritualTypes.js 5 rituels de rĂ©cupĂ©ration + profileThemes.js ThĂšmes visuels du profil + majorExercises.js Exercices de rĂ©fĂ©rence pour les classements + + navigation/ + index.js AppNavigator : bascule Auth ou App, providers globaux + AuthStack.js + BottomTabs.js 5 onglets + WorkoutStack.js + ProfileStack.js + SocialStack.js + + constants/ + theme.js Jetons de design (Colors, MUSCLE_GROUP_COLORS) + exerciseFilters.js Correspondance muscles et Ă©quipements ``` --- -## 🎼 SystĂšme de gamification +## Navigation -### Calcul de l'XP par sĂ©ance +``` +AppNavigator (racine) + Non connectĂ© : AuthStack + Auth (LoginScreen) + Register + EmailVerification + ForgotPassword + + ConnectĂ© : BottomTabs, 5 onglets + Accueil HomeScreen + SĂ©ances WorkoutStack + WorkoutList, WorkoutBuilder, ManualWorkoutCreator, CustomExercises, + EditExercise, Workout (sĂ©ance en cours), ExerciseDetail, ExerciseStats + Stats StatsScreen + SocialTab SocialStack + SocialHub, FriendProfile + ProfileTab ProfileStack + ProfileMain, EditProfile, RankRoadmap, TrophyRoom, Settings, Inventory +``` -```javascript -// 1. XP de base (calculĂ© par buildLogFromWorkout) -baseXP = volume * 0.12 + setsCompleted * 8 + totalExercises * 15 +--- -// 2. Multiplicateur de streak -xpEarned = round(baseXP * streakMultiplier) +## Contextes React -// 3. Bonus sĂ©ance longue (> 15 min) -// Normal : aucun modificateur nĂ©gatif -// SĂ©ance courte (< 15 min mais > 5 min) : XP Ă· 10 -// SĂ©ance trop courte (< 5 min, forcĂ©e) : XP = 0 -``` +### WorkoutLogsContext -### Niveaux +Source de vĂ©ritĂ© principale pour l'historique de sĂ©ances, persistĂ©e dans AsyncStorage. Expose la liste complĂšte des logs, les logs de sĂ©ances seules, les logs comptant pour la streak, l'XP cumulatif, ainsi que les opĂ©rations de crĂ©ation, suppression et ajout de rituel. -```javascript -// XP nĂ©cessaire pour le niveau N -xpForLevel(n) = 4665 * (1.03^n - 1) / (1.03 - 1) - -// Exemples -Niveau 1 → 140 XP total -Niveau 10 → 1 604 XP total -Niveau 30 → 6 657 XP total -Niveau 100 → 85 000 XP total -``` +### QuestContext -### Multiplicateurs de streak +Les 3 quĂȘtes du jour, le nombre complĂ©tĂ©, l'Ă©tat du bonus, et la fonction qui Ă©value une sĂ©ance terminĂ©e contre les quĂȘtes actives. -| Streak | Multiplicateur | Label | -|--------|---------------|-------| -| 0 jour | ×1.0 | — | -| 3 jours | ×1.1 | On Fire đŸ”„ | -| 7 jours | ×1.2 | Week Warrior ⚔ | -| 30 jours | ×1.5 | Godly Streak 👑 | -| 90 jours | ×2.0 | 3 Mois de Feu 🌊 | -| 180 jours | ×3.0 | Semi-Annuel 💎 | -| 365 jours | ×4.5 | Streak Annuel 🌟 | -| 730 jours | ×7.0 | Streak LĂ©gendaire ⚡ | +### TutorialContext -### QuĂȘtes quotidiennes +Machine Ă  Ă©tats du tutoriel interactif : chapitre actif, Ă©tape courante, cibles enregistrĂ©es par les Ă©crans, fonctions de scroll et de re-mesure, complĂ©tion locale et rĂ©conciliation avec le flag serveur. + +### WorkoutInProgressContext -3 quĂȘtes sont sĂ©lectionnĂ©es chaque jour parmi 20 templates (sĂ©lection dĂ©terministe par hash de la date — tout le monde a les mĂȘmes quĂȘtes le mĂȘme jour) : +État de la sĂ©ance en cours (reducer), actions d'ajout et de modification de sets et d'exercices, et la fonction `finalize` qui orchestre le log local, la validation des quĂȘtes et la synchronisation backend. -```javascript -// Exemples de templates -{ id: 'volume_10k', check: log => log.totalVolume >= 10000 } -{ id: 'sets_25', check: log => log.setsCompleted >= 25 } -{ id: 'duration_45', check: log => log.durationSeconds <= 2700 } -{ id: 'legs_day', check: log => log.muscleDistribution.jambes >= 40 } -{ id: 'new_pr', check: (_, prs) => prs.length > 0 } -``` +### UserContext + +Profil utilisateur courant, rĂ©cupĂ©rĂ© depuis le backend, avec fonction de rafraĂźchissement. + +### AuthContext + +Token JWT, Ă©tat de chargement initial, connexion et dĂ©connexion. -- ComplĂ©ter **1 quĂȘte** : +500 XP -- ComplĂ©ter **les 3 quĂȘtes** : +1000 XP bonus (animation confetti) +### SavedWorkoutsContext, CustomExercisesContext + +CRUD des sĂ©ances sauvegardĂ©es et des exercices personnalisĂ©s, persistĂ©s dans AsyncStorage. + +### ToastContext + +File de notifications toast affichĂ©es en overlay. --- -## đŸ§© Contextes React +## Services -### WorkoutLogsContext +Tous les services sont exposĂ©s via un barrel unique (`src/services/index.js`), ce qui permet des imports courts comme `import { getFriendsList, haptics } from '../services'`. -Source de vĂ©ritĂ© principale pour l'historique des sĂ©ances. Persiste dans AsyncStorage. +### stats.service.js -```javascript -const { - items, // Tous les logs (sĂ©ances + rituels + quĂȘtes) - sessionLogs, // Logs sĂ©ances uniquement (pas rituels, pas quest_reward) - activityLogs, // Pour calcul streak (pas shortSession, pas quest_reward) - loading, error, - refresh, - create(log), // Ajouter log - remove(id), // Supprimer log - addRitual(ritualId, label, duration, xpEarned), // Rituel de rĂ©cupĂ©ration - totalXP, // XP cumulatif - clearAll, // Debug uniquement -} = useWorkoutLogs(); -``` +Le service le plus important : gestion complĂšte des logs AsyncStorage, calcul de l'XP par sĂ©ance, du streak, du multiplicateur, du niveau, des rangs, de la rĂ©partition musculaire, dĂ©tection des nouveaux records. -### QuestContext +### quest.service.js -```javascript -const { - quests, // [{id, label, icon, completed, xp}] × 3 - bonusClaimed, // Bonus 3/3 quĂȘtes dĂ©jĂ  rĂ©clamĂ© - completedCount, // 0-3 - checkAndUpdateQuests(log, newPRs), // → {completedQuests, bonusUnlocked, questXP} - refresh, -} = useQuests(); -``` +Chargement des quĂȘtes du jour, sĂ©lection dĂ©terministe par hash de date parmi 20 modĂšles, vĂ©rification et marquage de complĂ©tion. -### TutorialContext +### workouts.service.js -```javascript -const { - isActive, activeChapterId, stepIndex, - hasCompleted, pendingChapterId, - targets, - registerTarget(key, rect), - registerScrollRef(chapterId, ref), - registerRemeasure(chapterId, fn), - scrollToStep(chapterId, y), - startChapter(chapterId), - nextStep, prevStep, finishChapter, - bootstrapped, -} = useTutorial(); -``` +Cycle de vie cĂŽtĂ© backend des sĂ©ances : crĂ©ation de brouillon, mise Ă  jour, finalisation, complĂ©tion. -### WorkoutInProgressContext +### api.js -```javascript -const { - state, // {id, name, exercises, notes, status, durationSeconds} - dispatch, - actions: { - finalize, // = finalizeWithLog() — log local + sync backend - addSet, updateSet, removeSet, - addExercise, removeExercise, - updateNotes, - }, - loadWorkout(workout), - addExerciseToWorkout(exercise), -} = useWorkoutInProgress(); -``` +Instance Axios : URL de base depuis `.env`, timeout, injection automatique du Bearer token, et sur une rĂ©ponse 401, dĂ©connexion automatique avec message de session expirĂ©e. --- -## ⚙ Services +## Catalogues de donnĂ©es -### stats.service.js (AsyncStorage) +### exerciseCatalog.js -Le service le plus important — toute la logique locale de logs et de calculs XP. +Plus de 350 exercices, chacun avec son groupe musculaire, son muscle cible principal, ses muscles secondaires, son Ă©quipement requis, son niveau de difficultĂ©, et un indicateur de mouvement composĂ© ou d'isolation. -```javascript -// CRUD logs AsyncStorage -listLogs() → WorkoutLog[] -addLog(log) → WorkoutLog (avec cap 2 XP/jour) -removeLog(id) → void -addRitualLog(ritualId, label, duration, xpEarned) → WorkoutLog | null (max 1/jour) - -// Calculs purs -buildLogFromWorkout(stateSnapshot, prevLogs) → WorkoutLog complet -findNewPRsInLog(log, allLogs) → PR[] -computeStreak(logs) → number -getStreakMultiplier(streak) → {multiplier, label, color, tier} -xpForLevel(n) → number -totalCumulativeXP(logs) → number -``` +### trophyCatalog.js -### quest.service.js +40 trophĂ©es locaux rĂ©partis en 8 catĂ©gories (HĂ©ritage, Force, Exploration, Secret, Corps, RĂ©gularitĂ©, Social, SpĂ©cial), plus le trophĂ©e capstone Souverain Absolu. CombinĂ© avec les 20 trophĂ©es serveur (catĂ©gorie Collection notamment), le total dĂ©passe 60 trophĂ©es rĂ©partis en 9 catĂ©gories affichĂ©es dans la Salle des TrophĂ©es. -```javascript -loadTodayQuests() → {date, quests, bonusClaimed} -checkAndMarkQuests(log, prs) → {completedIds, bonusUnlocked} -saveTodayQuests(state) -getTemplateById(id) → Template -``` +### tutorialChapters.js -### api.js (instance Axios) +8 chapitres correspondant aux grands Ă©crans de l'application : Dashboard, EntraĂźnement, Profil et Vitrine, Salle des TrophĂ©es, Inventaire, Social, Statistiques, RĂ©glages. -- **URL de base** : `API_URL` depuis `.env` -- **Timeout** : 10 secondes -- **Intercepteur requĂȘte** : injecte automatiquement `Authorization: Bearer {token}` -- **Intercepteur rĂ©ponse** : sur 401 → appelle `signOut()` + message "Session expirĂ©e" +### ritualTypes.js ---- +5 rituels de rĂ©cupĂ©ration active. -## đŸ—ș Navigation +| Rituel | MĂ©canique | XP | +|--------|-----------|-----| +| MobilitĂ© et souplesse | Minuteur de 5 minutes | 20 | +| Marche quotidienne | Minuteur de 15 minutes | 100 | +| Respiration et mental | Cercle animĂ© inspire et expire, 5 minutes | 20 | +| Automassage | 5 zones d'une minute chacune | 20 | +| Focus et culture | Article Ă  lire, minuteur bloquant de 5 minutes | 20 | -``` -AppNavigator (root) -├── {!userToken} AuthStack -│ ├── AuthScreen (landing) -│ ├── LoginScreen -│ ├── RegisterScreen -│ ├── EmailVerificationScreen -│ └── ForgotPasswordScreen -│ -└── {userToken} BottomTabs (5 onglets) - ├── 🏠 HomeScreen - ├── đŸ’Ș WorkoutStack - │ ├── WorkoutListScreen - │ ├── WorkoutScreen (sĂ©ance en cours) - │ ├── WorkoutBuilderScreen - │ ├── WorkoutDetailScreen - │ ├── ManualWorkoutCreatorScreen - │ ├── ExerciseDetailScreen - │ ├── ExerciseStatsScreen - │ ├── EditExerciseScreen - │ └── CustomExercisesScreen - ├── 📊 StatsScreen - └── đŸ‘€ ProfileStack - ├── ProfileScreen - ├── EditProfileScreen - ├── SettingsScreen - ├── RankRoadmapScreen - └── TrophyRoomScreen -``` +Un rituel maximum par jour calendaire. Compte pour la streak au mĂȘme titre qu'une sĂ©ance, et son XP n'est pas soumis au plafond quotidien. --- -## 🎹 Composants clĂ©s - -### `RecoveryRitualsCard` -Carte affichĂ©e sur HomeScreen les jours sans sĂ©ance. Propose 5 rituels de rĂ©cupĂ©ration, chacun avec son propre composant interactif : -- `CountdownTimer` — timer circulaire standard (mobilitĂ©, marche) -- `BreathingTimer` — cercle animĂ© inspire (4s) / expire (6s) -- `FoamRollingTimer` — 5 zones × 60s avec dots de progression -- `FocusReader` — article alĂ©atoire parmi 3, timer 5 min bloquant +## SystĂšme de gamification -### `ShortSessionWarningModal` -Modale animĂ©e (spring) dĂ©clenchĂ©e si la sĂ©ance dure < 5 min : -- "Modifier la sĂ©ance" → reprend l'entraĂźnement -- "Valider quand mĂȘme (0 XP)" → sauvegarde avec `shortSession: true` - -### `WorkoutRecapModal` -RĂ©capitulatif post-sĂ©ance : -- Volume total, sets complĂ©tĂ©s, durĂ©e, XP gagnĂ© -- Nouveaux PRs battus -- QuĂȘtes validĂ©es dans la sĂ©ance -- Animation confetti si bonus 3/3 quĂȘtes +### Calcul de l'XP par sĂ©ance -### `TutorialOverlay` -Overlay semi-transparent avec : -- DĂ©coupe transparente autour de l'Ă©lĂ©ment cible (`registerTarget`) -- Bulle de texte positionnĂ©e dynamiquement (top/bottom/center) -- Boutons PrĂ©cĂ©dent / Suivant / Terminer +```javascript +// Par exercice, calculĂ© en local (stats.service.js) +xp += setsCompleted * 10 + (volume * multiplicateur) / 20 +// multiplicateur = 1.2 si l'exercice est un mouvement composĂ©, sinon 1 -### `DailyQuestsCard` -Affiche les 3 quĂȘtes du jour avec progression, labels, icĂŽnes et le statut du bonus. +// Multiplicateur de streak appliquĂ© au total +xpEarned = round(xp * streakMultiplier) -### Design System (`src/constants/theme.js`) +// Anti-triche temporel +// moins de 5 minutes, forcĂ© : xpEarned = 0 +// entre 5 et 15 minutes : xpEarned = xpEarned / 10 +// 15 minutes ou plus : XP plein +``` -Toutes les couleurs passent par des tokens centralisĂ©s : +### Niveaux ```javascript -Colors.primary // #FE7439 (orange — accent principal) -Colors.secondaryAccent // #6E6AF0 (violet) -Colors.valid // #22C55E (vert validation) -Colors.warningAmber // #F59E0B (avertissement) -Colors.textPrimary // blanc pleine opacitĂ© -Colors.textSecondary // blanc ~70% -Colors.textMuted // blanc ~45% -Colors.card // fond carte -Colors.background // fond gĂ©nĂ©ral (dark) +xpForLevel(n) = round(4665 * (1.03 ** min(n, 200) - 1)) +// niveau 1 environ 140 XP, niveau 10 environ 1600 XP, +// niveau 100 environ 85 000 XP, niveau 200 environ 1 720 000 XP ``` +### Multiplicateurs de streak + +| Streak | Multiplicateur | Label | +|--------|-----------------|-------| +| 0 jour | x1.0 | | +| 3 jours | x1.1 | On Fire | +| 7 jours | x1.2 | Week Warrior | +| 30 jours | x1.5 | Godly Streak | +| 90 jours | x2.0 | 3 Mois de Feu | +| 180 jours | x3.0 | Semi-Annuel | +| 365 jours | x4.5 | Streak Annuel | +| 730 jours | x7.0 | Streak LĂ©gendaire | + +### QuĂȘtes quotidiennes + +3 quĂȘtes sĂ©lectionnĂ©es chaque jour parmi 20 modĂšles, par un hash dĂ©terministe de la date : tout le monde reçoit les mĂȘmes quĂȘtes le mĂȘme jour. ComplĂ©ter une quĂȘte rapporte de l'XP, complĂ©ter les 3 dĂ©clenche un bonus supplĂ©mentaire avec animation. + +### Rangs + +Novice, InitiĂ© Ă  partir du niveau 11, AthlĂšte Ă  31, CompĂ©titeur Ă  51, Warrior Ă  71, Élite Ă  91, MaĂźtre Ă  111, Grand MaĂźtre Ă  141, LĂ©gende Ă  171, ATHLY GOD Ă  200. + --- -## 🔗 Backend associĂ© +## Tutoriel interactif + +SystĂšme de spotlight en 8 chapitres, un par grande zone de l'application. Chaque Ă©tape peut cibler un Ă©lĂ©ment rĂ©el de l'Ă©cran (mesurĂ© dynamiquement via `useTutorialTarget`) ou afficher une carte centrĂ©e, avec positionnement automatique du texte au-dessus ou en dessous de la cible selon l'espace disponible. Auto-scroll vers les Ă©lĂ©ments hors champ, indicateur de progression Chapitre X sur N, retour haptique sur les actions de navigation. La complĂ©tion est persistĂ©e Ă  la fois dans AsyncStorage pour une reprise immĂ©diate, et cĂŽtĂ© serveur (`hasCompletedOnboarding`) pour rester cohĂ©rente entre appareils. Rejouable Ă  tout moment depuis les RĂ©glages, chapitre par chapitre. + +--- -Ce dĂ©pĂŽt frontend communique avec l'API **Athly Backend** (dĂ©pĂŽt sĂ©parĂ©). +## ParamĂštres dĂ©veloppeur (God Mode) -Le backend gĂšre : -- Authentification (JWT + OTP email) -- Synchronisation des sĂ©ances (best-effort depuis le front) -- Catalogue d'exercices (intĂ©gration WGER) -- Profil utilisateur +Accessibles depuis RĂ©glages, section God Mode. -> Voir le README du dĂ©pĂŽt backend pour l'installation et la documentation complĂšte de l'API. +| RĂ©glage | Effet | +|---------|-------| +| God Mode | Bascule gĂ©nĂ©rale utilisĂ©e par plusieurs outils de test | +| Bypass anti-triche 5 minutes | Ignore le seuil de durĂ©e minimale d'une sĂ©ance | +| Forcer l'affichage des rituels | Affiche la carte de rituels mĂȘme aprĂšs une sĂ©ance dĂ©jĂ  faite | +| Overrides de trophĂ©es | Force le dĂ©blocage ou le verrouillage d'un trophĂ©e pour le tester | -**L'application nĂ©cessite le backend pour l'authentification.** Une fois connectĂ©, les donnĂ©es de progression (logs, XP, quĂȘtes, rituels, trophĂ©es) sont stockĂ©es localement dans AsyncStorage — les calculs sont faits cĂŽtĂ© client. +PersistĂ©s dans AsyncStorage, rechargĂ©s Ă  chaque focus de l'Ă©cran concernĂ©. --- -## 🔧 ParamĂštres dĂ©veloppeur (God Mode) +## Tests + +```bash +npm test +``` + +3 suites Jest sur les modules JS purs (donnĂ©es et services sans dĂ©pendance React Native), exĂ©cutĂ©es via Babel en environnement Node : intĂ©gritĂ© structurelle du catalogue de chapitres du tutoriel, non-rĂ©gression des rituels de rĂ©cupĂ©ration, comportement du service de synchronisation d'XP. + +--- -Accessibles depuis ParamĂštres → section God Mode (uniquement en mode dev) : +## Backend associĂ© -| Toggle | Effet | -|--------|-------| -| God Mode | Bypass gĂ©nĂ©ral pour tests | -| Bypass anti-triche 5 min | Ignore le check de durĂ©e minimum | -| Forcer l'affichage des rituels | Affiche la carte rituels mĂȘme aprĂšs une sĂ©ance | +Ce dĂ©pĂŽt frontend communique avec l'API Athly Backend, dans le dossier `back/` du mĂȘme dĂ©pĂŽt. Le backend gĂšre l'authentification, le profil, le social (amis, groupes, lobby), l'inventaire et les coffres, les titres et trophĂ©es serveur, le parrainage, ainsi que la synchronisation de l'XP. Voir `back/README.md` pour l'installation et la documentation complĂšte de l'API. -Ces paramĂštres sont persistĂ©s dans AsyncStorage et se rechargent Ă  chaque focus de l'Ă©cran concernĂ©. +L'application nĂ©cessite le backend pour l'authentification et pour toutes les fonctionnalitĂ©s sociales et multijoueur. Les donnĂ©es de sĂ©ance immĂ©diates (logs, XP local, quĂȘtes, rituels) restent utilisables mĂȘme en cas de coupure rĂ©seau temporaire, la synchronisation reprenant automatiquement au retour du rĂ©seau. ---
-**Athly Front** · React Native + Expo · Offline-first +Athly Front : React Native, Expo, PWA. Local first pour l'entraßnement, backend pour le social.