# Architecture Technique - Wellpack Admin

Ce fichier contient la documentation technique détaillée du projet pour les agents IA.

## Vue d'ensemble

Wellpack Admin est un panneau d'administration Laravel 12 pour gérer des campagnes SMS marketing, des landing pages et des URLs courtes. Le frontend utilise des composants React intégrés dans des templates Blade via Vite, avec GrapesJS comme éditeur visuel pour les landing pages.

--- 

## GrapesJS - Système de Landing Pages

### Structure des fichiers

```
resources/js/grapejs/
├── blocks.js              # Importe et enregistre les 24 blocs
├── components.js          # Importe et enregistre les 28 composants
├── commands.js            # Commandes custom (save, preview, clear, device switching)
├── style.js               # Secteurs du Style Manager (typography, decorations, dimension)
├── richTextEditor.js      # Configuration de l'éditeur de texte riche
├── blocks/                # Définitions individuelles des blocs (28 fichiers)
├── components/            # Modèles et vues des composants (28 fichiers)
├── traits/                # Types de traits personnalisés (7 fichiers)
└── plugins/               # Plugins GrapesJS (code-editor)
```

### Blocs disponibles

| Catégorie | Blocs |
|-----------|-------|
| **Structure** | `row`, `column` |
| **Basiques** | `block`, `text`, `link`, `linkImage`, `separator`, `social` |
| **Médias** | `map`, `video`, `barcode`, `gallery`, `storeLocator`, `drive`, `scratch`, `flipcard`, `slider`, `effect` |
| **Formulaires** | `form`, `label`, `input`, `textarea`, `radio`, `checkbox`, `select`, `button` |

### Traits personnalisés

| Trait | Type | Fonction |
|-------|------|----------|
| `uploadImgTrait` | `uploadImg` | Ouvre le modal Asset Manager pour sélection d'image (jpg, jpeg, gif) |
| `storeLocatorCsvTrait` | `csv` | Import CSV/XLS avec magasins (name, address, latitude, longitude, phone, opening_time, link) |
| `galleryTrait` | `gallery` | Gère un tableau d'images stocké en JSON dans `data-images` |
| `effectImgTrait` | `effect` | Sélection d'image unique pour effets particules |
| `selectOptionTrait` | `select-options` | Éditeur textarea pour options select (format: `valeur::libellé`) |
| `textareaTrait` | `textarea` | Textarea standard avec événements keyup |
| `contactsSampleTrait` | `contacts-sample` | Placeholders de variables depuis CSV contacts |

### Composants interactifs

#### Scratch Card (Carte à gratter)
- **Fichiers** : `components/scratch.js` + `views/landing_website/scratch.js`
- **Librairie** : `scratchcard-js`
- **Attributs** :
  - `data-size` : Rayon du pinceau (défaut: 30)
  - `data-percent` : Seuil de révélation (défaut: 80)
  - `data-href` : URL de redirection après révélation
  - `data-img-fg` : Image de dessus (à gratter)
  - `data-img-bg` : Image de dessous (récompense)
- **Persistance** : LocalStorage `scratch-{id}`

#### Flipcard (Carte retournable)
- **Fichiers** : `components/flipcard.js` + `views/landing_website/flipcard.js`
- **Comportement** : Toggle classe `switched` au clic
- **Attributs** : `data-href`, `data-img-fg`, `data-img-bg`
- **Persistance** : LocalStorage `flipcard-{id}`

