# Prompt p15 — Ressources Humaines (web)
*Contextes requis : ctx-global.md + ctx-web-nextjs.md + ctx-laravel-bff.md*

---

## Profil & Accès
- **Rôle** : RRH (Responsable RH)
- **Nombre d'utilisateurs** : 2
- **Accès** : 174 employés, toutes les stations, tous les modules RH
- **Session** : 8h, OTP à la connexion

---

## Fichiers à créer

```
app/(erp)/rh/page.tsx
app/(erp)/rh/employes/page.tsx
app/(erp)/rh/employes/[id]/page.tsx
app/(erp)/rh/employes/[id]/paie/page.tsx
app/(erp)/rh/presences/page.tsx
app/(erp)/rh/paie/page.tsx
app/(erp)/rh/paie/[id]/bulletin/page.tsx
app/(erp)/rh/cnss/page.tsx
components/rh/EmployeTable.tsx
components/rh/FicheEmploye.tsx
components/rh/PresencesCalendrier.tsx
components/rh/BulletinPaie.tsx
components/rh/CalculPaieModal.tsx
components/rh/ExportCnss.tsx
components/rh/OngletContrat.tsx
components/rh/OngletPerformance.tsx
components/rh/OngletDocuments.tsx
hooks/useRh.ts
hooks/usePresences.ts
hooks/usePaie.ts
```

---

## Spec UX condensée

```
┌─────────────────────────────────────────────────────────────────────┐
│ FLOWUP ERP          Ressources Humaines                     [RRH]   │
├─────────────────────────────────────────────────────────────────────┤
│ [Dashboard][Employés][Présences][Paie][CNSS Export]                │
├─────────────────────────────────────────────────────────────────────┤
│ DASHBOARD RH                                                         │
│ Effectif: 174 · Actifs: 171 · En congé: 3 · Paie ce mois: 89M GNF  │
│ ┌──────────────────────────────────┐  ┌──────────────────────────┐  │
│ │  RÉPARTITION PAR STATION         │  │  ALERTES RH              │  │
│ │  Kaloum     : 12  ███            │  │  ⚠ 2 contrats expirent  │  │
│ │  Ratoma     : 10  ██             │  │    dans 30 jours         │  │
│ │  Dixinn     :  8  ██             │  │  ℹ Clôture paie: J-3    │  │
│ │  ...                             │  │                           │  │
│ └──────────────────────────────────┘  └──────────────────────────┘  │
├─────────────────────────────────────────────────────────────────────┤
│ FICHE EMPLOYÉ — Moussa Camara (EMP-0047)                            │
│ [Infos][Contrat][Présences][Paie][Performance][Documents]           │
│ ─────────────────────────────────────────────────────────────────── │
│  Infos :   Nom, prénom, né le, NIF, CNSS, poste, station, date ent. │
│  Contrat : type (CDI/CDD/Stage), salaire base, date début/fin       │
│  Présences: calendrier mois, pointages IoT/app, absences, retards   │
│  Paie :    historique 12 bulletins, détail cotisations, télécharger │
│  Perf. :   objectifs, KPIs ops IoT, évaluations semestrielles       │
│  Documents: contrat scanné, pièce identité, CNSS, diplômes          │
└─────────────────────────────────────────────────────────────────────┘
```

### Calcul de paie (règles Guinée)
- **CNSS patronal** : 13% sur salaire brut
- **CNSS salarial** : 5% sur salaire brut (déduit du net)
- **IR progressif** (tranches Guinée) :
  - 0 – 1 000 000 GNF : 0%
  - 1 000 001 – 3 000 000 GNF : 10%
  - 3 000 001 – 7 000 000 GNF : 15%
  - > 7 000 000 GNF : 20%
- **Primes** : prime de présence (pointage IoT ≥98%), prime opérations (KPIs station), heures sup.
- **Net à payer** = Brut - CNSS salarial - IR + Primes - Retenues diverses

### Export CNSS
- **XLSX** : format tableau CNSS Guinée (colonnes : N° CNSS, NOM, Prenom, Salaire brut, Part salariale, Part patronale)
- **XML** : format de déclaration électronique CNSS Guinée

---

## Endpoints BFF

