# SSA Box Manager v2

Refonte Symfony 8 de l’application SSA Box Manager pour Saint Seiya Awakening.

L’objectif de cette v2 est de reprendre le socle de la v1, corriger ses limites, améliorer la maintenabilité et préparer les futures fonctionnalités communautaires.

## Stack technique

- Symfony 8
- PHP 8.4
- Doctrine ORM / Migrations
- Twig
- AssetMapper
- CSS natif
- JavaScript natif modulaire
- MySQL / MariaDB
- Composer
- Développement local Windows
- Déploiement prévu sur OVH mutualisé Pro

Le projet n’utilise pas Docker, Node, Webpack, SCSS, EasyAdmin ou SPA séparée.

## Installation locale

Cloner le projet puis installer les dépendances :

```bash
composer install
```

Créer le fichier local d’environnement :

```bash
copy .env .env.local
```

Adapter ensuite `.env.local`.

Exemple minimal :

```dotenv
APP_ENV=dev
APP_SECRET=change_me

DATABASE_URL="mysql://user:password@127.0.0.1:3306/ssa_boxmanager_v2?serverVersion=8.0.32&charset=utf8mb4"

MAILER_DSN=null://null
APP_MAILER_FROM_ADDRESS=no-reply@ssa-boxmanager.local
APP_MAILER_FROM_NAME="SSA Box Manager"
```

## Base de données

Créer la base si elle n’existe pas :

```bash
php bin/console doctrine:database:create --if-not-exists
```

Exécuter les migrations :

```bash
php bin/console doctrine:migrations:migrate
```

Vérifier le mapping Doctrine :

```bash
php bin/console doctrine:schema:validate
```

Vérifier l’état des migrations :

```bash
php bin/console doctrine:migrations:status
```

Avant de passer à une nouvelle US qui modifie le mapping Doctrine, l’état attendu est :

```text
New: 0
```

Si une migration est disponible mais pas exécutée, lancer :

```bash
php bin/console doctrine:migrations:migrate
```

Si `schema:validate` est OK mais que `migrations:status` affiche encore `New: 1`, identifier la migration restante :

```bash
php bin/console doctrine:migrations:list
```

Puis vérifier si la migration est réellement nécessaire, redondante, ou déjà appliquée manuellement en base.

## Fixtures de développement

Le Sprint 2 ajoute des fixtures de données jeu.

Installer le bundle si nécessaire :

```bash
composer require --dev doctrine/doctrine-fixtures-bundle
```

Charger les fixtures sans supprimer les utilisateurs locaux :

```bash
php bin/console doctrine:fixtures:load --append
```

Les fixtures créent ou mettent à jour notamment :

```text
Rangs : EX, SS, S, A, B, C
Rôles : dps, support, control, tank, heal
Sections : bronze_saints, gold_saints, specters, gods, asgard
Saints : Gemini Saga, Aries Mu, Pegasus Seiya, Asgard Siegfried
```

Fichier principal :

```text
src/DataFixtures/GameDataFixtures.php
```

## Lancement local

Avec Symfony CLI :

```bash
symfony server:start
```

Ou avec le serveur PHP natif :

```bash
php -S 127.0.0.1:8000 -t public
```

L’application est ensuite accessible sur :

```text
http://127.0.0.1:8000
```

Si le navigateur affiche `127.0.0.1 n’autorise pas la connexion`, vérifier d’abord que le serveur local tourne :

```bash
symfony server:status
```

Puis relancer si besoin :

```bash
symfony server:start
```

## Assets

Le projet utilise AssetMapper.

Entrée front :

```text
assets/app.js
```

Entrée admin :

```text
assets/admin.js
```

Les CSS sont factorisés par contexte.

CSS front :

```text
assets/styles/front/
├── 00-tokens.css
├── 01-base.css
├── 02-layout.css
├── 03-components.css
├── 04-auth.css
├── 05-saints.css
├── 06-errors.css
└── 07-box.css
```

CSS admin :

```text
assets/styles/admin/
├── 00-tokens.css
├── 01-base.css
├── 02-layout.css
├── 03-components.css
├── 04-tables.css
├── 05-forms.css
└── 06-saints.css
```

JavaScript front :

```text
assets/js/front/
├── theme.js
├── box-modal.js
├── box-progression.js
└── box-remove-confirm.js
```

