# Prompt p12 — IoT Dashboard Supervision (web)
*Contextes requis : ctx-global.md + ctx-web-nextjs.md + ctx-laravel-bff.md*

---

## Profil & Accès
- **Rôle** : OPE (Responsable Opérations)
- **Nombre d'utilisateurs** : 2
- **Accès** : supervision complète des 23 stations et 52 capteurs IoT
- **Session** : 8h, OTP à la connexion

---

## Fichiers à créer

```
app/(erp)/iot/page.tsx
app/(erp)/iot/stations/[id]/page.tsx
app/(erp)/iot/alertes/page.tsx
components/iot/SupervisionMap.tsx
components/iot/StationsList.tsx
components/iot/StationPanel.tsx
components/iot/CuveGauge.tsx
components/iot/AlerteNotification.tsx
components/iot/AlerteHistory.tsx
components/iot/PompeDebit.tsx
components/iot/CapteurStatus.tsx
hooks/useIotSupervision.ts
hooks/useIotWebSocket.ts
hooks/useAlertes.ts
```

---

## Spec UX condensée

```
┌─────────────────────────────────────────────────────────────────────┐
│ FLOWUP ERP       IoT — Supervision 23 Stations          [OPE]       │
│ ● WebSocket connecté  ⚠ 2 alertes critiques         10:42:17 UTC   │
├────────────────────────────────────────────────────┬────────────────┤
│              CARTE STATIONS                        │ STATIONS (23) │
│                                                    │               │
│   🟢 Kaloum      🟢 Dixinn    🟠 Ratoma           │ 🟢 Kaloum     │
│                                                    │   Gasoil: 78% │
│   🔴 Matoto      🟢 Coleah    🟢 Lambang.         │   SP95:   61% │
│                                                    │   Pompes: 3/3 │
│       [ Leaflet OpenStreetMap ]                    │ ─────────     │
│                                                    │ 🟠 Ratoma     │
│   🟢 Dubreka     🟢 Kindia    🟢 Kankan            │   Gasoil: 24% │
│                                                    │   ⚠ Seuil bas │
│   🟠 = alerte seuil                               │   Pompes: 2/3 │
│   🔴 = alerte critique                            │ ─────────     │
│   🟢 = opérationnelle                             │ 🔴 Matoto     │
│                                                    │   🚨 FUITE C2 │
│   [clic station → panel détail]                   │   Pompes: 0/3 │
├────────────────────────────────────────────────────┴────────────────┤
│ ALERTES CRITIQUES                                                    │
│ 🔴 10:38  Station Matoto — Fuite détectée Cuve #2 (H₂S sensor)     │
│ 🟠 10:41  Station Ratoma — Niveau Gasoil < 10% (23 847 L / 30 000L)│
│ [Voir toutes les alertes]                                           │
└─────────────────────────────────────────────────────────────────────┘
```

### Panel détail station (slide-over droite)
```
┌────────────────────────────────────┐
│ KALOUM — Supervision IoT      [×]  │
│ ● 52 capteurs actifs               │
├────────────────────────────────────┤
│ CUVES                              │
│ ┌─── Gasoil ─────────────────────┐ │
│ │ ████████████████░░░░░░  78%    │ │
│ │ 23 400 L / 30 000 L            │ │
│ │ Température : 28°C             │ │
│ │ Densité : 0.836 g/cm³          │ │
│ └────────────────────────────────┘ │
│ ┌─── SP95 ───────────────────────┐ │
│ │ ████████████░░░░░░░░░  61%    │ │
│ │ 18 300 L / 30 000 L            │ │
│ └────────────────────────────────┘ │
│                                    │
│ POMPES (débit temps réel)          │
│ Pompe 1 : 42 L/min  ● actif        │
│ Pompe 2 : 38 L/min  ● actif        │
│ Pompe 3 : 0 L/min   ○ inactif      │
│                                    │
│ ALERTES STATION (3)                │
│ Pas d'alerte active ✓              │
│                                    │
│ [Voir historique 7j]               │
└────────────────────────────────────┘
```

### Types d'événements WebSocket
- **NIVEAU_CUVE** : mise à jour niveau en % et volume
- **POMPE_DEBIT** : débit instantané en L/min
- **ALERTE_FUITE** : détection fuite (critique, notification push)
- **ALERTE_SEUIL** : niveau sous seuil paramétré (alerte)
- **CAPTEUR_OFFLINE** : capteur hors ligne > 5min
- **TEMPERATURE** : température cuve (information)
- **DENSITE** : densité cuve (information)

---

## Endpoints BFF

