# Architecture frontend — Projet Batch-cooking > Documentation de l'organisation d'`apps/web` : structure des dossiers, routing, > gestion des erreurs, et conventions de style (SCSS/theming). --- ## Structure des dossiers ``` apps/web/src/ ├── api/ │ └── client.ts # ApiClient — appels fetch vers l'API (voir error-handling.md) ├── services/ │ └── error-message.service.ts # ErrorMessageService — libellés d'erreur i18n ├── features/ │ └── auth/ # tout ce qui concerne l'authentification │ ├── AuthContext.tsx # état global (profil connecté, login/signup/logout) │ ├── RequireAuth.tsx # garde de route : redirige vers /login si non connecté │ ├── RedirectIfAuthenticated.tsx # garde de route inverse (pour /login, /signup) │ └── auth-form.scss # styles partagés par LoginPage et SignupPage ├── pages/ │ ├── LoginPage.tsx / .scss (via auth-form.scss, partagé) │ ├── SignupPage.tsx / .scss (via auth-form.scss, partagé) │ └── HomePage.tsx + HomePage.scss ├── styles/ │ ├── _theme.scss # tokens de design (couleurs, espacements, typographie) │ └── global.scss # reset minimal + import du theme — importé une seule fois (main.tsx) ├── lib/ │ └── zod-errors.ts # utilitaire : erreurs zod → { champ: message } ├── App.tsx # table de routes └── main.tsx # point d'entrée : providers (Router, AuthProvider) + import du CSS global ``` **Règle de placement des styles** : un style spécifique à un seul composant/page vit dans un fichier `.scss` au même niveau que ce composant (`HomePage.tsx` + `HomePage.scss`). Un style partagé par plusieurs composants d'une même feature vit dans le dossier de la feature (`features/auth/auth-form.scss`, utilisé par `LoginPage` et `SignupPage`). Seuls le reset et les tokens globaux vivent dans `styles/`. --- ## Routing et gardes d'authentification ```mermaid flowchart TB START(("Visite de l'app")) CHECK{"AuthProvider :
GET /auth/me"} START --> CHECK CHECK -->|"200 (session valide)"| AUTHED["user défini"] CHECK -->|"401 (pas de session)"| ANON["user = null"] AUTHED --> ROUTE_HOME["/ → HomePage"] AUTHED --> ROUTE_LOGIN_A["/login ou /signup"] ROUTE_LOGIN_A -->|"RedirectIfAuthenticated"| ROUTE_HOME ANON --> ROUTE_HOME_A["/"] ROUTE_HOME_A -->|"RequireAuth"| ROUTE_LOGIN["/login"] ANON --> ROUTE_LOGIN2["/login ou /signup → rendu normal"] ``` - `AuthContext` (`features/auth/AuthContext.tsx`) appelle `GET /auth/me` une seule fois au montage pour restaurer la session depuis le cookie httpOnly — c'est ce qui permet à un rechargement de page de garder l'utilisateur connecté. - `RequireAuth` et `RedirectIfAuthenticated` sont deux gardes de route (`react-router-dom`) qui lisent cet état : la première protège `/`, la seconde protège `/login` et `/signup` (redirige un utilisateur déjà connecté vers `/`). Les deux affichent `null` tant que la vérification initiale est en cours, pour éviter un flash de contenu suivi d'une redirection. --- ## Client API et gestion des erreurs Voir [error-handling.md](./error-handling.md) pour le détail du contrat d'erreurs partagé avec l'API. En résumé côté frontend : - `ApiClient` (`api/client.ts`) — classe avec instance unique exportée (`apiClient`), enveloppe `fetch` avec `credentials: "include"` (requis pour que le cookie de session httpOnly parte/revienne, l'API et le web étant sur des origines différentes). Lève `ApiError` (porteuse du `code` d'erreur) pour toute réponse non-2xx. - `ErrorMessageService` (`services/error-message.service.ts`) — traduit un `code` d'erreur en libellé affichable, avec support de locale (`fr` uniquement pour l'instant). --- ## SCSS et theming - **`sass`** (Dart Sass) est utilisé via le support natif de Vite — aucune config supplémentaire needed au-delà d'avoir le package installé (`vite.config.ts` fixe juste l'API moderne de Sass pour éviter un warning de dépréciation). - **`styles/_theme.scss`** — tokens de design exposés en **custom properties CSS** sur `:root` (`--color-primary`, `--space-md`, etc.), pas en simples variables SCSS : ça les rend disponibles au runtime, pas seulement à la compilation — ce qui permettrait un futur switch de thème (ex. mode sombre) en redéfinissant juste ces variables, sans reconstruire les feuilles de style. Toute nouvelle règle CSS doit référencer `var(--token)`, jamais une couleur/valeur en dur. - **`styles/global.scss`** — importé une seule fois, dans `main.tsx`. Contient uniquement le reset minimal et l'import du thème (`@use "./theme"`). Rien de spécifique à une page/un composant n'y va. - Les tokens étant des **custom properties CSS** (pas des variables Sass), ils sont disponibles globalement au runtime dès que `global.scss` a été chargé une fois — un fichier `.scss` de composant/page les consomme directement via `var(--token)`, sans avoir besoin de `@use` le partiel theme (ce serait un import sans effet, puisqu'aucun symbole Sass n'en est consommé). Chaque fichier documente en commentaire à quoi correspond chaque règle un peu non-triviale.