JavaScript admin :

```text
assets/js/admin/
```

Vérifier la carte des assets :

```bash
php bin/console debug:asset-map
```

Compiler les assets pour la production :

```bash
php bin/console asset-map:compile
```

En développement, Symfony peut servir les assets dynamiquement.

Si le navigateur sert un ancien contenu de `assets/app.js`, vérifier qu’un ancien build n’est pas présent dans :

```text
public/assets/
```

En local, si nécessaire, supprimer les assets compilés puis vider le cache :

```powershell
Remove-Item -Recurse -Force .\public\assets
php bin/console cache:clear
```

Puis recharger fortement le navigateur avec `Ctrl + F5` ou `Ctrl + Shift + R`.

## Organisation applicative

Les éléments liés au front sont rangés dans des dossiers `Front`.

Les éléments liés à l’admin sont rangés dans des dossiers `Admin`.

Les éléments transverses restent dans les dossiers racine métier.

```text
src/
├── Controller/
│   ├── Admin/
│   ├── Front/
│   └── Security/
├── DataFixtures/
├── Entity/
├── Enum/
├── Form/
│   ├── Admin/
│   ├── Front/
│   └── Security/
├── Repository/
├── Security/
└── Service/
    ├── Admin/
    ├── Front/
    ├── Game/
    └── Security/
```

Conventions :

- les contrôleurs restent minces ;
- la logique métier va dans `src/Service/` ;
- les classes techniques Symfony Security vont dans `src/Security/` ;
- les formulaires sont rangés par contexte ;
- les enums transverses vont dans `src/Enum/` ;
- les repositories restent dans `src/Repository/`.

## Organisation des templates

Les templates sont séparés entre front et admin.

```text
templates/
├── front/
│   ├── account/
│   ├── box/
│   ├── partials/
│   ├── saint/
│   └── security/
├── admin/
│   ├── dashboard/
│   ├── rank/
│   ├── role/
│   ├── saint/
│   └── section/
└── bundles/
    └── TwigBundle/
        └── Exception/
```

Le layout front principal est :

```text
templates/front/base.html.twig
```

Les partials front sont dans :

```text
templates/front/partials/
```

Le layout admin principal est :

```text
templates/admin/base.html.twig
```

Les pages d’erreur personnalisées sont dans :

```text
templates/bundles/TwigBundle/Exception/
```

## Pages d’erreur

Le Sprint 2 ajoute des templates d’erreur personnalisés :

```text
templates/bundles/TwigBundle/Exception/error404.html.twig
templates/bundles/TwigBundle/Exception/error403.html.twig
templates/bundles/TwigBundle/Exception/error.html.twig
```

En environnement `dev`, Symfony affiche volontairement les pages d’exception techniques.

Pour prévisualiser les pages d’erreur personnalisées en dev, la route suivante peut être activée :

```text
config/routes/dev/framework.yaml
```

Contenu attendu :

```yaml
when@dev:
    _errors:
        resource: '@FrameworkBundle/Resources/config/routing/errors.php'
        prefix: /_error
```

Prévisualisation :

```text
/_error/404
/_error/403
/_error/500
```

## Authentification

Le Sprint 1 met en place le socle utilisateur :

- inscription ;
- confirmation email ;
- connexion ;
- déconnexion ;
- mot de passe oublié ;
- rate limits ;
- préparation migration v1 SHA-256.

### Identifiant de connexion

Le login se fait avec le `username`.

C’est volontaire pour assurer la compatibilité avec la v1, où le login historique est un username et non un email.

L’email reste nécessaire pour :

- les nouveaux comptes v2 ;
- la confirmation email ;
- la récupération de mot de passe ;
- la future liaison multi-box.

Les comptes legacy v1 peuvent temporairement ne pas avoir d’email en base.

### Confirmation email

Les nouveaux comptes v2 sont créés avec :

```text
is_verified = false
```

Ils doivent confirmer leur email avant de pouvoir se connecter.

En local, les emails ne sont pas réellement envoyés avec :

```dotenv
MAILER_DSN=null://null
```

Pendant le Sprint 1, les liens de confirmation sont loggés dans :

```text
var/log/dev.log
```

Rechercher :

```text
Email confirmation link generated.
```

### Mot de passe oublié

La récupération de mot de passe se fait uniquement par email.

