# System Patterns

Dernière mise à jour : 2026-02-23

## Architecture applicative

```
Utilisateur --> Filament Dashboard (/admin)
                    |
                    v
              Pages Filament (Livewire)
                    |
                    +---> Toggle Lecture / Ecriture (propriété $mode)
                    |
                    v
              LogisticsService (app/Services/)
                    |
                    +---> API Logistics (HTTP POST + X-API-KEY)
                    |     (retry automatique sur ConnectionException)
                    |
                    +---> api_request_logs (MySQL)
                    |     (succès ET échecs)
                    |
                    +---> LogisticsApiException (en cas d'erreur)
```

## Patterns utilisés

### Service centralisé

`App\Services\LogisticsService` encapsule tous les appels HTTP vers l'API Logistics. Chaque méthode publique correspond à un endpoint (19 méthodes). Le service :

- Construit l'URL à partir de `config('logistics.base_url')`, `config('logistics.folder')` et le nom de l'endpoint.
- Ajoute automatiquement le header `X-API-KEY`.
- Configure `timeout()` et `connectTimeout()` depuis la config.
- Effectue un retry automatique (nombre et délai configurables) uniquement sur les `ConnectionException`.
- Enregistre chaque requête dans la table `api_request_logs` (succès et échecs).
- Retourne un tableau PHP avec les clés `data`, `metadata`, `error`.
- Lance une `LogisticsApiException` en cas d'erreur de connexion ou de requête.

### Exception dédiée

`App\Exceptions\LogisticsApiException` (étend `RuntimeException`) fournit :

- Des messages d'erreur en français lisibles par l'utilisateur.
- Des propriétés `endpoint` et `params` pour le contexte de l'erreur.
- Deux méthodes statiques : `connectionTimeout()` (API injoignable) et `requestFailed()` (erreur de requête).

### Pages Filament personnalisées (pas de Resources)

L'application n'utilise pas de Resources Filament (pas de CRUD local). Chaque page Filament :

- Étend `Filament\Pages\Page`.
- Utilise des propriétés Livewire publiques pour les champs de formulaire.
- Possède une propriété `$mode` (string : `'read'` ou `'write'`) pour le toggle Lecture/Ecriture (sauf Dashboard, Documentation, TablesExplorer).
- Appelle `LogisticsService` via `app(LogisticsService::class)` dans des méthodes d'action.
- Attrape `LogisticsApiException` en premier, puis `\Throwable` en fallback.
- Affiche les résultats via les composants du système de design `x-logistics.*`.

### Toggle Lecture / Ecriture

Les pages entité (Articles, Documents, Journaux, Tiers, Divers) intègrent un toggle permettant de basculer entre :

- **Lecture** (`$mode = 'read'`) : formulaires pour les endpoints de récupération de données.
- **Ecriture** (`$mode = 'write'`) : formulaires pour les endpoints d'envoi de données.

Le toggle est implémenté avec deux boutons et un `wire:click="$set('mode', 'read')"` / `wire:click="$set('mode', 'write')"`. Le rendu conditionnel utilise `@if ($mode === 'read')` / `@else`. Les pages sans endpoint d'écriture affichent un état vide (`<x-logistics.empty-state>`) en mode écriture.

### Conversion CSV vers tableaux (splitCsv)

La page Documents utilise une méthode privée `splitCsv(string $value): array` qui convertit les champs de formulaire (texte séparé par virgules) en tableaux PHP pour les paramètres d'API qui attendent des arrays (Artid, Qty, Saleprice, Discount, Vatid, Vatpc). Exemple : `"ART001,ART002"` devient `["ART001", "ART002"]`.

### Traduction et normalisation des erreurs API

`App\Support\ApiErrorTranslator` centralise le traitement des erreurs retournées par l'API :

- **Normalisation** : Le champ `error` de l'API peut être `null`, une chaîne ou un tableau de chaînes. La méthode `normalize()` convertit tout en chaîne lisible.
- **Traduction** : La méthode `translate()` ajoute une explication en français aux messages d'erreur connus (ex: "Search terms are required" -> "Le champ de recherche est obligatoire.").
- **Format de sortie** : Quand une explication est trouvée, le message est formaté sur plusieurs lignes : `{message original}\n\nExplication : {explication}`.

### Validation et tracking des appels API

Chaque page Filament implémente :