```
GET /api/employes
  Query : ?station_id={id}&poste={p}&search={q}&page={n}&per_page=20
  Réponse : {
    data: [{
      id: INT,
      code: "EMP-0047",
      nom: "Camara",
      prenom: "Moussa",
      poste: "Chauffeur",
      station_nom: "Kaloum",
      statut: 1|3,  // 3 = sorti
      date_entree: "2023-01-15",
      salaire_base: "3500000"   // VARCHAR (GNF)
    }],
    meta: { total: INT, actifs: INT, en_conge: INT }
  }

GET /api/employes/{id}
  Réponse : {
    id: INT, code: "EMP-0047",
    nom: "Camara", prenom: "Moussa",
    date_naissance: "1985-03-12",
    nif: "...", numero_cnss: "...",
    poste: "Chauffeur", station_id: INT,
    date_entree: "2023-01-15",
    salaire_base: "3500000",    // VARCHAR
    type_contrat: "CDI"|"CDD"|"Stage",
    date_fin_contrat: null|"..."
  }

GET /api/presences/{employe_id}
  Query : ?mois={YYYY-MM}
  Réponse : [{
    date: "2026-05-13",
    heure_entree: "07:58",
    heure_sortie: "16:02",
    source: "iot"|"app"|"manuel",
    statut: "present"|"absent"|"retard"|"conge"
  }]

POST /api/paie/calculer
  Body : { mois: "2026-05", employe_ids: [INT] | "tous" }
  Réponse : {
    job_id: "uuid",
    status: "en_cours",
    nb_employes: 174
  }

GET /api/paie/bulletins
  Query : ?mois={YYYY-MM}&employe_id={id}&page={n}
  Réponse : [{
    id: INT,
    employe_id: INT,
    employe_nom: "Moussa Camara",
    mois: "2026-05",
    salaire_brut: "3500000",     // VARCHAR
    cnss_salarial: "175000",     // VARCHAR (5%)
    cnss_patronal: "455000",     // VARCHAR (13%)
    ir: "350000",                // VARCHAR (calculé)
    primes: "200000",            // VARCHAR
    retenues: "0",               // VARCHAR
    net_a_payer: "3175000",      // VARCHAR
    pdf_url: "...",
    qr_authenticite: "VER-2026-BUL-0047"
  }]

GET /api/paie/bulletins/{id}
  Réponse : { ...détail complet du bulletin... }

GET /api/cnss/export
  Query : ?mois={YYYY-MM}&format=xlsx|xml
  Réponse : File (téléchargement)

GET /api/rh/stats
  Réponse : {
    effectif_total: 174,
    actifs: 171,
    en_conge: 3,
    masse_salariale_mois: "89000000",   // VARCHAR
    contrats_expirant_30j: 2
  }
```

---

## Règles spécifiques

- **RGRH-01** : Tous les montants (salaires, cotisations, primes) = VARCHAR(255). Les calculs de paie sont effectués côté BFF (pas de calcul de paie côté client). L'UI affiche uniquement les résultats.
- **RGRH-02** : Le calcul de paie mensuel est un job async (POST /api/paie/calculer retourne un `job_id`). L'UI poll le statut du job toutes les 2s jusqu'à `status: "termine"`.
- **RGRH-03** : Les bulletins de paie incluent un QR d'authenticité (lien vers `verif.flowup-febi.com`). Le PDF est généré côté BFF.
- **RGRH-04** : La fiche employé comporte 6 onglets. Chaque onglet charge ses données de manière lazy (SWR, uniquement quand l'onglet est activé).
- **RGRH-05** : Les présences source "IoT" (pointage réseau capteurs) et source "app" (mobile) sont en lecture seule. Seules les présences source "manuel" peuvent être modifiées (correction par le RRH avec motif obligatoire).
- **RGRH-06** : Export CNSS : le bouton génère le fichier côté BFF et retourne une URL de téléchargement signée (TTL 5min). Pas de génération côté client.
- **RGRH-07** : IDs = `number` (INT UNSIGNED). Soft delete = `statut: 3` pour les employés sortis (toujours visibles en historique, filtrables).
- **RGRH-08** : Recherche employé avec debounce 300ms sur nom/prénom/code/station.

---

## Tâche Claude

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

**Contraintes techniques absolues :**
- Palette navy `#1A2157`, blue `#1E5EFF`, cyan `#00C8C0` — Inter + JetBrains Mono
- Montants = VARCHAR(255) → `string` dans les types TS. Pas de calcul de paie côté client
- IDs = `number` (INT UNSIGNED). Soft delete = `statut: 3`
- Tabs lazy loading (SWR par onglet)
- Job polling 2s pour le calcul de paie

**Génère dans cet ordre :**
1. Types TypeScript (`types/rh.ts`)
2. Hook `useRh.ts` (dashboard, employés, liste)
3. Hook `usePresences.ts` (calendrier mensuel)
4. Hook `usePaie.ts` (bulletins, calcul job, polling 2s)
5. `EmployeTable.tsx` (liste paginée + recherche debounce)
6. `PresencesCalendrier.tsx` (grille mois, couleurs par statut)
7. `OngletContrat.tsx`, `OngletPerformance.tsx`, `OngletDocuments.tsx`
8. `CalculPaieModal.tsx` (déclenchement + polling job)
9. `BulletinPaie.tsx` (affichage détaillé + QR)
10. `ExportCnss.tsx` (XLSX + XML)
11. `FicheEmploye.tsx` (6 onglets lazy)
12. Pages : `page.tsx` (dashboard), `employes/page.tsx`, `employes/[id]/page.tsx`, `employes/[id]/paie/page.tsx`, `presences/page.tsx`, `paie/page.tsx`, `paie/[id]/bulletin/page.tsx`, `cnss/page.tsx`