Un compte legacy sans email ne peut pas demander de reset password via username, afin d’éviter une récupération de compte risquée.

Pendant le Sprint 1, les liens de reset password sont loggés dans :

```text
var/log/dev.log
```

Rechercher :

```text
Password reset link generated.
```

### Migration password v1

La v1 utilise un hash SHA-256 legacy.

La v2 prépare une migration transparente :

1. un compte legacy possède un hash SHA-256 en base ;
2. l’utilisateur se connecte avec son mot de passe habituel ;
3. Symfony accepte temporairement le hash legacy ;
4. après connexion réussie, le mot de passe est rehashé avec le hasher Symfony moderne ;
5. le hash legacy est nettoyé.

Champs concernés dans `app_user` :

```text
password
legacy_password_hash
legacy_password_migrated_at
```

## Rate limits

Le Sprint 1 ajoute des protections sur :

- login ;
- inscription ;
- demande de reset password.

Le login throttling est configuré dans :

```text
config/packages/security.yaml
```

Les limiters applicatifs sont configurés dans :

```text
config/packages/rate_limiter.yaml
```

Service dédié :

```text
src/Service/Security/AuthRateLimiterService.php
```

## Admin custom

Le Sprint 2 ajoute un début de backoffice custom, sans EasyAdmin.

Layout admin :

```text
templates/admin/base.html.twig
```

Dashboard :

```text
src/Controller/Admin/DashboardController.php
templates/admin/dashboard/index.html.twig
```

Route principale :

```text
/admin
```

La zone admin est protégée par :

```text
ROLE_ADMIN
```

Règle attendue dans `config/packages/security.yaml` :

```yaml
access_control:
    - { path: ^/admin, roles: ROLE_ADMIN }
```

Pour donner temporairement le rôle admin à un compte local :

```sql
UPDATE app_user
SET roles = '["ROLE_ADMIN"]'
WHERE username = 'TON_USERNAME';
```

## Données jeu — Sprint 2

Le Sprint 2 pose les fondations des données jeu administrables.

Enums transverses :

```text
src/Enum/AppLocale.php
src/Enum/SaintGender.php
src/Enum/SaintStatus.php
```

Locales supportées :

```text
fr
en
es
pt
de
```

Fallback applicatif de contenu :

```text
en
```

Statuts de Saint :

```text
draft
published
upcoming
expected
archived
```

Différence métier importante :

- `upcoming` : Saint annoncé, teasé, bêta, CN ou probablement à venir ;
- `expected` : Saint souhaité ou proposé par la communauté, non confirmé officiellement.

## Référentiels jeu

Entités de référentiel :

```text
src/Entity/Rank.php
src/Entity/RankTranslation.php
src/Entity/Role.php
src/Entity/RoleTranslation.php
src/Entity/Section.php
src/Entity/SectionTranslation.php
```

Repositories :

```text
src/Repository/RankRepository.php
src/Repository/RoleRepository.php
src/Repository/SectionRepository.php
```

Tables SQL :

```text
game_rank
game_rank_translation
game_role
game_role_translation
game_section
game_section_translation
```

Routes admin :

```text
/admin/ranks
/admin/ranks/new
/admin/ranks/{id}/edit

/admin/roles
/admin/roles/new
/admin/roles/{id}/edit

/admin/sections
/admin/sections/new
/admin/sections/{id}/edit
```

Les référentiels ne sont pas supprimés physiquement au Sprint 2. Ils sont activables/désactivables avec `isActive`.

## Saints

Entités :

```text
src/Entity/Saint.php
src/Entity/SaintTranslation.php
```

Repository :

```text
src/Repository/SaintRepository.php
src/Repository/SaintTranslationRepository.php
```

Service de slug localisé :

```text
src/Service/Game/LocalizedSlugger.php
```

Service de préparation admin :

```text
src/Service/Admin/SaintAdminDataPreparer.php
```

Formulaires admin :

```text
src/Form/Admin/SaintType.php
src/Form/Admin/SaintTranslationType.php
```

Contrôleur admin :

```text
src/Controller/Admin/SaintController.php
```

Templates admin :

```text
templates/admin/saint/
```

Tables SQL :

```text
game_saint
game_saint_translation
game_saint_role
game_saint_section
```

Principes :

