Écran « Activité » sur GET /api/Audit, réservé au SuperAdmin comme la policy
de l'endpoint (menuId 13, conditionné à role.value == 0). Filtres instance,
type d'entité, utilisateur et plage de dates, pagination 50, clic sur une
ligne pour le détail avant/après en table plutôt que le JSON brut. Les ids
d'instance et d'utilisateur sont résolus en noms, un id absent de l'annuaire
restant affiché tel quel : le journal doit rester lisible après la
suppression de ce qu'il décrit.
manager_api_new n'est pas touché. L'écran passe par un http.get direct au
Bearer, comme _loadKnowledge / _loadInsights / _reindex du Guide IA : une
lecture seule ne justifie pas d'étendre un client qui s'édite à la main, et
le déclencheur de génération n'existe plus depuis le lot A.
Côté utilisateurs, compteur « X / 5 » et bouton d'ajout désactivé au
plafond. Le SuperAdmin en est exclu : son GET /api/User renvoie toutes les
instances, compter cette liste contre un plafond par instance n'aurait
aucun sens. Le masquage du rôle SuperAdmin pour un InstanceAdmin, resté en
question dans todo-features.md, était déjà fait — _allowedRoles filtre sur
r >= callerRole.
Trois pièges relevés en câblant :
- AuditController renvoie les entités brutes, pas un DTO — les champs sont
ceux d'AuditLog en camelCase.
- invokeAPI ne lève pas sur un code d'erreur et son résultat était ignoré
dans users_screen : un e-mail déjà utilisé (409) ou un rôle refusé (403)
ne produisait aucun message. Le statut est désormais testé et le corps
affiché, ce qui rendra visible sans retouche le futur 422 du plafond.
- DropdownButtonFormField ne relit pas initialValue sur reconstruction
(FormField.didUpdateWidget ne traite que forceErrorText) : « Réinitialiser
les filtres » vidait la requête sans vider l'affichage. Remplacé par un
DropdownButton piloté.
40 clés i18n FR/EN/NL, flutter gen-l10n relancé. flutter analyze propre sur
les dossiers travaillés, flutter build web vert.
Deux dettes serveur restent ouvertes, hors périmètre de ce commit : le
plafond de 5 n'est pas appliqué par UserController (ce qui est livré ici est
un garde-fou d'interface, un POST direct passe toujours), et aucune section
n'est journalisée — AuditedTypes.Contains exige l'égalité exacte alors que
Section est abstraite. Détail dans DOCS/todo-features.md et v1-plan.md lot F.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Socle visuel (constants.dart)
- 11 rôles typographiques, 8 espacements, 5 rayons, paddings de carte et de page,
extraits du CSS des maquettes validées (DOCS/claude design/).
- Les couleurs restent celles de l'app : un écran neuf se fond dans manager-app,
il n'y ouvre pas une seconde palette. Seules les valeurs sans équivalent
existant sont reprises — remplissages discrets, bordures, gris atténué, ambre.
- Mesuré avant : 11 tailles de police différentes dans lib/Components/, de 9 à 25 px.
Écran Guide IA
- Coquille à deux onglets : Configuration / Ce que demandent vos visiteurs.
- Aperçu de conversation branché sur le vrai POST /api/AI/chat, pas une simulation.
- Carte « Ce que connaît votre guide » sur GET /api/Ai/knowledge/{id} : mesuré sur
l'index vectoriel, pas sur les tables de contenu — une section désactivée en est
purgée. Les « points d'intérêt » de la maquette deviennent « morceaux de contenu » :
les points d'une carte sont indexés dans le texte de leur SectionMap.
- Onglet des questions visiteurs alimenté par GET /api/Ai/insights/{id}. Une carte
sans données se masque au lieu d'afficher un cadre creux.
Client API
- AIApi était dans le client généré mais exposé nulle part dans client.dart, où
les 18 autres façades le sont. Câblé.
34 clés i18n FR/EN/NL. flutter analyze propre, flutter build web ✅.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>