#### Drive-to-Store (Géolocalisation magasin)
- **Fichiers** : `components/drive.js` + `views/landing_website/drive.js`
- **Fonctionnement** :
  - Géolocalisation via `navigator.geolocation`
  - Calcul de distance Haversine vers le magasin le plus proche
  - Affiche nom, adresse, horaires + boutons (Appeler, Site web, S'y rendre)
- **Attributs** :
  - `data-stores` : Nom du fichier JSON des magasins
  - `data-btn_go_label`, `data-btn_call_label`, `data-btn_website_label` : Libellés boutons
  - `data-btn_go_color`, `data-btn_call_color`, `data-btn_website_color` : Couleurs boutons
  - `data-name_font_size`, `data-address_font_size`, `data-hours_font_size`, `data-btn_font_size` : Tailles police

#### Store Locator (Recherche de magasin)
- **Fichiers** : `components/storeLocator.js` + `views/landing_website/storeLocator.js`
- **Comportement** : Redirige vers page store locator avec paramètres
- **Attributs** : `data-stores`, `data-map_label`, `data-map_label_color`, `data-map_label_font_size`

#### Gallery (Galerie d'images)
- **Fichiers** : `components/gallery.js` + `views/landing_website/galleries.js`
- **Librairie** : PhotoSwipe lightbox
- **Stockage** : Tableau JSON dans `data-images`

#### Slider (Carrousel)
- **Fichiers** : `components/slider.js` + `views/landing_website/slider.js`
- **Librairie** : Bootstrap Carousel
- **Attributs** :
  - `data-images` : Tableau JSON des images
  - `data-interval` : Intervalle en ms (défaut: 5000)
  - `data-chevron-color` : Couleur des flèches (défaut: #ffffff)

#### Effect (Animation particules)
- **Fichiers** : `components/effect.js` + `views/landing_website/effect.js`
- **Comportement** : Animation Canvas de particules (images tombantes/montantes)
- **Attributs** :
  - `data-image` : Image de la particule (JSON)
  - `data-timer` : Durée en ms avant fade out
  - `data-size` : Taille max en px (défaut: 50)
  - `data-nb-items` : Nombre de particules (défaut: 20)
  - `data-scale` : Rétrécissement min en % (défaut: 70)
  - `data-speed` : Vitesse en % (défaut: 100)
  - `data-direction` : Si présent = haut en bas, sinon bas en haut

#### Barcode (Code-barre)
- **Fichier** : `components/barcode.js`
- **Génération** : API BWIP-JS externe
- **Attributs** :
  - `code` : Numéro du code-barre
  - `color` : Couleur hexadécimale
  - `barcode_type` : `ean13` (défaut) ou `ean8`
- **Endpoint API** : `GET /api/barcode?code=...&color=...&barcode_type=...`

### Système de formulaires

#### Attributs du formulaire
- `form-redirect-url` : URL de redirection après soumission
- `form-success` : Message de succès affiché
- `form-email-subject` : Sujet de l'email
- `form-email-sender` : Nom de l'expéditeur
- `form-email-content` : Contenu de l'email

#### Validation côté client (`views/landing_website/forms.js`)
- **Email** : Regex standard
- **Téléphone (France)** : `^(?:(?:\+|00)33|0)\s*[1-9](?:[\s.-]*\d{2}){4}$`
- **Date** : MM/DD/YYYY avec validation jours/mois
- **Numérique** : `^(0|[1-9][0-9]*)$`

#### Traitement backend (`LandingWebsiteController::storeForm`)
- Stocke les résultats dans `landing_website_form_results`
- Envoie notifications via `LandingFormSubmitted` et `LandingFormSubmittedResult`
- Support destinataires via tags (`form_emails`, `form_bcc_emails`)

### Storage Manager (Sauvegarde)

```javascript
storageManager: {
    type: 'remote',
    stepsBeforeSave: 10,  // Sauvegarde automatique tous les 10 changements
    options: {
        remote: {
            urlStore: '/landing_websites/{id}/template/store',
            urlLoad: '/landing_websites/{id}/template/load'
        }
    }
}
```

#### Format de la colonne `gjs`
```json
{
    "html": "<!-- HTML généré -->",
    "css": "/* CSS compilé */",
    "components": [/* Arbre des composants GrapesJS */],
    "styles": [/* Règles de style */]
}
```

### Fichiers backend clés

#### Contrôleur : `app/Http/Controllers/LandingWebsiteController.php` (~980 lignes)
| Méthode | Fonction |
|---------|----------|
| `editGjs()` | Vue éditeur GrapesJS |
| `storeTemplate()` | Sauvegarde JSON du template |
| `loadTemplate()` | Charge JSON du template |
| `storeAsset()` | Upload images via Spatie Media Library |
| `storeForm()` | Traitement soumission formulaire + notifications |
| `storeFormEmails()` | Gestion emails destinataires |
| `getStoresCsv()` | Import CSV magasins |
| `getBarcodeImg()` | Génération code-barre via API externe |
| `showDriveToStore()` | Page drive-to-store |
| `showStoreLocator()` | Page store locator |

#### Modèle : `app/Models/LandingWebsite.php`
- **Traits** : `InteractsWithMedia`, `HasTags`
- **Casts** : `gjs` → array, `is_active` → boolean, `is_template` → boolean
- **Méthodes clés** :
  - `getAssets()` : Retourne les médias pour l'Asset Manager
  - `convertGmGjs()` / `restoreGmGjs()` : Conversion URLs Google Maps
  - `getPageIsActiveAttribute()` : Statut actif hérité du parent
  - `formResults()` : Relation vers `LandingWebsiteFormResult`
  - `children()` / `parent()` : Relations hiérarchiques

#### Service : `app/Services/LandingWebsiteService.php`
| Méthode | Fonction |
|---------|----------|
| `findBy($slug, $token)` | Trouve une landing par slug ShortUrl |
| `shouldBeRedirect($request)` | Vérifie si redirection nécessaire |
| `getShortUrlData($landingWebsites)` | Enrichit avec données ShortUrl API |
| `insertContentPlaceholders($content, $params)` | Remplace `${var}` dans le contenu |

### Hiérarchie Parent-Enfant

Les landing pages supportent une structure hiérarchique :
- **Pages parent** (`parent_id` NULL) peuvent avoir des enfants
- **Pages enfants** héritent du statut actif du parent (`page_is_active`)
- Chaque enfant a son propre ShortUrl et token
- La duplication clone le parent + tous ses enfants

### Points d'entrée JavaScript

- **Éditeur** : `resources/js/views/landing_website_gjs.js` - Initialise GrapesJS
- **Affichage** : `resources/js/views/landing_website_show.js` - Active les composants interactifs

### Import CSV magasins

**Endpoint** : `POST /landing_websites/stores/csv`

**Colonnes obligatoires** :
- `name` : Nom du magasin
- `address` : Adresse
- `latitude` : Latitude (format décimal)
- `longitude` : Longitude (format décimal)

**Colonnes optionnelles** :
- `phone` : Téléphone (format international)
- `opening_time` : Horaires d'ouverture
- `link` : URL personnalisée
- `website` : Site web

**Format** : CSV séparé par point-virgule, encodage ISO-8859-15

---

## Short URLs

Les ShortUrls connectent à une API externe (via `ShortUrlLogic` facade) et sont liés aux landing pages et campagnes.

### Relation avec Landing Pages
- Chaque landing page a un `short_url_api_id`
- Le slug est géré par l'API ShortUrl externe
- Support import/export bulk via Excel

### Service : `app/Services/ShortUrlService.php`
- Communication avec l'API Wellpack SDK
- Gestion CRUD des short URLs
- Synchronisation avec les campagnes

---

## Données géographiques

Le système utilise la hiérarchie géographique française :
- **Régions** > **Départements** > **Villes** > **IRIS** (zones de recensement)

### Commandes Artisan
```bash
# Convertir GeoPackage en GeoJSON
php artisan app:convert-geopackage-to-geojson

# Rafraîchir les données IRIS
php artisan iris:refresh
```

### Source des données
- Téléchargement : https://geoservices.ign.fr/contoursiris
- Stockage : `storage/app/contours-iris-gpkg` et `storage/app/contours-iris-geojson`

---

## Multi-tenancy

Les routes sont organisées autour des Partners :
- La plupart des ressources sont sous `partners/{partner}/`
- Le middleware `partner` gère le contrôle d'accès

---

## Intégrations clés

| Package | Usage |
|---------|-------|
| `wellpack/sdk` | Fonctionnalités SMS et campagnes (repo privé) |
| `laravel/passport` | Authentification OAuth pour API |
| `spatie/laravel-permission` | Gestion des permissions |
| `spatie/laravel-tags` | Système de tags |
| `spatie/laravel-medialibrary` | Gestion des médias/assets |
| `spatie/laravel-translatable` | Modèles traduisibles |
| `maatwebsite/excel` | Import/export Excel |

---

## Commandes courantes

```bash
# Développement (serveur, queue, logs, vite)
composer dev

# Tests
composer test
php artisan test
php artisan test --filter=TestName

# Build assets
npm run build
npm run dev

# Formatage code
./vendor/bin/pint
```