- `technicalSlug` est stable, unique, non localisé ;
- les slugs d’URL sont localisés dans `SaintTranslation.urlSlug` ;
- chaque Saint peut avoir plusieurs rôles ;
- chaque Saint peut appartenir à plusieurs sections ;
- le rang peut être nul pour les Saints en brouillon, à venir ou souhaités ;
- le fallback de contenu est l’anglais ;
- une traduction anglaise est garantie côté admin ;
- les traductions vides hors fallback ne sont pas persistées inutilement.

Exemples :

```text
technicalSlug = gemini_saga

/en/saints/gemini-saga
/fr/saints/saga-gemeaux
/es/saints/saga-de-geminis
```

Routes admin :

```text
/admin/saints
/admin/saints/new
/admin/saints/{id}/edit
```

## Front Saints

Le Sprint 2 ajoute une consultation front minimale des Saints publiés.

Contrôleur :

```text
src/Controller/Front/SaintController.php
```

Templates :

```text
templates/front/saint/index.html.twig
templates/front/saint/show.html.twig
```

Routes :

```text
/{_locale}/saints
/{_locale}/saints/{slug}
```

Exemples :

```text
/en/saints
/en/saints/gemini-saga
/fr/saints
/fr/saints/saga-gemeaux
/es/saints/saga-de-geminis
```

Seuls les Saints avec le statut suivant sont affichés :

```text
published
```

Les Saints `draft`, `upcoming`, `expected` et `archived` ne sont pas listés côté front public au Sprint 2.

## Box utilisateur — Sprint 3

Le Sprint 3 pose les fondations de la box utilisateur connectée.

Objectif fonctionnel :

- créer et résoudre automatiquement la box principale d’un utilisateur connecté ;
- afficher la box en grille ;
- ajouter un Saint publié à la box ;
- modifier la progression d’un Saint de box via une modale ;
- appliquer un reset, un maxxage standard et un over maxxage sans sauvegarde immédiate ;
- retirer un Saint de la box avec confirmation.

Entités :

```text
src/Entity/Box.php
src/Entity/BoxSaint.php
```

Relations principales :

```text
User 1──n Box
Box 1──n BoxSaint
BoxSaint n──1 Saint
```

Repositories :

```text
src/Repository/BoxRepository.php
src/Repository/BoxSaintRepository.php
src/Repository/SaintRepository.php
```

`SaintRepository` contient une méthode dédiée pour récupérer les Saints publiés non encore présents dans une box :

```text
findPublishedNotInBox(Box $box)
```

Tables SQL :

```text
user_box
user_box_saint
```

Principes métier :

- une box appartient à un utilisateur ;
- une box principale active est créée automatiquement si elle n’existe pas ;
- un même Saint ne peut pas être présent deux fois dans la même box ;
- la contrainte unique `box_id + saint_id` empêche les doublons en base ;
- seuls les Saints publiés peuvent être ajoutés à la box ;
- retirer un Saint supprime sa ligne `BoxSaint` et donc sa progression ;
- si le Saint est ajouté à nouveau ensuite, il revient aux valeurs initiales ;
- la suppression est protégée par POST, token CSRF, vérification d’appartenance à la box courante et confirmation navigateur.

Champs principaux de `BoxSaint` :

```text
level
stars
reincarnation
friendship
is_awakened
is_repair_cloth_active
is_starwill_active
skill1_level
skill2_level
skill3_level
skill4_level
eighth_sense_alpha
eighth_sense_beta
eighth_sense_gamma
eighth_sense_delta
is_favorite
private_note
public_note
created_at
updated_at
```

Valeurs initiales :

```text
level = 1
stars = 2
reincarnation = 0
friendship = 1
is_awakened = false
is_repair_cloth_active = false
is_starwill_active = false
skills = 1
8e sens = 1
is_favorite = false
```

Progression rapide en modale :

```text
Reset
- level 1
- stars 2
- reincarnation 0
- friendship 1
- skills 1
- 8e sens 1
- éveil / RC / Starwill désactivés

Maxxer
- level 80
- stars 6
- reincarnation 12
- friendship 10
- skills 5
- 8e sens 6
- éveil / RC / Starwill activés

Over maxxer
- mêmes valeurs que Maxxer
- stars 12
```

Le reset, le maxxage et l’over maxxage modifient uniquement les champs du formulaire en modale. La sauvegarde réelle se fait seulement au clic sur `Enregistrer`.

