Aller au contenu

Sanctions admin UI — console compliance officer

Persona : compliance officer + DSI banque + auditeur interne. Acteur secondaire : on-call SRE VitaKYC.

Modules consommés : sanctions-svc (API admin), sanctions-etl-svc (status cron), audit-svc (search audit log signé), metrics-svc (Prometheus).

ADRs : ADR-006, ADR-030.

Pages liées : Sanctions screening — moteur, POC sanctions matcher, Runbook SRE sanctions.

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.


Acteurs autorisés par défaut (cf RBAC tenant) :

Rôle12.1 voir12.2 voir12.3 modifier12.4 lire audit12.4 rejeu12.5 dashboard
Compliance officer L1✅ son tenant
Compliance officer L2 / MLRO✅ avec dual-control✅ son tenant
DSI banque (admin)✅ avec dual-control✅ son tenant
Auditeur interne / BCT✅ son tenant
Agent KYC L1
SRE VitaKYC✅ tous tenants✅ tous✅ tous

┌──────────────────────────────────────────────────────────────────────────────────┐
│ Sanctions · Sources status tenant : TN-BANQUEX [↻] │
├──────────────────────────────────────────────────────────────────────────────────┤
│ Healthy : 6 / 7 · Stale : 1 · Error : 0 · Last full reindex : il y a 6 j │
├──────────────────────────────────────────────────────────────────────────────────┤
│ Source Status Last sync Entries listVersion Next │
│ OFAC SDN 🟢 healthy il y a 3 h 13 412 v2026-04-27.a +21h │
│ OFAC Consolidated 🟢 healthy il y a 3 h 7 209 v2026-04-27.a +21h │
│ UN Consolidated 🟢 healthy il y a 2 j 718 v2026-04-25 +5j │
│ EU CFSP 🟡 stale il y a 28 h 3 014 v2026-04-26 +20m │
│ UK OFSI 🟢 healthy il y a 4 h 7 142 v2026-04-27 +20h │
│ World Bank Debarred 🟢 healthy il y a 2 j 2 998 v2026-04-25 +28j │
│ OpenSanctions agg. 🟢 healthy il y a 3 h 52 187 v2026-04-27 +21h │
│ Dow Jones Watchlist 🔵 OFF — — — — │
│ │
│ ┌─ Détail EU CFSP (stale) ──────────────────────────────────────────────────┐ │
│ │ Last sync attempt 2026-04-26 06:00 UTC │ │
│ │ Last sync success 2026-04-26 06:00 UTC │ │
│ │ Status detail last attempt 2026-04-27 06:00 returned 503 │ │
│ │ Next attempt 2026-04-27 12:00 UTC (in 20 min) │ │
│ │ Snapshots MinIO v2026-04-26 → v2026-04-25 → v2026-04-24 (10 conservés)│ │
│ │ Actions [⚡ Force refresh now] [📥 Download last snapshot] │ │
│ └────────────────────────────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────────────────────────┘
AnnotationDétail
Triggernavigation depuis sidebar “Sanctions admin” → onglet “Sources” — poll toutes les 30 s
APIGET /v1/sanctions/lists → renvoie [{source, status, lastSyncAt, entries, listVersion, nextSyncAt, errorDetail?}] ; POST /v1/sanctions/lists/:source/refresh (force refresh) ; GET /v1/sanctions/lists/:source/snapshots (versions disponibles MinIO)
Statushealthy (last sync ≤ cadence × 1.2), stale (cadence × 1.2 < last sync ≤ cadence × 3), error (last sync > cadence × 3 OU dernière tentative en erreur), OFF (source désactivée par config tenant)
States alternativestoutes sources off → empty state “Aucune source active” + CTA “Activer OFAC SDN” · réseau coupé runtime → cache last-known + bandeau “données stale” · 1+ erreurs → bandeau rouge top “X sources en erreur”
Transitionsclic ligne source → drawer détail (snapshots + erreurs + actions) · clic Force refresh → modal confirmation + appel POST + toast résultat · clic Download snapshot → signed URL MinIO 10 min
Permissionslecture pour tous compliance + admin · Force refresh exige rôle ≥ L2 ; trace actor + reason dans audit
i18nclés sanctions.sources.* FR/AR/EN obligatoires ; statut couleur + icône reste universel
A11ygrille en <table> avec aria-rowindex, statut + icône + texte (pas couleur seule), drawer focus-trapped

