Cette page fixe la spec UI back-office du module Sanctions Screening : 5 écrans permettant à un compliance officer de superviser les sources de listes, configurer les politiques de matching, rechercher dans l’audit, et lever des alertes opérationnelles. Mockups détaillés dans le Workflow 12 de la maquette UI complète.
GET /v1/sanctions/etl/schedule → schedule courant ; GET /v1/sanctions/etl/runs?period=last_90d → historique des exécutions ; PUT /v1/sanctions/etl/schedule (admin + dual-control)
Modèle
`ScheduledJob {source, kind: full
States alternatives
aucun cron actif → empty state · 1 cron en retard de > 1h → cellule rouge cliquable vers détail incident · conflit fenêtre (2 fulls en parallèle dimanche 02:00) → bandeau warning
Transitions
clic cellule → modal détail run (logs + duration + entries delta) · clic “Modifier la planification” → écran dédié avec dual-control · clic “Voir historique” → table filtrable par source/résultat
Permissions
lecture pour tous compliance ; édition réservée DSI + L2 avec dual-control + audit
Données techniques
cron en format Quartz (6-field) car compatible Temporal CronWorkflow ; affichage UTC strict — la conversion locale est faite côté UI
A11y
calendrier doit avoir équivalent en <table> listing si screen-reader détecté ; pas d’info via couleur seule
GET /v1/sanctions/policies → policy active + drafts ; POST /v1/sanctions/policies/:version/draft → créer draft ; POST /v1/sanctions/policies/:version/publish → exige 2 sig Ed25519 (compliance + DSI)
Modèle
`SanctionsPolicy {version, status: DRAFT
Onglets
Sources : on/off par source + override cadence ; Thresholds : 5 sliders par typologie ; Re-ranker weights : 5 sliders (name/phon/dob/nat/alias) avec validation sum == 1.0 ; Feature flags : dj_enabled, cache_ttl_hours, topN, audit_export_enabled, etc.
States alternatives
policy active → modification → crée automatiquement draft v+1 · validation client-side : weights sum == 1.0, thresholds monotones (RCA-2 ≤ RCA-1 ≤ PEP ≤ direct) ; serveur re-vérifie · si refresh des sources non terminé pour la nouvelle version → warning “draft non testable maintenant”
Transitions
”Enregistrer draft” → POST policy DRAFT, retour écran avec “v1.5 draft prêt” · “Demander dual-control” → ouvre modal avec recherche second signataire (autocomplete agents L2 ou MLRO) → notification email/Kafka · à la 2e sig → publish atomique + Kafka event sanctions.policy.updated · audit trail signé conserve les 2 signatures
Calibration suggérée
calculée par metrics-svc sur les 90j d’historique d’audit signé : pour chaque threshold candidat ∈ [0.70, 0.99] step 0.01, recalcule FP/FN sur les cases ré-évalués manuellement par les agents (decision finale agent vs typologie automatique). Suggère le threshold qui minimise FP sous contrainte FN ≤ tenant_max_fn
Permissions
lecture pour tous compliance ; édition réservée DSI + L2 ; publication exige dual-control
i18n
sliders et labels FR/AR/EN ; valeurs numériques formatées localement (virgule vs point)
A11y
sliders avec inputs numériques accessibles ; raccourcis clavier Tab / Shift+Tab ; valeurs annoncées au screen-reader
GET /v1/sanctions/screenings?from=&to=&decision=&candidate=&page= (paginé, RLS appliqué) ; GET /v1/sanctions/screenings/:id/audit (event signé complet) ; POST /v1/sanctions/screenings/:id/replay (rejoue le re-ranker sur le snapshot listVersion) ; GET /v1/sanctions/screenings/:id/export.pdf
Chain integrity check
au chargement de la liste, audit-svc exécute verifyChain sur les events affichés ; en cas de rupture, bandeau rouge top “Tampering détecté à event #N” + escalation auto vers SRE et compliance officer
Rejeu
déclenche workflow Temporal : récupère snapshot OpenSearch listVersion depuis MinIO, restaure dans un index temporaire sanctions_replay_{screeningId}, re-tourne le re-ranker (version pinned), compare au verdict original. Affiche diff (devrait être 0 si déterministe). Si différent → audit critique escaladé
Export PDF
génère un PDF signé par tenant key contenant : query, listVersion, top-N candidates avec scores complets, audit chain depuis création tenant, rendu lisible par auditeur BCT non-technique
States alternatives
aucun résultat → empty state “Aucun screening sur cette période” · chain integrity rompue → bandeau critique + verrou édition policy · audit trop ancien (> 10 ans) → not-found 404 conformément à la rétention WORM
Transitions
clic ligne → expand détail · clic Rejouer → modal confirmation + workflow async + notification email à la fin · clic Export PDF → signed URL MinIO 30 min
Permissions
lecture pour compliance + auditeur (RLS tenant) ; rejeu réservé L2/MLRO ou auditeur ; export PDF idem
Performance
pagination cursor-based (pas offset) · filtrage côté serveur · cap 1000 lignes par requête · index Postgres (tenant_id, occurred_at desc) + (tenant_id, screening_id) · chain integrity check exécuté en streaming sur la page courante (~200 events) en p95 ≤ 100 ms
A11y
table avec <caption>, tri clavier, bouton “Skip to detail” si expand · annonce vocale du résultat de chain integrity
navigation sidebar → onglet “KPIs” — auto-refresh toutes les 60 s
API
GET /v1/sanctions/kpis?period=24h, GET /v1/sanctions/health/cluster, GET /v1/sanctions/alerts/active ; toutes proxy vers metrics-svc (Prometheus + custom recordings)
issues priorisées : critique (audit chain rupture, OpenSearch down) > élevé (source en error > 6h) > medium (source stale, heap > 85%) > info ; chaque alerte a un lien runbook on-call
States alternatives
tous métriques OK → “Aucune alerte actionnable” · monitoring service down → bandeau “metrics indisponibles, données stale” · tenant sans aucun screening → empty state “Aucun screening sur la période”
Transitions
clic carte KPI → drill-down vers la dimension (ex Latence → graphe détaillé time series) · clic alerte → écran 12.1 ou 12.4 ou runbook · clic période 24h → switch 1h / 24h / 7j / 30j
Permissions
lecture pour tous compliance + DSI + auditeur + SRE
Performance
données pré-aggregées Prometheus recording rules (5 min refresh) ; UI ne tape pas Prometheus en direct ; cache 30 s côté backend
A11y
sparklines avec aria-label qui annonce “tendance stable / hausse / baisse” + valeurs numériques min/max/dernier ; cartes avec role="status"