```
GET /api/iot/supervision
  Réponse : [{
    station_id: INT,
    station_nom: "Kaloum",
    lat: "9.538",          // VARCHAR
    lng: "-13.677",        // VARCHAR
    statut_global: "ok"|"alerte"|"critique",
    nb_capteurs_actifs: 52,
    nb_capteurs_total: 52,
    nb_pompes_actives: 3,
    nb_pompes_total: 3,
    cuves: [{
      id: INT,
      produit: "Gasoil",
      capacite: "30000",           // VARCHAR (litres)
      niveau_actuel: "23400",      // VARCHAR
      niveau_pct: "78",            // VARCHAR
      temperature: "28",           // VARCHAR (°C)
      densite: "0.836",            // VARCHAR (g/cm³)
      statut: "ok"|"alerte"|"critique"
    }],
    alertes_actives: [{ id: INT, type: "...", message: "...", gravite: "..." }]
  }]

GET /api/iot/stations/{id}/detail
  Réponse : { ...même structure que supervision mais pour 1 station + historique 7j }

GET /api/iot/alertes
  Query : ?statut=active|resolue&gravite=critique|alerte&station_id={id}&page={n}
  Réponse : {
    data: [{
      id: INT,
      station_nom: "Matoto",
      type: "ALERTE_FUITE"|"ALERTE_SEUIL"|"CAPTEUR_OFFLINE"|...,
      message: "Fuite détectée Cuve #2",
      gravite: "critique"|"alerte"|"info",
      statut: "active"|"resolue",
      created_at: "2026-05-13T10:38:00Z",
      resolue_at: null|"..."
    }],
    meta: { total: INT, critiques_actives: INT }
  }

PUT /api/iot/alertes/{id}/resoudre
  Body : { commentaire: "Intervention réalisée. Fuite colmatée." }
  Réponse : { id: INT, statut: "resolue", resolue_at: "..." }

WS ws://127.0.0.1:4800
  Auth : ?token={jwt}
  Events reçus : {
    type: "NIVEAU_CUVE"|"POMPE_DEBIT"|"ALERTE_FUITE"|"ALERTE_SEUIL"|"CAPTEUR_OFFLINE",
    station_id: INT,
    capteur_id: INT,
    data: { ... }  // selon type
    timestamp: "..."
  }
```

---

## Règles spécifiques

- **RGIOT-01** : La connexion WebSocket (`ws://127.0.0.1:4800?token={jwt}`) est établie dès le montage du composant root. Reconnexion automatique avec backoff exponentiel (1s, 2s, 4s, 8s, max 60s). Indicateur visuel (dot vert/rouge) dans le header.
- **RGIOT-02** : Alertes critiques (ALERTE_FUITE, CAPTEUR_OFFLINE) déclenchent une notification push via l'API Notifications du navigateur (si permission accordée) ET un badge persistant dans le header.
- **RGIOT-03** : La carte Leaflet ne se rend pas côté serveur — `dynamic(() => import(...), { ssr: false })`. Marqueurs cliquables → slide-over panel détail (pas de navigation page).
- **RGIOT-04** : Le slide-over panel de détail station est mis à jour en temps réel via les événements WebSocket filtrés par `station_id`.
- **RGIOT-05** : Montants/volumes = VARCHAR(255). Les niveaux (%) sont des strings → `parseFloat()` uniquement pour le rendu visuel des jauges (largeur CSS), pas pour la DB.
- **RGIOT-06** : Les alertes critiques actives restent en bandeau rouge en haut de page jusqu'à résolution explicite. L'OPE peut marquer "Résolu" avec un commentaire obligatoire.
- **RGIOT-07** : IDs = `number` (INT UNSIGNED). Soft delete = `statut: 3` pour les capteurs décommissionnés.
- **RGIOT-08** : La liste des stations (panel droit) est triée : critiques en premier, puis alertes, puis ok. Tri automatique mis à jour en temps réel via WebSocket.

---

## Tâche Claude

Génère le code complet Next.js 15 TypeScript pour le module IoT Dashboard Supervision FlowUp ERP.

**Contraintes techniques absolues :**
- Palette navy `#1A2157`, blue `#1E5EFF`, cyan `#00C8C0` — Inter + JetBrains Mono
- Montants/volumes = VARCHAR(255) → `string` dans les types TS
- IDs = `number` (INT UNSIGNED)
- Leaflet = dynamic import, SSR disabled
- WebSocket dans `useIotWebSocket` avec cleanup, reconnexion auto backoff
- Slide-over panel (pas de page séparée) pour le détail station

**Génère dans cet ordre :**
1. Types TypeScript (`types/iot.ts`)
2. Hook `useIotWebSocket.ts` (connexion, reconnexion, dispatch events par type)
3. Hook `useIotSupervision.ts` (état 23 stations, merge WebSocket + polling fallback 30s)
4. Hook `useAlertes.ts` (liste alertes, résolution)
5. `CuveGauge.tsx` (barre animée couleur-status)
6. `PompeDebit.tsx` (débit temps réel L/min)
7. `CapteurStatus.tsx` (dot vert/rouge)
8. `AlerteNotification.tsx` (bandeau critique)
9. `StationPanel.tsx` (slide-over détail)
10. `StationsList.tsx` (panel droit trié par criticité)
11. `SupervisionMap.tsx` (Leaflet, dynamic import, marqueurs colorés)
12. `AlerteHistory.tsx` (journal alertes paginé)
13. Pages : `page.tsx` (dashboard principal), `stations/[id]/page.tsx`, `alertes/page.tsx`