┌──────────────────────────────────────────────────────────────────────────────────┐
│ Sanctions · Cron calendar (UTC) tenant : TN-BANQUEX │
├──────────────────────────────────────────────────────────────────────────────────┤
│ 00:00 04:00 08:00 12:00 16:00 20:00 │
│ Lundi ░░░░░ OFAC ░░░░░ EU. ░░░░░ ░░░░░ legend │
│ ░░░░░ delta ░░░░░ delta ░░░░░ ░░░░░ 🟦 full reindex │
│ Mardi ░░░░░ delta ░░░░░ delta ░░░░░ ░░░░░ 🟩 delta sync │
│ Mercredi ░░░░░ delta ░░░░░ delta ░░░░░ ░░░░░ 🟥 echec retry │
│ Jeudi ░░░░░ delta ░░░░░ delta ░░░░░ ░░░░░ ░ idle │
│ Vendredi ░░░░░ delta ░░░░░ delta ░░░░░ ░░░░░ │
│ Samedi ░░░░░ delta ░░░░░ delta ░░░░░ ░░░░░ │
│ Dimanche FULL delta ░░░░░ ░░░░░ ░░░░░ ░░░░░ │
│ 🟦OFAC │
│ UN+UK │
│ +OS │
├──────────────────────────────────────────────────────────────────────────────────┤
│ Prochain événement : OFAC delta dans 21 h 03 min │
│ Conflits détectés : aucun │
│ Charge max prédite : 18% CPU cluster (OK) │
│ │
│ [ Modifier la planification ] [ Voir l'historique des runs (90j) ] │
└──────────────────────────────────────────────────────────────────────────────────┘
AnnotationDétail
Triggernavigation depuis sidebar → onglet “Cron”
APIGET /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 alternativesaucun 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
Transitionsclic 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
Permissionslecture pour tous compliance ; édition réservée DSI + L2 avec dual-control + audit
Données techniquescron en format Quartz (6-field) car compatible Temporal CronWorkflow ; affichage UTC strict — la conversion locale est faite côté UI
A11ycalendrier doit avoir équivalent en <table> listing si screen-reader détecté ; pas d’info via couleur seule

4. Écran 12.3 — Configuration thresholds + weights + flags

Section intitulée « 4. Écran 12.3 — Configuration thresholds + weights + flags »
┌──────────────────────────────────────────────────────────────────────────────────┐
│ Sanctions · Configuration policy tenant : TN-BANQUEX │
│ policy v1.4 · Active depuis 12 jours │
├──────────────────────────────────────────────────────────────────────────────────┤
│ [ Sources ] [ Thresholds ] [ Re-ranker weights ] [ Feature flags ] │
├──────────────────────────────────────────────────────────────────────────────────┤
│ Onglet « Thresholds » (par typologie de hit) │
│ │
│ Direct sanctions (OFAC, UN, EU, UK) │
│ ├── ─────●────── 0.92 [info ⓘ : threshold strict, recommandé BCT] │
│ │
│ PEP (DJ + OpenSanctions PEP) │
│ ├── ──────●───── 0.85 │
│ │
│ RCA 1-hop (frère sanctionné, UBO direct) │
│ ├── ───────●──── 0.80 │
│ │
│ RCA 2-hop (UBO indirect via société) │
│ ├── ────────●─── 0.70 │
│ │
│ Adverse media (DJ Special Interest) │
│ ├── ───────●──── 0.75 [ ⚠ manuel only — toujours review L2 ] │
│ │
│ ┌─ Calibration suggérée (basée sur 90j de données) ──────────────────────┐ │
│ │ Threshold OFAC actuel 0.92 produit 4.2% FP, 0.3% FN │ │
│ │ Suggestion : 0.93 → 2.1% FP, 0.4% FN (BCT préfère minimiser FP) │ │
│ │ [Appliquer suggestion] [Voir analyse détaillée] │ │
│ └────────────────────────────────────────────────────────────────────────┘ │
│ │
│ [ Annuler ] [ Enregistrer comme draft v1.5 ] [ Demander dual-control ] │
└──────────────────────────────────────────────────────────────────────────────────┘
AnnotationDétail
Triggernavigation sidebar → onglet “Configuration”
APIGET /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
OngletsSources : 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 alternativespolicy 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éecalculé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
Permissionslecture pour tous compliance ; édition réservée DSI + L2 ; publication exige dual-control
i18nsliders et labels FR/AR/EN ; valeurs numériques formatées localement (virgule vs point)
A11ysliders avec inputs numériques accessibles ; raccourcis clavier Tab / Shift+Tab ; valeurs annoncées au screen-reader

┌──────────────────────────────────────────────────────────────────────────────────┐
│ Sanctions · Audit search tenant : TN-BANQUEX │
├──────────────────────────────────────────────────────────────────────────────────┤
│ Filtres │
│ Période : [2026-04-20] → [2026-04-27] │
│ Décision : [Toutes ▾] Candidate : [_______________] Screening ID : [_______] │
│ Agent : [Tous ▾] Source : [Tous ▾] listVersion : [Toutes ▾] │
│ [ Rechercher ] chain integrity verified : ✅ 1 247 / 1 247 events │
├──────────────────────────────────────────────────────────────────────────────────┤
│ Date Screening Query Décision Score Sig │
│ 2026-04-27 scr_8472 Mehdi Ben Ali MATCH_PEP 0.92 ✅ │
│ 2026-04-27 scr_8471 Sami Said CLEAR — ✅ │
│ 2026-04-27 scr_8470 Ali Al Makki MATCH_DIRECT_SANCTIONS 1.00 ✅ │
│ 2026-04-26 scr_8312 Layla Trabelsi MATCH_PEP 0.91 ✅ │
│ ... │
│ │
│ ┌─ Détail scr_8470 ──────────────────────────────────────────────────────────┐ │
│ │ Query Ali Hassan Al Makki, DOB 1968-03-15, NAT SY │ │
│ │ listVersion v2026-04-27.a (snapshot disponible MinIO) │ │
│ │ Reranker version 1.0.0 · weights {0.40 0.15 0.20 0.10 0.15} │ │
│ │ Top 3 candidates │ │
│ │ 1. Ali Hassan AL-MAKKI (ofac-001) score 1.00 → MATCH_DIRECT_SANCTIONS │ │
│ │ 2. Sami AL-MAKKI (rca-001) score 0.74 → CLEAR (RCA below 0.80) │ │
│ │ 3. ... │ │
│ │ Signature Ed25519 ✅ verified · previousEventHash sha256:abc... │ │
│ │ Actions [⚙ Rejouer ce screening] [📄 Export PDF audit] [🔗 Permalink] │ │
│ └─────────────────────────────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────────────────────────┘
AnnotationDétail
Triggernavigation sidebar → onglet “Audit” — query string permet deep-link (?screeningId=scr_8470)
APIGET /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 checkau 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
Rejeudé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 PDFgé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 alternativesaucun 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
Transitionsclic ligne → expand détail · clic Rejouer → modal confirmation + workflow async + notification email à la fin · clic Export PDF → signed URL MinIO 30 min
Permissionslecture pour compliance + auditeur (RLS tenant) ; rejeu réservé L2/MLRO ou auditeur ; export PDF idem
Performancepagination 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
A11ytable avec <caption>, tri clavier, bouton “Skip to detail” si expand · annonce vocale du résultat de chain integrity

┌──────────────────────────────────────────────────────────────────────────────────┐
│ Sanctions · KPIs et monitoring tenant : TN-BANQUEX · 24h ▾ │
├──────────────────────────────────────────────────────────────────────────────────┤
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ Screenings │ │ Latence p95 │ │ Faux positifs│ │ MATCH_DIRECT │ │
│ │ 8 412 │ │ 147 ms │ │ taux 4.1% │ │ 23 cases │ │
│ │ ↑ +12% j-1 │ │ target<200 │ │ cible <5% │ │ tous L2 │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ └──────────────┘ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ MATCH_PEP │ │ MATCH_RCA │ │ Adverse media│ │ Chain audit │ │
│ │ 148 │ │ 62 │ │ 89 (manuel)│ │ ✅ 100% │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ └──────────────┘ │
├──────────────────────────────────────────────────────────────────────────────────┤
│ Latence pipeline (p50 / p95 / p99) · 24h │
│ broad search OS ▁▂▁▂▃▂▁▂▂▁▂▂▁▂▁▂▂▃▂▂▁ 17ms / 28ms / 41ms │
│ re-ranker ▁▂▁▂▂▁▂▁▂▂▂▁▂▁▂▂▁▂▂▁▂ 31ms / 48ms / 67ms │
│ pipeline total ▂▃▂▃▄▃▂▃▃▂▃▃▂▃▂▃▃▄▃▃▂ 82ms / 147ms / 198ms │
│ │
│ Cluster OpenSearch │
│ Heap utilisée 68% / 85% threshold Index sanctions_TN-BANQUEX 2.1 GB │
│ Query rate 142 req/s Documents 35 487 │
│ Indexation rate 0 docs/s (idle) Shards 1 primary 0 replicas │
│ │
│ Alertes actionnables │
│ • 1 source en stale : EU CFSP (28 h depuis dernier sync, attempt 503) │
│ [⚡ Force refresh] [🔍 Voir runbook on-call] │
│ • Heap OS proche threshold : 68% (cible <85%) → no action │
│ • OK : pas de tampering détecté audit chain │
└──────────────────────────────────────────────────────────────────────────────────┘
AnnotationDétail
Triggernavigation sidebar → onglet “KPIs” — auto-refresh toutes les 60 s
APIGET /v1/sanctions/kpis?period=24h, GET /v1/sanctions/health/cluster, GET /v1/sanctions/alerts/active ; toutes proxy vers metrics-svc (Prometheus + custom recordings)
Métriques principalessanctions_screening_total, `sanctions_screening_duration_seconds{phase=broad
Alertes actionnablesissues 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 alternativestous 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”
Transitionsclic 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
Permissionslecture pour tous compliance + DSI + auditeur + SRE
Performancedonnées pré-aggregées Prometheus recording rules (5 min refresh) ; UI ne tape pas Prometheus en direct ; cache 30 s côté backend
A11ysparklines avec aria-label qui annonce “tendance stable / hausse / baisse” + valeurs numériques min/max/dernier ; cartes avec role="status"

ÉvénementChannelDestinatairesLatence
Source en error > 6 hemail + KafkaDSI + compliance + SRE≤ 5 min
chain integrity rompueemail URGENT + Slack/Teams + KafkaDSI + compliance + MLRO + SRE VitaKYC≤ 1 min
Policy publiée (dual-control)emailtous compliance + auditeur≤ 1 min
OpenSearch heap > 85 % 5 minemail + SlackSRE≤ 5 min
Snapshot MinIO échecemailSRE≤ 5 min
Tentative force refreshaudit log + Kafkalogged≤ 1 s

  • Toutes les chaînes UI dans des clés i18n sanctions.admin.* FR/AR/EN obligatoires (cf ADR-009)
  • Dates et heures affichées au timezone tenant (configurable, défaut UTC pour ops, locale tenant pour compliance)
  • Nombres formatés selon locale (séparateur décimal virgule en FR/AR, point en EN)
  • Sliders et champs numériques acceptent les deux formats en saisie

  • Tab order = ordre DOM ; focus ring custom 2 px couleur d’accent
  • aria-labelledby / aria-describedby calculés automatiquement
  • Statuts (healthy/stale/error) jamais via couleur seule — toujours icône + texte
  • Tableaux avec <caption>, aria-rowindex, aria-colindex
  • Sliders avec inputs numériques accessibles + raccourcis clavier ( / step 0.01, Page Up/Down step 0.10)
  • Écrans testés NVDA Windows + VoiceOver iOS/macOS + TalkBack Android
  • Mode haut-contraste supporté (palette dérivée des design tokens VitaKYC)

MetricCible MVPCible V2
First contentful paint p95≤ 1.5 s≤ 800 ms
Time to interactive p95≤ 2.5 s≤ 1.5 s
Auto-refresh 12.5 (60 s poll)≤ 200 ms p95≤ 100 ms
Recherche audit (12.4, 1000 résultats)≤ 1 s p95≤ 500 ms
Rejeu screening (12.4)≤ 30 s p95≤ 10 s
Export PDF audit≤ 5 s p95≤ 2 s

ItemMVP (V0)V2 (S+12)
Cron calendar éditionlecture seuleédition GUI complète avec dual-control
Calibration suggéréecalcul on-demandcontinuous (background daily)
Bulk audit exportpar screeningbulk avec selection range
Replay screeningunitairebulk replay sur listVersion donnée
Mobile back-officenoniOS/Android lecture seule (KPIs)
AI assistnonsuggestions de threshold + détection drift FP/FN automatique
Notificationsemail + Kafka+ SMS + Teams + Slack

  • 5 écrans Workflow 12 livrés en Figma haute-fidélité + dev React/Web Components
  • API REST admin documentées OpenAPI + contract tests Pact
  • Auto-refresh 60 s opérationnel (12.5)
  • Chain integrity check exécuté à chaque ouverture 12.4 (≤ 100 ms p95 sur 200 events)
  • Rejeu screening fonctionnel sur snapshot MinIO + comparaison verdict
  • Dual-control publication policy enforced (impossible sans 2 sig)
  • Calibration suggérée calculée + affichée sur 12.3
  • Notifications email + Kafka pour les 6 événements transversaux
  • WCAG 2.1 AA testé sur les 5 écrans
  • RTL arabe testé
  • Pilote tenant TN-BANQUEX : 1 compliance officer + 1 DSI utilisent l’UI réelle pendant 2 semaines, retour formalisé
  • Runbook on-call SRE (cf Runbook sanctions monitoring)


Document de spec UI Sanctions admin — version 1.0 (2026-04-27).