# Prompt p17 — Auditeur & Logs (web)
*Contextes requis : ctx-global.md + ctx-web-nextjs.md + ctx-laravel-bff.md*

---

## Profil & Accès
- **Rôle** : AUD (Auditeur)
- **Nombre d'utilisateurs** : 2 (maximum absolu — rejeté si 3ème connexion simultanée)
- **Accès** : LECTURE SEULE ABSOLUE sur tous les modules
- **Session** : 8h, OTP à la connexion
- **Méta-audit** : toutes les consultations de l'Auditeur sont tracées dans `flw_audit_consultations`

---

## Fichiers à créer

```
app/(erp)/audit/page.tsx
app/(erp)/audit/journal/page.tsx
app/(erp)/audit/anomalies/page.tsx
app/(erp)/audit/ecarts/page.tsx
app/(erp)/audit/fraudes/page.tsx
app/(erp)/audit/exports/page.tsx
components/audit/AuditDashboard.tsx
components/audit/JournalAuditTable.tsx
components/audit/AnomaliesList.tsx
components/audit/EcartsIotVsManuel.tsx
components/audit/SuspicionsFraude.tsx
components/audit/QrInvalidesLog.tsx
components/audit/ExportAudit.tsx
components/audit/ReadOnlyBadge.tsx
hooks/useAudit.ts
```

---

## Spec UX condensée

```
┌─────────────────────────────────────────────────────────────────────┐
│ FLOWUP ERP          Audit & Conformité      [AUD]  🔒 LECTURE SEULE │
│ Session: 7h43 restantes  · Vos consultations sont tracées           │
├─────────────────────────────────────────────────────────────────────┤
│ [Tableau de bord][Journal Audit][Anomalies][Écarts IoT][Fraudes]    │
│ [Exports certifiés]                                                 │
├─────────────────────────────────────────────────────────────────────┤
│ TABLEAU DE BORD AUDIT — 13 mai 2026                                  │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌────────────┐  │
│ │ ANOMALIES    │ │ ÉCARTS STOCK │ │ QR INVALIDES │ │SUSPICIONS  │  │
│ │   7 actives  │ │ 3 stations   │ │  12 ce mois  │ │ FRAUDE : 1 │  │
│ │   ▲ vs hier  │ │ >1% attendu  │ │              │ │ ⚠ URGENT  │  │
│ └──────────────┘ └──────────────┘ └──────────────┘ └────────────┘  │
├─────────────────────────────────────────────────────────────────────┤
│ JOURNAL D'AUDIT (append-only — jamais modifiable)                   │
│ ┌──────────────────────────────────────────────────────────────┐    │
│ │ 2026-05-13 10:42 │ CEO        │ CONSULTE   │ Dashboard KPIs │    │
│ │ 2026-05-13 10:41 │ TRE Bah    │ CRÉE       │ Paiement 480M  │    │
│ │ 2026-05-13 10:40 │ CFO Diallo │ VALIDE     │ Paiement 89M   │    │
│ │ 2026-05-13 10:38 │ AUD [vous] │ CONSULTE   │ Journal audit  │    │
│ │ 2026-05-13 10:35 │ GCG Bah    │ DÉPOSE     │ Contrat v3     │    │
│ │ [Filtres: Acteur ▾][Module ▾][Action ▾][Période ▾]           │    │
│ └──────────────────────────────────────────────────────────────┘    │
├─────────────────────────────────────────────────────────────────────┤
│ ÉCARTS IoT vs JAUGEAGE MANUEL                                       │
│ Station Ratoma   : IoT 23 847 L │ Manuel 23 500 L │ Écart: 347 L ⚠ │
│ Station Matoto   : IoT  8 920 L │ Manuel  8 950 L │ Écart:  30 L ✓ │
│ Station Kaloum   : IoT 23 400 L │ Manuel 23 410 L │ Écart:  10 L ✓ │
└─────────────────────────────────────────────────────────────────────┘
```

### Méta-audit (l'Auditeur est audité)
- Chaque page consultée par l'AUD est enregistrée dans `flw_audit_consultations`
- Colonnes : `id` INT, `auditeur_id` INT, `module` VARCHAR, `action` "CONSULTE", `detail` VARCHAR, `ip` VARCHAR, `created_at` DATETIME
- Cette table est append-only — aucun DELETE/UPDATE n'est jamais possible dessus

### Journal Audit (append-only)
- Toutes les actions système de tous les utilisateurs : créations, modifications, validations, connexions, exports, suppressions (soft)
- Non modifiable : aucune interface de modification, pas de bouton "Supprimer"
- Horodatage UTC, acteur identifié, IP, action, module, entité affectée

### Contrôle écarts IoT vs Jaugeage manuel
- Comparaison : niveau IoT (automatique) vs jaugeage physique (saisi par Gérant)
- Seuil alerte : >0,5% d'écart
- Seuil suspect : >1% d'écart (signalement automatique dans "Suspicions fraude")

---

## Endpoints BFF