Services front :

```text
src/Service/Front/CurrentBoxResolver.php
src/Service/Front/BoxSaintManager.php
src/Service/Front/BoxSaintEditor.php
```

Formulaire front :

```text
src/Form/Front/BoxSaintType.php
```

Contrôleur front :

```text
src/Controller/Front/BoxController.php
```

Template front :

```text
templates/front/box/index.html.twig
```

Assets front dédiés :

```text
assets/styles/front/07-box.css
assets/js/front/box-modal.js
assets/js/front/box-progression.js
assets/js/front/box-remove-confirm.js
```

Routes :

```text
/{_locale}/box
/{_locale}/box/saints/add
/{_locale}/box/saints/{id}/edit
/{_locale}/box/saints/{id}/remove
```

Toutes les routes de box nécessitent un utilisateur connecté avec `ROLE_USER`.

## Convention de commentaire de fichier

Dans les fichiers autres que CSS ou HTML/Twig, le chemin complet du fichier est indiqué en haut du fichier sous forme de commentaire.

Exemple :

```php
<?php

// src/Service/Security/UserRegistrationService.php
```

Autres exemples :

```php
<?php

// src/Controller/Front/SaintController.php
```

```js
// assets/admin.js
```

Les fichiers CSS et Twig ne sont pas concernés par cette convention.

## Commandes de contrôle

Avant commit, lancer au minimum :

```bash
php bin/console cache:clear
php bin/console lint:twig templates
php bin/console lint:yaml config/packages
php bin/console doctrine:schema:validate
php bin/console debug:router
php bin/console debug:asset-map
```

Selon les changements, vérifier aussi :

```bash
php bin/console doctrine:migrations:status
php bin/console debug:container App\Service\Security\AuthRateLimiterService
php bin/console debug:container App\Repository\SaintRepository
php bin/console debug:container App\Service\Game\LocalizedSlugger
php bin/console debug:container App\Service\Front\CurrentBoxResolver
php bin/console debug:container App\Service\Front\BoxSaintManager
php bin/console debug:container App\Service\Front\BoxSaintEditor
php bin/console debug:container App\Form\Front\BoxSaintType
php bin/console debug:container App\Repository\BoxRepository
php bin/console debug:container App\Repository\BoxSaintRepository
```

Pour vérifier les routes du Sprint 2 :

```bash
php bin/console debug:router | findstr admin
php bin/console debug:router | findstr front_saint
```

Pour vérifier les routes du Sprint 3 :

```bash
php bin/console debug:router | findstr front_box
```

Pour vérifier les assets JS de box :

```bash
php bin/console debug:asset-map | findstr box-modal
php bin/console debug:asset-map | findstr box-progression
php bin/console debug:asset-map | findstr box-remove-confirm
```

Pour vérifier les fixtures :

```bash
php bin/console doctrine:fixtures:load --append
```

## Routes principales du Sprint 1

```text
/register
/register/success
/verify/email
/login
/logout
/account
/reset-password
/reset-password/check-email
/reset-password/reset/{token}
```

## Routes principales du Sprint 2

Admin :

```text
/admin
/admin/ranks
/admin/ranks/new
/admin/ranks/{id}/edit
/admin/roles
/admin/roles/new
/admin/roles/{id}/edit
/admin/sections
/admin/sections/new
/admin/sections/{id}/edit
/admin/saints
/admin/saints/new
/admin/saints/{id}/edit
```

Front :

```text
/{_locale}/saints
/{_locale}/saints/{slug}
```

Erreurs en dev :

```text
/_error/404
/_error/403
/_error/500
```

## Routes principales du Sprint 3

Box utilisateur :

```text
/{_locale}/box
/{_locale}/box/saints/add
/{_locale}/box/saints/{id}/edit
/{_locale}/box/saints/{id}/remove
```

## Git

Le Sprint 1 a été développé sur la branche :

```text
feature/sprint-1-auth-user-foundation
```

Le Sprint 2 a été développé sur la branche :

```text
feature/sprint-2-game-data-foundation
```

Le Sprint 3 est développé sur la branche :

```text
feature/sprint-3-user-box-foundation
```

Flux recommandé en cours de sprint :

```bash
git status
git add .
git commit -m "Message explicite"
```

Commit de documentation de fin de Sprint 3 :

