diff --git a/docs/architecture/30-frontend.md b/docs/architecture/30-frontend.md index 14a7012..5109a61 100644 --- a/docs/architecture/30-frontend.md +++ b/docs/architecture/30-frontend.md @@ -4,39 +4,47 @@ Application Angular 22, 100 % standalone, testée avec Vitest. Source dans `apps ## État actuel -Statut : `En cours`. L'application sert une première page métier, le tableau de bord, alimentée -par des fixtures : les endpoints qu'elle appelle n'existent pas encore côté API. +Statut : `En cours`. L'application sert le tableau de bord, la liste et le détail des sites, la +supervision des capteurs (admin) et le flux des alertes actives, tous branchés sur l'API réelle. Ce qui est en place : - Bootstrap par `bootstrapApplication(App, appConfig)`, **aucun `NgModule`** dans le dépôt. - `app.config.ts` fournit `provideBrowserGlobalErrorListeners()`, `provideRouter(routes)` et - `provideHttpClient(withInterceptors([mockApiInterceptor]))`. -- Une route `/dashboard` en composant différé, et une redirection depuis la racine. -- `core/services` porte `StatsService`, `AlertsService`, `PredictionsService`, `SitesService` et - `AuthService`, `core/interceptors` l'intercepteur de fixtures et l'intercepteur d'authentification - (jeton porteur, rafraîchissement sur 401), `core/guards` la garde de route `authGuard`, - `features/dashboard` la page principale, `shared/components` la jauge de consommation et le - graphique de charge par site, tous deux construits sur Chart.js. + `provideHttpClient(withInterceptors([authInterceptor, mockApiInterceptor]))`. +- Des routes en composants différés (`/dashboard`, `/sites`, `/sites/:siteId`, + `/monitoring/sensors` réservée au rôle `admin`) et une redirection depuis la racine. +- `core/services` porte un service HTTP par domaine (`StatsService`, `AlertsService` avec ses + filtres `site_id` et `severity`, `PredictionsService`, `SitesService`, `ReadingsService`, + `SensorsService`, `AuthService`), `core/interceptors` l'intercepteur de fixtures et l'intercepteur + d'authentification (jeton porteur, rafraîchissement sur 401), `core/guards` la garde `authGuard`. +- `features/` porte une page par domaine. `shared/components` porte la jauge de consommation et + les graphiques Chart.js, le widget `app-alert-feed` (flux d'alertes filtrable par site et + sévérité, rafraîchi toutes les 60 s, première vue de l'application avec des états chargement / + vide / indisponible) et, dans `shared/models`, des types alignés sur les schémas Pydantic du + backend, plus les tables de présentation partagées (`alert-presentation.ts` : ton, libellé et + unité par sévérité, type et métrique). - Une authentification complète côté interface : connexion, mot de passe oublié/réinitialisation, - changement de mot de passe, garde de route sur `/dashboard` et `/sites`. Détail : + changement de mot de passe, garde de route sur toute la zone authentifiée. Détail : [31-contrat-authentification.md](31-contrat-authentification.md). - Un système de design partagé (`shared/components/ui/` : `ev-button`, `ev-card`, `ev-alert`, - `ev-badge`, `ev-brand`, tokens CSS dans `styles/_tokens.scss`) que toute nouvelle page doit - réutiliser plutôt que redéfinir ses propres styles. Détail : + `ev-badge`, `ev-brand`, `ev-icon`, tokens CSS dans `styles/_tokens.scss`, classes globales de + formulaire, de navigation et de tableau) que toute nouvelle page doit réutiliser plutôt que + redéfinir ses propres styles. Détail : [32-design-systeme-frontend.md](32-design-systeme-frontend.md). - L'état vit dans des signaux, sans bibliothèque dédiée. +- TypeScript en `"strict": true` ; `strictTemplates` n'est pas encore activé. - Vitest via le builder `@angular/build:unit-test`, couverture activée. - Prettier configuré, parser `angular` pour les gabarits HTML. Ce qui n'existe pas encore : -- **`stats`/`alerts` restent sur fixtures.** `GET /api/v1/stats/summary` et `GET /api/v1/alerts` - sont servis par l'intercepteur de fixtures ; l'API expose bien ces routes désormais, mais rien - ne bascule `useMockFixtures` à `false` en développement pour les consommer réellement. - `GET /api/v1/predictions` fait exception : jamais mocké, branché sur l'API réelle depuis cette - PR (voir plus bas). -- Aucun état de chargement : tant que la première réponse n'est pas arrivée, la page reste vide. +- **Le mode fixtures est inactif.** `useMockFixtures` vaut `false` dans `environment.ts` comme dans + `environment.development.ts` : `mockApiInterceptor` ne sert `/stats/summary` et `/alerts` que + dans son propre spec. En développement, toutes les pages exigent un backend joignable et un jeton + valide. +- Un état de chargement généralisé : seul `app-alert-feed` en a un, les autres pages restent vides + tant que la première réponse n'est pas arrivée. - Aucun lint : ESLint n'est pas installé. ## Arborescence @@ -87,11 +95,11 @@ sequenceDiagram ``` `mockApiInterceptor` n'intercepte que `/stats/summary` et `/alerts`, et seulement si -`environment.useMockFixtures` est vrai. Le drapeau est à `true` en développement, à `false` en -production : toute autre requête, et toutes les requêtes en production, suivent le chemin réel. -`/predictions` est volontairement exclu de cette liste (contrairement à `stats`/`alerts`) : il -suit toujours le chemin réel, comme `/auth/*` - en développement, ça veut dire qu'un jeton valide -et un backend joignable sont nécessaires pour que la section prévisions du dashboard s'affiche. +`environment.useMockFixtures` est vrai. Le drapeau vaut `false` dans les deux fichiers +d'environnement : en pratique toutes les requêtes suivent le chemin réel et l'intercepteur n'est +exercé que par son spec. `/predictions` et `/auth/*` ne sont de toute façon jamais mockés. En +développement, un jeton valide et un backend joignable sont donc nécessaires pour que le tableau de +bord s'affiche. En développement, `proxy.conf.json` redirige tout `/api` vers `http://localhost:8000`. C'est ce qui évite le CORS sur le poste, et c'est pourquoi `environment.development.ts` se contente d'un diff --git a/docs/architecture/32-design-systeme-frontend.md b/docs/architecture/32-design-systeme-frontend.md index 2d015bc..790c60f 100644 --- a/docs/architecture/32-design-systeme-frontend.md +++ b/docs/architecture/32-design-systeme-frontend.md @@ -20,8 +20,9 @@ seule fois dans `src/styles.scss`. Disponibles partout sans import supplémentai | `--color-success` / `-bg`, `--color-warning` / `-bg` / `-text`, `--color-danger` / `-hover` / `-bg` / `-border`, `--color-critical` | États sémantiques (alertes, badges) | | `--color-text-inverse` | Texte sur fond coloré plein (boutons/badges) | | `--font-family` | Police unique de l'application | +| `--font-size-xs` à `--font-size-2xl` | Échelle typographique (0.75rem à 2.25rem) : libellés, corps, titres, grands nombres | | `--radius-sm`, `--radius-md`, `--radius-pill` | Rayons de bordure (input/bouton, carte, pastille) | -| `--shadow-card` | Ombre portée des cartes | +| `--shadow-card`, `--shadow-card-hover` | Ombre portée des cartes, au repos et au survol | | `--space-1` à `--space-5` | Échelle d'espacement (0.35rem à 2.5rem) | Les classes de formulaire partagées (`.form-label`, `.form-input`, `.form-select`, `.form-hint`) @@ -84,6 +85,23 @@ dans le tableau `imports` du composant qui l'utilise. ```html ``` +- **``** (`icon/`) : `name` (obligatoire : `spike` / `threshold` / `anomaly` / `outage` / + `sensor`, les types d'alerte du contrat) et `label` (facultatif). SVG inline en trait sur + `currentColor`, dimensionné par `font-size` comme `ev-brand`. Sans `label` l'icône est décorative + (`aria-hidden`) ; avec, elle porte `role="img"` et `aria-label`. Pas de bibliothèque d'icônes : la + CSP du reverse proxy (`script-src 'self'`) interdit les scripts tiers, pas le SVG inline. + ```html + + ``` +- **``** (`shared/components/alert-feed/`) : widget métier plutôt qu'atome du kit, + mais réutilisable tel quel. Input `siteId` (facultatif : fige le site et masque son filtre). Il + porte ses filtres (`.form-select`), ses états et son rafraîchissement ; le parent ne fait que le + poser dans une section. + +Les classes de tableau partagées sont dans `apps/frontend/src/styles/_tables.scss`, importées +globalement : `.ev-table-card` sur la `` qui enveloppe un tableau (padding nul), +`.ev-table` sur le ``, `.ev-table__number` pour une cellule numérique en chiffres +tabulaires, `.ev-table__muted` pour une cellule sans valeur. ## Logo