```
GET /api/audit/anomalies
  Query : ?gravite=critique|alerte|info&statut=active|resolue&page={n}
  Réponse : {
    data: [{
      id: INT,
      type: "ECART_STOCK"|"QR_INVALIDE"|"CONNEXION_SUSPECTE"|"PAIEMENT_ANORMAL",
      description: "Écart stock >1% Station Ratoma — Gasoil",
      gravite: "critique"|"alerte"|"info",
      station_nom: "Ratoma"|null,
      created_at: "...",
      statut: "active"|"resolue"
    }],
    totaux: { critiques: INT, alertes: INT, infos: INT }
  }

GET /api/audit/journal
  Query : ?acteur_id={id}&module={m}&action={a}&debut={date}&fin={date}&page={n}
  Réponse : {
    data: [{
      id: INT,
      acteur_nom: "CFO Diallo",
      acteur_role: "CFO",
      module: "Paiements",
      action: "VALIDE"|"CRÉE"|"MODIFIE"|"CONSULTE"|"SUPPRIME_SOFT"|"CONNECTE"|"EXPORTE",
      detail: "Paiement PAY-2026-0147 — 480M GNF",
      ip: "192.168.1.10",
      created_at: "2026-05-13T10:40:00Z"
    }],
    meta: { total: INT }
  }

GET /api/audit/ecarts
  Query : ?station_id={id}&debut={date}&fin={date}
  Réponse : [{
    station_id: INT,
    station_nom: "Ratoma",
    produit: "Gasoil",
    date: "2026-05-13",
    niveau_iot: "23847",         // VARCHAR (litres)
    niveau_manuel: "23500",      // VARCHAR
    ecart_litres: "347",         // VARCHAR
    ecart_pct: "1.45",           // VARCHAR
    alerte: true,
    suspect: true
  }]

GET /api/audit/fraudes
  Query : ?statut=en_cours|clos&page={n}
  Réponse : [{
    id: INT,
    type: "ECART_PERSISTANT"|"QR_REUTILISE"|"PAIEMENT_FRACTIONNE"|"CONNEXION_INSOLITE",
    description: "Écarts stock persistants sur 7 jours — Station Ratoma",
    station_nom: "Ratoma"|null,
    montant_estime: "1200000"|null,  // VARCHAR
    statut: "en_cours"|"clos",
    created_at: "...",
    preuves: ["url_export1", "url_export2"]
  }]

GET /api/audit/qr-invalides
  Query : ?debut={date}&fin={date}&page={n}
  Réponse : [{
    id: INT,
    reference_scannee: "VNT-XXXX-XXXX",
    resultat: "FALSIFIE"|"INTROUVABLE"|"EXPIRE",
    scanner_ip: "...",
    created_at: "..."
  }]

POST /api/audit/exports
  Body : {
    type: "journal"|"anomalies"|"ecarts"|"fraudes",
    debut: "2026-05-01",
    fin: "2026-05-13",
    format: "pdf"
  }
  Réponse : {
    id: INT,
    pdf_url: "...",
    qr_authenticite: "AUD-EXP-2026-0012",
    genere_at: "..."
  }
```

---

## Règles spécifiques

- **RGAUD-01** : AUCUN bouton de modification, suppression, validation ou action dans toute l'interface. Chaque page est en lecture absolue. Le composant `ReadOnlyBadge` est affiché dans le header de chaque section.
- **RGAUD-02** : Maximum 2 sessions AUD simultanées. Si un 3ème AUD tente de se connecter, le BFF retourne HTTP 403 avec message "Nombre maximum de sessions auditeur atteint (2/2)". Géré côté BFF, l'UI affiche l'erreur.
- **RGAUD-03** : Toutes les consultations de l'AUD sont tracées automatiquement côté BFF (middleware). L'UI informe l'AUD via le sous-titre permanent "Vos consultations sont tracées".
- **RGAUD-04** : Le journal d'audit est append-only. L'interface n'a aucun bouton "Modifier" ou "Supprimer". La seule action disponible est l'export PDF certifié avec QR d'authenticité.
- **RGAUD-05** : Les exports PDF incluent un QR d'authenticité (lien vers `verif.flowup-febi.com`). Ils sont signés numériquement par le BFF.
- **RGAUD-06** : Montants (écarts, fraudes) = VARCHAR(255) → `string` dans les types TS. Comparaisons numériques pour affichage couleur (alerte/suspect) via `parseFloat()` uniquement pour le rendu CSS.
- **RGAUD-07** : IDs = `number` (INT UNSIGNED). Aucun soft delete dans ce module — l'AUD ne supprime rien.
- **RGAUD-08** : Les filtres du journal d'audit sont persistés dans l'URL (query params) — l'AUD peut partager une vue filtrée avec un collègue.

---

## Tâche Claude

Génère le code complet Next.js 15 TypeScript pour le module Auditeur & Logs FlowUp ERP.

**Contraintes techniques absolues :**
- Palette navy `#1A2157`, blue `#1E5EFF`, cyan `#00C8C0` — Inter + JetBrains Mono
- Interface 100% lecture seule — zéro bouton POST/PUT/DELETE
- Montants = VARCHAR(255) → `string` dans les types TS
- IDs = `number` (INT UNSIGNED)
- Filtres journal = query params URL (nuqsStateSerializer ou searchParams Next.js)
- SWR pour tous les fetches (pas de mutations)

**Génère dans cet ordre :**
1. Types TypeScript (`types/audit.ts`)
2. Hook `useAudit.ts` (anomalies, journal, écarts, fraudes, QR invalides — SWR uniquement)
3. `ReadOnlyBadge.tsx` (badge permanent visible sur chaque section)
4. `JournalAuditTable.tsx` (tableau paginé, filtres URL query params)
5. `AnomaliesList.tsx` (liste avec gravité, aucun bouton d'action)
6. `EcartsIotVsManuel.tsx` (tableau comparaison, couleur par seuil)
7. `SuspicionsFraude.tsx` (liste suspicions, preuves en lecture)
8. `QrInvalidesLog.tsx` (log scans invalides)
9. `ExportAudit.tsx` (formulaire export PDF + QR authenticité)
10. `AuditDashboard.tsx` (4 KPIs, aucune action)
11. Pages : `page.tsx` (dashboard), `journal/page.tsx`, `anomalies/page.tsx`, `ecarts/page.tsx`, `fraudes/page.tsx`, `exports/page.tsx`
