# Plan de migration React — Modules Participants & Hébergement

**Plateforme :** Mediknode (Laravel 11 / Blade → React embarqué via Vite)  
**Thème React :** Veltrix React v4.2.0 (Bootstrap 5 + Reactstrap)  
**Date de rédaction :** 2026-05-05  
**Principe fondamental :** Zéro effet de bord sur la production — bascule par feature flag, rollback immédiat possible.

---

## Table des matières

1. [Périmètre](#1-périmètre)
2. [Architecture cible](#2-architecture-cible)
3. [Stratégie d'isolation](#3-stratégie-disolation)
4. [Ce qui NE change PAS](#4-ce-qui-ne-change-pas)
5. [Phase 1 — API Laravel](#5-phase-1--api-laravel)
6. [Phase 2 — Setup React dans Vite](#6-phase-2--setup-react-dans-vite)
7. [Phase 3 — Module Participants](#7-phase-3--module-participants)
8. [Phase 4 — Module Hébergement](#8-phase-4--module-hébergement)
9. [Phase 5 — Recette & bascule production](#9-phase-5--recette--bascule-production)
10. [Phase 6 — Nettoyage](#10-phase-6--nettoyage)
11. [Gestion du badge (CORE)](#11-gestion-du-badge-core)
12. [Tableau des risques](#12-tableau-des-risques)
13. [Calendrier estimatif](#13-calendrier-estimatif)

---

## 1. Périmètre

### Modules migrés en React
| Module | Controllers concernés | Vues Blade remplacées |
|--------|----------------------|----------------------|
| **Participants** | `ParticipantController` | 15 vues (`index`, `show`, `add`, `edit`, `validate`, `reprise`, `subscribe`, `revalidate`, `edit-account`, ...) |
| **Hébergement** | `HebergementController` | 8 vues (`index`, `show`, `add`, `edit`, `validate`, `reprise`, `edit-reprise`) |

### Modules qui restent en Blade (hors périmètre)
- Hôtels / RoomTypes / RoomArrangements
- Tous les autres modules du backoffice
- Frontend (événements publics)

---

## 2. Architecture cible

```
Laravel (API + session auth)
│
├── routes/web.php          ← routes Blade existantes (inchangées pendant migration)
├── routes/api.php
│   ├── /api/v2/...         ← endpoints DataTable existants (inchangés)
│   └── /api/react/...      ← nouveaux endpoints pour React (ajout uniquement)
│
├── resources/
│   ├── views/backend/
│   │   ├── participants/   ← vues Blade originales (intactes jusqu'à Phase 6)
│   │   ├── hebergement/    ← vues Blade originales (intactes jusqu'à Phase 6)
│   │   └── react/          ← nouveaux wrappers Blade (juste un <div id="root">)
│   │       ├── participants.blade.php
│   │       └── hebergement.blade.php
│   │
│   └── js/
│       ├── backend/        ← JS existant (inchangé)
│       └── react/          ← nouveau code React isolé
│           ├── participants/
│           │   ├── main.jsx
│           │   ├── App.jsx
│           │   ├── router.jsx
│           │   ├── api/       ← appels axios
│           │   ├── components/
│           │   └── pages/
│           └── hebergement/
│               ├── main.jsx
│               ├── App.jsx
│               ├── router.jsx
│               ├── api/
│               ├── components/
│               └── pages/
│
└── vite.config.js          ← ajout des 2 nouveaux entry points React
```

---

## 3. Stratégie d'isolation

### Feature flags dans `.env`

```dotenv
REACT_PARTICIPANTS=false
REACT_HEBERGEMENT=false
```

### Bascule dans les controllers (un seul if, zéro logique dupliquée)

```php
// ParticipantController@index
public function index(Event $event)
{
    $this->authorize('view', $event);

    if (config('app.react_participants')) {
        return view('backend.react.participants', compact('event'));
    }

    // logique Blade existante inchangée
    return view('backend.participants.index', compact('event', ...));
}
```

```php
// HebergementController@index
public function index(Event $event)
{
    if (config('app.react_hebergement')) {
        return view('backend.react.hebergement', compact('event'));
    }

    return view('backend.hebergement.index', compact('event', ...));
}
```

### Rollback
Changer `REACT_PARTICIPANTS=false` dans `.env` + `php artisan config:cache` → retour immédiat au Blade, sans déploiement.

---

## 4. Ce qui NE change PAS

| Élément | Raison |
|---------|--------|
| Génération PDF badge (DomPDF) | 100% serveur, React n'intervient pas |
| Endpoint `GET /participants/{id}/get-badge` | Retourne un fichier PDF, inchangé |
| Endpoint `GET /hebergement/{id}/get-voucher` | Idem |
| Import Excel participants/hébergements | Controller Laravel, React soumet juste le fichier |
| Système d'authentification (session Laravel) | React utilise les cookies de session existants |
| Hôtels / RoomTypes / RoomArrangements | Hors périmètre, reste Blade |
| Tous les autres modules backoffice | Hors périmètre |
| `ManageController` (legacy `/manage/`) | Déprécié séparément, hors périmètre |
| Pusher / Laravel Echo | Réintégré si besoin via `laravel-echo` npm |

---

## 5. Phase 1 — API Laravel

> **Durée estimée : 1 semaine**  
> **Risque prod : zéro** (ajout uniquement, aucune modification de l'existant)

### 5.1 Sanctum SPA (auth cookie)

Vérifier que `config/cors.php` autorise le domaine backoffice et que `EnsureFrontendRequestsAreStateful` est actif. Pas de JWT — on réutilise la session existante.

### 5.2 Nouveaux endpoints Participants

Fichier : `app/Http/Controllers/Backend/Api/ParticipantApiController.php`

| Méthode | URL | Description |
|---------|-----|-------------|
| `GET` | `/api/react/events/{event}/participants` | Liste paginée + filtres (nom, statut, catégorie) |
| `GET` | `/api/react/events/{event}/participants/{id}` | Détail participant |
| `POST` | `/api/react/events/{event}/participants` | Créer participant |
| `PUT` | `/api/react/events/{event}/participants/{id}` | Modifier participant |
| `DELETE` | `/api/react/events/{event}/participants/{id}` | Supprimer |
| `POST` | `/api/react/events/{event}/participants/{id}/validate` | Valider |
| `POST` | `/api/react/events/{event}/participants/{id}/invalidate` | Invalider |
| `POST` | `/api/react/events/{event}/participants/{id}/present` | Marquer présent |
| `POST` | `/api/react/events/{event}/participants/{id}/unpresent` | Marquer absent |
| `POST` | `/api/react/events/{event}/participants/{id}/quick-validate` | Validation rapide |
| `POST` | `/api/react/events/{event}/participants/{id}/reprise` | Reprise |
| `POST` | `/api/react/events/{event}/participants/{id}/revalidate` | Revalider |
| `POST` | `/api/react/events/{event}/participants/{id}/subscribe` | Mise à jour souscription |
| `GET` | `/api/react/events/{event}/participants/search-users` | Recherche utilisateurs (autocomplete) |
| `GET` | `/api/react/events/{event}/participants/{id}/badge-url` | URL du badge PDF |

**Réponse standard :**
```json
{
  "data": { ... },
  "message": "OK",
  "errors": null
}
```

### 5.3 Nouveaux endpoints Hébergement

Fichier : `app/Http/Controllers/Backend/Api/HebergementApiController.php`

| Méthode | URL | Description |
|---------|-----|-------------|
| `GET` | `/api/react/events/{event}/hebergements` | Liste paginée |
| `GET` | `/api/react/events/{event}/hebergements/{id}` | Détail |
| `POST` | `/api/react/events/{event}/hebergements` | Créer |
| `PUT` | `/api/react/events/{event}/hebergements/{id}` | Modifier |
| `DELETE` | `/api/react/events/{event}/hebergements/{id}` | Supprimer |
| `POST` | `/api/react/events/{event}/hebergements/{id}/validate` | Valider |
| `POST` | `/api/react/events/{event}/hebergements/{id}/invalidate` | Invalider |
| `POST` | `/api/react/events/{event}/hebergements/{id}/checkin` | Check-in |
| `POST` | `/api/react/events/{event}/hebergements/{id}/uncheckin` | Annuler check-in |
| `POST` | `/api/react/events/{event}/hebergements/{id}/reprise` | Reprise |
| `GET` | `/api/react/events/{event}/hotels` | Liste hôtels (pour select) |
| `GET` | `/api/react/hotels/{hotel}/room-types` | Types de chambre |
| `GET` | `/api/react/room-types/{roomType}/arrangements` | Arrangements |

### 5.4 Ressources API (JSON transformers)

- `ParticipantResource` — shape JSON du participant (inclut user, workshops, metas)
- `HebergementResource` — shape JSON de la réservation hébergement
- `HotelResource` / `RoomTypeResource` — pour les selects

---

## 6. Phase 2 — Setup React dans Vite

> **Durée estimée : 3 jours**  
> **Risque prod : zéro**

### 6.1 Dépendances npm à ajouter

```bash
npm install react react-dom react-router-dom axios
npm install reactstrap bootstrap  # déjà dans Veltrix, aligner les versions
npm install @tanstack/react-table  # remplace DataTables jQuery
npm install react-select           # remplace Select2
npm install react-to-print         # ou conserver print.js via CDN
npm install @vitejs/plugin-react
```

### 6.2 Modifier `vite.config.js`

```js
import react from '@vitejs/plugin-react'

export default defineConfig({
  plugins: [laravel({ ... }), react()],
  build: {
    rollupOptions: {
      input: {
        frontend: 'public/assets/css/frontend.css',         // existant
        'react-participants': 'resources/js/react/participants/main.jsx',
        'react-hebergement':  'resources/js/react/hebergement/main.jsx',
      }
    }
  }
})
```

### 6.3 Wrappers Blade

**`resources/views/backend/react/participants.blade.php`**
```blade
@extends('backend.layouts.master')

@section('head-css')
  @vite('resources/js/react/participants/main.jsx')
@endsection

@section('content')
  <div
    id="react-participants-root"
    data-event-id="{{ $event->id }}"
    data-event-name="{{ $event->name }}"
    data-csrf="{{ csrf_token() }}"
  ></div>
@endsection
```

> Les données contextuelles (event_id, csrf) sont passées via `data-*` attributes — pas de variable JS globale.

### 6.4 Intégration thème Veltrix

- Copier `src/assets/scss/` de Veltrix dans `resources/js/react/`
- Utiliser les composants `Card`, `Table`, `Modal`, `Badge` de Reactstrap (déjà dans Veltrix)
- Adapter les couleurs via les variables SCSS pour matcher la charte actuelle du backoffice

---

## 7. Phase 3 — Module Participants

> **Durée estimée : 2 semaines**  
> **Déployable en prod avec `REACT_PARTICIPANTS=false` pendant tout le dev**

### 7.1 Pages à créer

| Page React | Équivalent Blade | Priorité |
|-----------|-----------------|----------|
| `ParticipantList` | `participants/index.blade.php` | 🔴 P1 — critique desk |
| `ParticipantShow` | `participants/show.blade.php` | 🔴 P1 |
| `ParticipantAdd` | `participants/add.blade.php` | 🟡 P2 |
| `ParticipantEdit` | `participants/edit.blade.php` | 🟡 P2 |
| `ParticipantValidate` | `participants/validate.blade.php` | 🔴 P1 — critique desk |
| `ParticipantSubscribe` | `participants/subscribe.blade.php` | 🟡 P2 |
| `ParticipantReprise` | `participants/reprise.blade.php` | 🟡 P2 |
| `ParticipantRevalidate` | `participants/revalidate.blade.php` | 🟡 P2 |
| `ParticipantEditAccount` | `participants/edit-account.blade.php` | 🟢 P3 |

### 7.2 Composants partagés à créer

- `<ParticipantTable>` — liste avec TanStack Table, filtres, pagination
- `<ParticipantStatusBadge>` — badge coloré selon statut
- `<ParticipantActions>` — menu actions inline (valider, présent, badge, supprimer)
- `<BadgePrintButton>` — bouton impression badge (voir section 11)
- `<ParticipantSearch>` — recherche live par nom/code
- `<CategorySelect>` — select des catégories
- `<WorkshopList>` — ateliers du participant

### 7.3 Gestion de l'état

- **React Query** (ou SWR) pour le cache des données serveur — évite Redux pour les données API
- **React Router v6** pour la navigation interne (`/events/:eventId/participants/*`)
- Pas de Redux — trop lourd pour ce périmètre (contrairement au thème Veltrix complet)

### 7.4 Actions critiques desk (P1)

Ces actions doivent être accessibles **sans quitter la liste** :

```
Liste participants
├── [Recherche instantanée]
├── Ligne participant
│   ├── [✓ Valider]        → Modal de confirmation inline
│   ├── [● Présent]        → Toggle inline, mise à jour optimiste
│   ├── [🖨 Badge]          → print.js (voir section 11)
│   └── [→ Voir fiche]     → Navigation React Router
```

---

## 8. Phase 4 — Module Hébergement

> **Durée estimée : 1 semaine**  
> **Déployable en prod avec `REACT_HEBERGEMENT=false` pendant tout le dev**

### 8.1 Pages à créer

| Page React | Équivalent Blade | Priorité |
|-----------|-----------------|----------|
| `HebergementList` | `hebergement/index.blade.php` | 🔴 P1 |
| `HebergementShow` | `hebergement/show.blade.php` | 🔴 P1 |
| `HebergementAdd` | `hebergement/add.blade.php` | 🟡 P2 |
| `HebergementEdit` | `hebergement/edit.blade.php` | 🟡 P2 |
| `HebergementValidate` | `hebergement/validate.blade.php` | 🔴 P1 |
| `HebergementReprise` | `hebergement/reprise.blade.php` | 🟡 P2 |

### 8.2 Composants partagés

- `<HebergementTable>` — liste avec filtres hôtel, statut, check-in
- `<CheckinButton>` — toggle check-in inline
- `<VoucherPrintButton>` — impression voucher PDF (même pattern que badge)
- `<HotelSelect>` / `<RoomTypeSelect>` / `<ArrangementSelect>` — selects chaînés

---

## 9. Phase 5 — Recette & bascule production

> **Durée estimée : 1 semaine**

### 9.1 Environnement de recette

1. Activer sur staging : `REACT_PARTICIPANTS=true` / `REACT_HEBERGEMENT=true`
2. Tests fonctionnels avec le personnel desk
3. Scénarios à valider :
   - [ ] Recherche participant par nom
   - [ ] Validation + impression badge automatique
   - [ ] Marquer présent / absent
   - [ ] Création participant
   - [ ] Modification participant
   - [ ] Ajout hébergement
   - [ ] Check-in hébergement
   - [ ] Impression voucher
   - [ ] Import Excel (participants + hébergements)
   - [ ] Retour liste après action (filtre préservé)

### 9.2 Bascule production

1. Déployer le code (feature flags à `false` → aucun impact)
2. Activer `REACT_PARTICIPANTS=true` → tester 30 min
3. Activer `REACT_HEBERGEMENT=true` → tester 30 min
4. Garder les vues Blade en place pendant **1 mois** (rollback possible)

---

## 10. Phase 6 — Nettoyage

> **Après 1 mois de prod stable**

- Supprimer les vues Blade `participants/*.blade.php` et `hebergement/*.blade.php`
- Retirer les feature flags du `.env` et des controllers
- Supprimer le code Blade dans les controllers (le `if (config(...))`)
- Évaluer la dépréciation de `ManageController` (legacy `/manage/`)

---

## 11. Gestion du badge (CORE)

> Le badge est le flux critique du desk événement. Il reste **100% Laravel**.

### Flux inchangé

```
[Action validation]
       ↓
ParticipantController@validationPost()
       ↓
generateBadge() → DomPDF → storage/app/{eventId}/badges/access-print/badge_{id}.pdf
       ↓
redirect → /participants?print_badge={userId}
```

### Côté React (reproduction exacte du comportement actuel)

```jsx
// Bouton impression badge
const printBadge = (userId) => {
  const url = `/events/${eventId}/participants/${userId}/get-badge?t=${Date.now()}`;
  printJS(url, 'pdf'); // même librairie, chargée dans le wrapper Blade
};

// Auto-print après validation (équivalent du JS Blade actuel)
useEffect(() => {
  const params = new URLSearchParams(location.search);
  const userId = params.get('print_badge');
  if (userId) {
    setTimeout(() => printBadge(userId), 800);
    navigate(location.pathname, { replace: true }); // nettoyer l'URL
  }
}, []);
```

### Endpoint badge (inchangé, Laravel)

```
GET /events/{eventId}/participants/{userId}/get-badge
→ response()->file($pdfPath, ['Content-Type' => 'application/pdf'])
```

**React ouvre cet URL dans print.js — aucun changement côté serveur.**

---

## 12. Tableau des risques

| Risque | Probabilité | Impact | Mitigation |
|--------|------------|--------|------------|
| Badge ne s'imprime plus | Faible | Critique | Endpoint Laravel inchangé, même logique JS |
| Régression sur Blade pendant dev | Nulle | Élevé | Feature flags = code Blade non touché |
| Conflit CSS Veltrix / thème actuel | Moyenne | Moyen | CSS scopé dans les wrappers React |
| Perte de filtre/état après action | Faible | Moyen | React Router + React Query préservent l'état |
| Session expirée en prod | Faible | Moyen | Intercepteur axios → redirect login |
| Performance API lente | Faible | Moyen | Pagination, React Query cache |
| Import Excel cassé | Nulle | Élevé | Controller Laravel inchangé, React soumet `FormData` |

---

## 13. Calendrier estimatif

```
Semaine 1   Phase 1 — API endpoints React (lecture + écriture)
Semaine 2   Phase 2 — Setup Vite + React + intégration Veltrix
Semaine 3   Phase 3 — Participants P1 (List, Show, Validate, Badge)
Semaine 4   Phase 3 — Participants P2/P3 (Add, Edit, Subscribe, Reprise)
Semaine 5   Phase 4 — Hébergement (List, Show, Validate, Checkin, Add, Edit)
Semaine 6   Phase 5 — Recette staging + corrections
Semaine 7   Phase 5 — Bascule production progressive
Semaine 11+ Phase 6 — Nettoyage (après 1 mois de prod stable)
```

---

## Checklist de démarrage (Phase 1)

- [ ] Ajouter `REACT_PARTICIPANTS=false` et `REACT_HEBERGEMENT=false` dans `.env` et `.env.example`
- [ ] Créer `app/Http/Controllers/Backend/Api/ParticipantApiController.php`
- [ ] Créer `app/Http/Controllers/Backend/Api/HebergementApiController.php`
- [ ] Créer `app/Http/Resources/ParticipantResource.php`
- [ ] Créer `app/Http/Resources/HebergementResource.php`
- [ ] Ajouter les routes `/api/react/...` dans `routes/api.php`
- [ ] Vérifier `config/cors.php` pour Sanctum SPA
- [ ] Tester les endpoints avec Postman/Insomnia
