manager-app/CLAUDE.md

105 lines
6.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# manager-app
Interface de gestion de contenu Flutter (web/desktop) pour configurer `tablet-app` et `mymuseum-visitapp`.
## Stack
- Flutter web (cible principale), support desktop partiel
- State management : **Provider** + `ChangeNotifier`
- Navigation : **GoRouter**
- Firebase Storage (upload de ressources)
## Structure
```
lib/
├── main.dart # Entry point, init Firebase, GoRouter, breakpoints responsive
├── app_context.dart # Provider root wrapping ManagerAppContext
├── client.dart # Wrapper exposant les 12+ facades API générées
├── constants.dart # Couleurs, types de sections, langues, types de ressources
├── Models/ # ManagerAppContext (état central), Session, Menu...
├── Helpers/ # FileHelper (localStorage session), PDFHelper
├── Components/ # 48+ widgets réutilisables (inputs, pickers, players...)
└── Screens/ # Écrans par domaine
├── Main/ # Dashboard principal avec menu latéral
├── Configurations/ # Builder de configuration par type de section
│ └── SubSection/ # Map, Menu, Slider, Quiz, Article, PDF, Video, Weather, Event, Parcours, Game, Agenda
├── Resources/ # CRUD ressources (Image, Video, Audio, PDF, JSON...)
├── Applications/ # Liaison config ↔ app device
├── Kiosk_devices/ # Gestion des devices
├── Users/ # Gestion des utilisateurs
├── ApiKeys/ # Gestion des clés API
├── Notifications/ # Push notifications
└── Statistics/ # Analytics visiteurs
```
## Client API généré (manager_api_new/)
**C'est ici que le client est généré.** Il est consommé via dépendance locale par `tablet-app` et `mymuseum-visitapp`.
- **Éditer manuellement** les fichiers de `manager_api_new/` en miroir des changements backend — **ne pas relancer le générateur OpenAPI**, il écraserait des patches locaux déjà accumulés dans ce client.
- 16 classes API : AuthenticationApi, ConfigurationApi, SectionApi, SectionMapApi, SectionEventApi, ResourceApi, DeviceApi, UserApi, StatsApi, AIApi, etc.
- 130+ DTOs générés dans `manager_api_new/lib/model/`
## Package layout partagé (myinfomate_layout/)
Package Dart pur (pas de dépendance Flutter) contenant `bentoLayout()` — le placement "bento" dense (chaque card occupe colSpan × lignes rowSpan sur une grille à N colonnes, même principe que `grid-auto-flow: dense` en CSS). Utilisé pour l'aperçu live de `app_configuration_link_screen.dart` ET par `mymuseum-visitapp` (même placement, pour que l'aperçu soit fidèle au rendu réel). Côté web (`visitapp-web`), le même rendu est obtenu nativement via CSS Grid (pas de portage JS nécessaire). Tests dans `myinfomate_layout/test/` (fixtures `bento_layout_cases.json`).
La taille d'une card = deux entiers `gridColSpan` / `gridRowSpan` (1 ou 2), portés par `AppConfigurationLinkDTO` (donc réglables indépendamment par plateforme). Dans l'aperçu, ils se règlent via un sélecteur de forme par ligne (`card_shape_selector.dart`) OU par glisser du coin d'une card (drag 2D) — les deux écrivent le même champ.
## État central (ManagerAppContext)
Contient : credentials, accessToken, instanceId, instanceDTO, référence au client API, configuration/section sélectionnée.
Accès via `context.read<AppContext>()` ou `context.watch<AppContext>()`.
## Flow d'authentification
1. `FileHelper().readSessionWeb()` → localStorage
2. Si pas de session → `/login`
3. POST `/api/Authentication/AuthenticateWithJson` → TokenDTO
4. Init `Client` avec le host backend
5. Fetch `InstanceDTO` → détermine les features (isMobile, isTablet, isWeb, isVR, isStatistic)
6. Redirect vers `/main/:view`
## Breakpoints responsive
- Mobile : 0550px
- Tablet : 550800px
- Desktop : 8011920px
- 4K : 1921px+
## Internationalisation — règle non négociable
Le manager est livré en **FR / EN / NL**. Toute chaîne visible par un utilisateur passe par
`AppLocalizations` : **aucun littéral de texte dans un widget**, jamais, y compris sur un écran
« qu'on traduira plus tard ». Un écran ajouté sans ses clés est un écran à refaire.
- Fichiers : `lib/l10n/app_fr.arb` (template, cf. `l10n.yaml`), `app_en.arb`, `app_nl.arb`.
**Les trois doivent avoir exactement le même jeu de clés.**
- Après toute modification d'un `.arb` : `flutter gen-l10n` (les `app_localizations*.dart`
générés sont versionnés).
- Lecture dans un widget : `AppLocalizations.of(context)!.maCle`, ou `final l = AppLocalizations.of(context)!;`
en tête de `build` quand il y en a plusieurs.
### Les pièges qui reviennent
- **Pas de contexte ?** Ne pas replier sur un littéral. Passer `AppLocalizations` en paramètre —
c'est ce que font `getSectionTypeName(l, type)`, `resourceTypeLabel(l, type)`,
`ProgressionMode.label(l)` et `AiTranslateException.localized(l)`.
- **Valeur par défaut d'un paramètre** (`this.labelHint = "…"`) : impossible à traduire, un const
n'a pas de contexte. Rendre le paramètre nullable et résoudre au `build`
(`widget.labelHint ?? l.selectLanguageHint`).
- **Listes/enums de libellés** construits en `initState` ou en constante de fichier : les construire
dans `build`, sinon la langue est figée au premier rendu.
- **Message d'erreur venant d'un service** : le service ne traduit pas. Il porte un code ou un
message backend, l'UI décide du texte.
- **Ce qui ne se traduit pas** : noms de marque (MyInfoMate, Unov), valeurs de données
(`"Point"`, `"Polygon"`, types d'API), messages de `print`/`StateError` jamais affichés,
et l'écran de réindexation du Guide IA (SuperAdmin uniquement, FR assumé — le commentaire
dans `guide_ia_screen.dart` le dit).
### Vérifier avant de pousser
```bash
flutter gen-l10n && flutter analyze --no-pub
# et relire le diff : tout `Text("…")`, `label:`, `hintText:`, `tooltip:`, `message:` littéral est un oubli
```
## Commandes utiles
```bash
flutter run -d chrome # Lancer en web
flutter build web # Build web
flutter pub run build_runner build # Regénérer code généré
```