```bash
git add README.md
git commit -m "Update README for sprint 3"
```

Puis, après validation globale du sprint :

```bash
git checkout dev
git pull
git merge feature/sprint-3-user-box-foundation
```

## Sprint 1 — État fonctionnel

Fonctionnalités couvertes :

- US-001 : entité User ;
- US-002 : inscription ;
- US-003 : confirmation email ;
- US-004 : login/logout ;
- US-005 : mot de passe oublié ;
- US-006 : préparation migration password v1 ;
- US-006.5 : login par username et email optionnel legacy ;
- US-007 : rate limits ;
- US-008 : premiers templates frontend ;
- US-009 : documentation du socle.

## Sprint 2 — État fonctionnel

Fonctionnalités couvertes :

- US-010 : enums métier Saint ;
- US-011 : référentiels Rank / Role / Section ;
- US-012 : entité Saint ;
- US-013 : traductions Saint et slugs URL localisés ;
- US-014 : repositories données jeu ;
- US-015 : layout admin custom ;
- US-016 : CRUD admin référentiels ;
- US-017 : CRUD admin Saints ;
- US-018 : fixtures données jeu ;
- US-019 : consultation front minimale des Saints publiés ;
- US-019.5 : pages d’erreur et factorisation CSS ;
- US-020 : documentation Sprint 2.

## Sprint 3 — État fonctionnel

Fonctionnalités couvertes :

- US-021 : entité `Box` et liaison avec `User` ;
- US-022 : entité `BoxSaint` et contrainte anti-doublon `box + saint` ;
- US-023 : résolution et création automatique de la box courante ;
- US-024 : page front `/box` avec affichage en grille ;
- US-025 : ajout d’un Saint publié à sa box ;
- US-026 : édition complète d’un Saint de box via modale ;
- US-027 : reset, maxxer et over maxxer sans sauvegarde immédiate ;
- US-028 : retrait d’un Saint de box avec confirmation ;
- US-029 : documentation Sprint 3.

## Validation globale de fin de Sprint 3

Avant commit ou merge, lancer :

```bash
git status
php bin/console cache:clear
php bin/console lint:twig templates
php bin/console lint:yaml config/packages
php bin/console doctrine:schema:validate
php bin/console doctrine:migrations:status
php bin/console debug:router
php bin/console debug:asset-map
```

Vérifier les services et repositories du Sprint 3 :

```bash
php bin/console debug:container App\Service\Front\CurrentBoxResolver
php bin/console debug:container App\Service\Front\BoxSaintManager
php bin/console debug:container App\Service\Front\BoxSaintEditor
php bin/console debug:container App\Form\Front\BoxSaintType
php bin/console debug:container App\Repository\BoxRepository
php bin/console debug:container App\Repository\BoxSaintRepository
```

Vérifier les routes principales :

```bash
php bin/console debug:router | findstr front_box
php bin/console debug:router | findstr front_saint
```

Vérifier les assets de box :

```bash
php bin/console debug:asset-map | findstr box
```

Vérifier les écrans front :

```text
/fr/box
/en/box
/fr/saints
/en/saints
```

Vérifier les comportements box :

```text
- un utilisateur connecté accède à /fr/box ;
- une box principale est créée automatiquement si absente ;
- la box vide affiche un état vide propre ;
- un Saint publié peut être ajouté ;
- un même Saint ne peut pas être ajouté deux fois ;
- le Saint ajouté disparaît de la liste d’ajout ;
- la modale Modifier s’ouvre et se ferme correctement ;
- les champs de progression sont sauvegardés après Enregistrer ;
- Reset modifie le formulaire sans sauvegarder immédiatement ;
- Maxxer passe le Saint au max standard 6 étoiles ;
- Over maxxer passe le Saint à 12 étoiles ;
- Annuler ne persiste pas les modifications faites en modale ;
- Retirer affiche une confirmation ;
- Annuler la confirmation ne supprime rien ;
- Confirmer le retrait supprime le BoxSaint ;
- le Saint retiré réapparaît dans la liste d’ajout ;
- un Saint retiré puis ajouté à nouveau repart aux valeurs initiales.
```

Si tout est OK :

```bash
git add README.md
git commit -m "Update README for sprint 3"
```

Puis merge vers `dev` :

```bash
git checkout dev
git pull
git merge feature/sprint-3-user-box-foundation
```
