Commit graph

3 commits

Author SHA1 Message Date
f14060720b feat(admin): refonte du panneau par intention, vue Localisations, tests e2e
Some checks are pending
CI / javascript (push) Waiting to run
CI / python (push) Waiting to run
CI / mutation (push) Waiting to run
Le panneau était découpé par table SQL, pas par question que se pose l'admin.
Conséquence : « je constate ici, j'agis dans un autre onglet », et aucun moyen
de voir ce qui coince réellement.

Redécoupage — un onglet = une question
- Pilotage      : est-ce que ça tourne ? (fusionne l'ancien « Actions »)
- Groupes       : trouver et corriger
- Localisations : qu'est-ce qui coince dans le géocodage ?  ← NOUVEAU
- Journal       : que s'est-il passé ?
- LLM & coûts   : combien ça coûte ?

Pilotage : chaque chiffre problématique porte son action
- Bandeau de santé (groupes, géocodage, file, bloqués, coût) coloré par état
- Alertes actionnables : « 12 localisations en erreur » + [Examiner] +
  [Tout remettre en file], au lieu d'un mur de boutons dans un autre onglet
- Déclencheurs de traitements inline, opérations destructives repliées
- L'ancien bloc « Éléments de genre » (des centaines de mots-clés jamais
  consultés) est retiré

Localisations : la vue qui manquait totalement
L'admin ne disposait que d'actions EN MASSE sur band_locations et d'aucun moyen
de voir CE qui échouait. Débloquer un seul lieu supposait de relancer des
milliers d'appels Geoapify/Groq facturés.
- GET  /admin/api/locations          liste filtrable (statut, lieu, groupe, pays)
- POST /admin/api/locations/:id/requeue     relance UNE ligne
- PATCH /admin/api/locations/:id            saisie manuelle des coordonnées
- Diagnostic lisible sans clic : lieu brut, statut, essais, erreur réelle

Groupes : recherche d'abord
Une barre de recherche et des filtres rapides en chips remplacent les 8 champs
texte ; les filtres avancés sont repliés.

Accessibilité
- Lignes de tableau activables au clavier (role=button, tabindex, Entrée)
- Modales : Échap ferme, focus piégé, focus rendu à l'élément d'origine
- Contraste : --err (#c61a1a) échouait WCAG AA en texte sur fond sombre (3,4:1).
  Les messages d'erreur étaient difficiles à lire. Ajout de --err-text /
  --ok-text (~6,5:1) pour les usages en couleur de texte.
  Détecté par les nouveaux tests axe sur les vues rendues.
- Statuts affichés en français au lieu des valeurs brutes de la base

Tests
- 36 tests API sur les trois nouveaux endpoints (allowlist de statuts,
  bornes des coordonnées, audit, 404)
- 53 parcours Playwright sur la VRAIE app Fastify + faux pool, dans une
  topologie identique à la production (statique servi + /admin/* proxifié)
- Tests axe sur les vues RENDUES : le test jsdom existant ne voyait que la
  coquille vide du dashboard, tout étant construit en JavaScript
- e2e branché sur le hook pre-push, pas sur `check` : la boucle de
  développement reste à 6 s, le push coûte 28 s

Correction trouvée par les tests
Le routeur ne séparait pas la query string du nom de vue :
« #/locations?status=error » ne correspondait à aucun alias et retombait sur
Pilotage — les liens des alertes ne fonctionnaient pas.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-18 15:05:29 +02:00
68e483762e feat: flag-icons dropdown + admin live monitor
- Sélecteur de langue : dropdown custom avec flag-icons CDN (fi fi-xx), fermeture click-outside, aria-expanded
- Admin Monitor : nouvelle vue live avec status temps réel (crawl runs, géocodeur, jobs en attente)
- Log stream incrémental : fetch uniquement les nouveaux logs via min_id, buffer 500 entrées, filtre level + recherche texte client-side, flash animation sur nouvelles lignes
- Boutons inline Annuler pour runs actifs et jobs en attente
- API : GET /admin/api/live (agrégé), POST crawl-runs/:id/cancel, POST job-triggers/:id/cancel, param min_id sur GET /logs
- Refresh configurable 3/5/10/30s, pause/reprendre, vider le buffer

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-01 21:02:13 +02:00
a7d7bc94de feat(admin): dashboard admin complet (auth forte, API, monitoring)
Nouveau service apps/admin (admin.metalfrom.eu / admin.dev.metalfrom.eu) :
- Frontend statique vanilla JS/CSS reprenant le design system du site
  (login, dashboard stats, table bands éditable, queue d'enrichissement,
  historique crawl_run, logs live, checkpoints, journal d'audit)
- nginx reverse-proxy /admin/api/* et /admin/auth/* vers le service api
  interne (same-origin côté navigateur, pas de CORS cross-site nécessaire
  pour le cookie de session)

apps/api :
- Nouvelle auth dédiée au dashboard, séparée du token BM_IMPORT_TOKEN
  existant : login bcrypt + session JWT en cookie httpOnly/secure/
  sameSite=strict, rate-limit + lockout après 5 échecs/15min, seeding
  du compte admin via env vars (jamais de mot de passe en clair en DB
  ou en git)
- Routes /admin/api/* : stats, queue (breakdown priorité identique au
  crawler Python), bands (recherche/tri/pagination/édition + audit log),
  crawl-runs, crawl-checkpoints, logs, audit-log
- trustProxy activé (Traefik + nginx en amont)

apps/crawler :
- log_event() écrit dans la nouvelle table crawl_log (run start/finish/
  erreurs) pour que le dashboard affiche les logs sans exposer le socket
  Docker (choix délibéré : pas de docker.sock monté, accès DB only)

migration 006_admin_dashboard.sql : admin_users, admin_login_attempts,
admin_audit_log, crawl_log

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-30 22:15:13 +02:00