- **Validation** : Les champs obligatoires sont vérifiés avant chaque appel API. Si un champ requis est vide, un message d'erreur en français est affiché via `$this->errorMessage` et la méthode retourne sans appeler l'API. Les règles de validation sont basées sur la documentation fournisseur (`documentation/WEB-A-1 (3).md`).
- **Tracking** : Des propriétés booléennes publiques (`$hasSearched`, `$hasCheckedStock`, etc.) sont mises à `true` après chaque appel API (succès ou erreur). Cela permet de distinguer "jamais recherché" de "recherché sans résultat" dans les vues Blade.
- **État vide** : Le composant `json-block` accepte une prop `$searched`. Quand `$searched` est `true` et `$data` est vide, un état vide est affiché. Pour les `data-table`, les vues vérifient `$hasSearched && count($data) === 0`.
- **Badge de comptage** : Les badges de résultats utilisent `count($data)` (comptage réel PHP) au lieu de `$metadata['rowcount']` (retourné par l'API, parfois incorrect).

### Tableaux de référence des paramètres API

Chaque endpoint sur chaque page Filament dispose d'un tableau de référence des paramètres sous le formulaire, implémenté via le composant `<x-logistics.param-table>`. Le composant accepte un tableau `$params` où chaque élément contient `name`, `type`, `required` et `description`. Si le tableau est vide (endpoint sans paramètres), le composant ne rend rien. Les descriptions proviennent de la documentation API et incluent les informations critiques (format obligatoire, limites, sensibilité à la casse).

### Endpoints partiellement fonctionnels

L'endpoint `Document_GetPDF` est fonctionnel : le paramètre `LAYOUT` doit être une valeur numérique sous forme de string (ex: `"1"`). Les valeurs textuelles provoquent une erreur. Le PDF est retourné encodé en base64 dans le champ `data.pdf`.

### Endpoint custom_geninv_updatestock

L'endpoint `custom_geninv_updatestock` est fonctionnel en MODE=1 (Restock). Un bandeau d'avertissement ambre dans l'interface explique les deux modes disponibles et leurs prérequis. Le formulaire inclut un champ THIRDID (obligatoire en mode Restock) et la validation côté client vérifie cette condition. MODE=0 (Inventaire) dépend de la configuration des journaux KI du dossier.

### Page Documentation

`App\Filament\Pages\Documentation` est une page spéciale qui :

- Lit le fichier `documentation/documentation_api_logistics.md` au montage.
- Convertit le markdown en HTML via `Str::markdown()`.
- Affiche le contenu dans une vue avec la classe CSS `.documentation-prose` pour un rendu stylisé.
- Propose deux actions d'en-tête : télécharger en PDF (via `barryvdh/laravel-dompdf`) et ouvrir dans un nouvel onglet.

### Système de design (composants Blade)

Convention documentée dans `.cursor/rules/design-system.mdc`. Tous les composants visuels réutilisables sont dans `resources/views/components/logistics/` :

| Composant | Rôle |
|-----------|------|
| `<x-logistics.card>` | Conteneur blanc arrondi avec ombre et anneau |
| `<x-logistics.section-header>` | En-tête de section (titre, description, slot `actions`) |
| `<x-logistics.error-banner>` | Bandeau d'erreur API conditionnel |
| `<x-logistics.stat-bar>` | Barre horizontale de métadonnées |
| `<x-logistics.stat-item>` | Élément individuel (icône + label + valeur) |
| `<x-logistics.data-table>` | Tableau dynamique avec en-têtes auto-détectés et état vide |
| `<x-logistics.empty-state>` | État vide centré (icône + titre + description) |
| `<x-logistics.search-input>` | Champ de recherche avec icône loupe intégrée |
| `<x-logistics.form-field>` | Champ de formulaire (label + input + padding gauche) à espacement homogène |
| `<x-logistics.json-block>` | Bloc JSON formaté avec bordure et fond adapté |
| `<x-logistics.param-table>` | Tableau de référence des paramètres API (PARAMETRE / TYPE / OBLIGATOIRE / DESCRIPTION) |

Règles :
- Toujours utiliser les composants `x-logistics.*` au lieu de dupliquer les classes CSS.
- Un `<x-logistics.card>` n'a pas de padding interne. Le padding est géré par les enfants (`<div class="p-6">`).
- Le `<x-logistics.section-header>` est le premier enfant d'une carte et crée une bordure de séparation.
- Toutes les actions réseau doivent avoir un indicateur de chargement (`wire:loading`).

### Thème Filament personnalisé

Le panel Filament utilise un thème CSS personnalisé (`resources/css/filament/admin/theme.css`) enregistré via `->viteTheme()` dans `AdminPanelProvider`. Ce thème :

- Importe le CSS de base Filament.
- Active le plugin `@tailwindcss/typography` pour les classes `prose`.
- Scanne les fichiers `app/Filament/**/*`, `resources/views/filament/**/*`, et `resources/views/components/logistics/**/*` pour inclure les classes Tailwind utilisées dans les composants.
- Contient des styles CSS personnalisés pour la classe `.documentation-prose`.

Après tout ajout de nouvelles classes Tailwind dans ces fichiers, il faut exécuter `npm run build`.

### Configuration externalisée

Les paramètres de connexion à l'API (URL, clé, dossier, timeout, retry) sont dans `config/logistics.php` et lus depuis `.env`.

## Structure des répertoires

```
app/
  Exceptions/
    LogisticsApiException.php  # Exception dédiée API
  Filament/
    Pages/
      Articles.php             # Recherche articles + stock (toggle lecture/écriture)
      Dashboard.php            # Page d'accueil
      Divers.php               # Endpoints divers : getserialnumber, codes_list, custom_geninv_updatestock (toggle)
      Documentation.php        # Documentation API (markdown -> HTML)
      Documents.php            # 9 endpoints documents (toggle lecture/écriture, splitCsv)
      Journaux.php             # Recherche journaux (toggle lecture/écriture)
      TablesExplorer.php       # Exploration tables + colonnes (filtre, déduplication, types)
      Tiers.php                # Recherche tiers + historique (toggle lecture/écriture)
  Models/
    User.php                   # Modèle utilisateur (Fortify)
  Providers/
    Filament/
      AdminPanelProvider.php   # Configuration du panel (sans auth, viteTheme)
    FortifyServiceProvider.php # Authentification Fortify
    AppServiceProvider.php     # Config globale (CarbonImmutable, DB safety)
  Services/
    LogisticsService.php       # Service centralisé API Logistics (19 méthodes)
  Support/
    ApiErrorTranslator.php     # Normalisation et traduction des erreurs API

config/
  logistics.php                # Configuration API Logistics (URL, clé, timeout, retry)

documentation/
  documentation_api_logistics.md  # Documentation complète de l'API (avec accents)
  WEB-A-1 (3).md                  # Documentation originale du fournisseur

resources/
  css/
    app.css                    # CSS principal (Tailwind 4, Flux UI)
    filament/admin/
      theme.css                # Thème Filament personnalisé (Tailwind 4 + Typography + prose)
  views/
    components/logistics/      # 11 composants du système de design
    filament/pages/            # 7 vues de pages Filament
    pdf/
      documentation.blade.php  # Template PDF pour la documentation

database/
  migrations/
    ...create_users_table.php
    ...create_cache_table.php
    ...create_jobs_table.php
    ...add_two_factor_columns_to_users_table.php
    ...create_api_request_logs_table.php

tests/Feature/
  ArticlesPageTest.php         # 10 tests page Articles (toggle, validation, tracking, erreurs, barcode)
  DocumentationTest.php        # 5 tests page Documentation (Livewire + PDF)
  DocumentsPageTest.php        # 22 tests page Documents (toggle, 9 endpoints, validation, erreurs, results)
  DiversPageTest.php           # 22 tests page Divers (toggle, 3 endpoints, validation, erreurs, THIRDID conditionnel, modes)
  JournauxPageTest.php         # 7 tests page Journaux (toggle, validation, tracking, erreurs)
  LogisticsServiceTest.php     # 14 tests service API (mocks HTTP)
  TablesExplorerTest.php       # 6 tests page TablesExplorer (Livewire)
  TiersPageTest.php            # 15 tests page Tiers (toggle, validation, tracking, erreurs, métadonnées, casse thirdid)
  FilamentDashboardTest.php    # Tests dashboard Filament (2 tests en échec pré-existant)
  DashboardTest.php            # Tests dashboard
  ExampleTest.php              # Test d'exemple Laravel
tests/Unit/
  ApiErrorTranslatorTest.php   # 9 tests normalisation et traduction des erreurs API

routes/
  web.php                      # Routes web (home, dashboard, documentation PDF)

.cursor/rules/
  design-system.mdc            # Convention de design (composants, CSS, structure)
  memory-bank.mdc              # Gestion du memory bank
  update-documentation.mdc     # Procédure de mise à jour de la documentation
  laravel-boost.mdc            # Règles Laravel Boost
```

## Conventions

- Filament v5 : les icônes de navigation utilisent l'enum `Filament\Support\Icons\Heroicon` (pas de strings).
- Filament v5 : la propriété `$view` est non-static (`protected string $view`).
- Les propriétés statiques (`$navigationIcon`, `$navigationLabel`, `$title`, `$navigationSort`) restent static.
- Les appels API passent toujours par `LogisticsService`, jamais directement par `Http::`.
- Les pages Filament attrapent `LogisticsApiException` en premier, puis `\Throwable` en fallback.
- Les messages d'erreur affichés à l'utilisateur sont en français.
- Toutes les vues Filament utilisent les composants `x-logistics.*` du système de design.
- Après modification des vues ou composants, exécuter `npm run build` pour recompiler le thème.
- Tous les contenus rédigés en français doivent utiliser les accents appropriés.
- L'endpoint custom_geninv_updatestock est fonctionnel en MODE=1 (Restock) avec un bandeau d'information décrivant les modes.
- Chaque endpoint sur chaque page dispose d'un tableau de référence des paramètres via `<x-logistics.param-table>`.
