Files
Ferme/CLAUDE.md
2026-03-18 14:47:03 +01:00

9.5 KiB

CLAUDE.md

Stack

  • Backend: Symfony 8 + API Platform 4 (PHP 8.4)
  • Frontend: Nuxt 4 (Vue 3, Pinia, Tailwind, Zod) in frontend/
  • Infra: Docker (PHP-FPM + Nginx), Apache vhost serves API sous /api et frontend depuis frontend/dist

Commands

# Docker
make start              # Démarrer les containers
make stop               # Arrêter les containers
make restart            # Redémarrer les containers
make shell              # Shell dans le container PHP

# Install complet
make install            # composer install + migrations + build frontend

# Backend
make composer-install   # Installer dépendances PHP
make migration-migrate  # Lancer les migrations
make fixtures           # Charger les fixtures
make cache-clear        # Vider le cache Symfony
make test               # Lancer les tests PHPUnit
make test FILES=tests/path/to/TestFile.php  # Test spécifique
make php-cs-fixer-allow-risky FILES=src/... # Fixer le style

# Frontend
make build-nuxtJS       # npm install + build:dist (dans le container)
make dev-nuxt           # Serveur dev Nuxt (dans le container)
# Ou directement dans frontend/ :
cd frontend && npm run dev     # Dev server (port 3000)
cd frontend && npm run build:dist  # Build production

# Base de données
make db-reset           # ⚠️ Supprime et recrée la BDD + migrations + fixtures

Architecture backend

src/
├── ApiResource/        # Ressources API Platform custom
├── Command/            # Commandes Symfony (dont app:seed)
├── DataFixtures/       # Fixtures Doctrine
├── Dto/                # DTOs (ex: PontBasculeReading)
├── Entity/             # Entités Doctrine (= ressources API Platform)
├── Exception/          # Exceptions custom (PontBasculeException)
├── Kernel.php
├── Service/            # Services métier (PontBasculePayloadDecoder…)
└── State/              # State providers/processors API Platform

Architecture frontend

frontend/
├── components/
│   ├── ui/             # Composants réutilisables, auto-importés avec préfixe Ui (ex: UiLoadingDots)
│   ├── reception/      # Composants métier réception
│   ├── shipment/       # Composants métier expédition
│   ├── workflow/       # Composants partagés réception/expédition (workflow-weight, workflow-waiting-list, workflow-liot-fields)
│   └── commun/         # Composants communs (update-weight)
├── composables/        # useApi, useWeighing, usePdfPrinter, useAppVersion, useLiotHandling, useFormDataLoading, useAddressSync, useWorkflowSteps
│   └── steps/          # useWeighingStep (logique étape pesée)
├── config/             # reception.config.ts, shipment.config.ts (WorkflowConfig)
├── types/              # workflow.ts (interfaces partagées WorkflowEntity, WorkflowConfig, StepDefinition)
├── services/           # Couche service avec DTOs typés dans services/dto/
│   └── workflow-service.ts  # Factory service API (createWorkflowService)
├── stores/             # Pinia stores (reception, shipment, auth)
│   └── workflow-store.ts    # Factory store (useWorkflowStoreLogic)
├── pages/              # Pages Nuxt (file-based routing)
├── layouts/            # Layout default : max-width 1050px
├── i18n/locales/       # Traductions (défaut: fr)
├── utils/              # Constants, zod-errors helpers
└── assets/css/         # Tailwind config, main.css (font Helvetica)

Conventions backend

  • Code en anglais ; "pont-bascule" est un terme métier conservé tel quel.
  • Les opérations API Platform sont définies directement sur les entités Doctrine.
  • Pas de classes Repository custom : utiliser EntityManagerInterface avec les repos par défaut.
  • config/reference.php est auto-généré — ne pas modifier à la main.
  • Endpoints toujours au pluriel (convention API Platform).
  • Ne jamais créer de GET qui crée des ressources : utiliser POST + PATCH.
  • Les noms de Supplier, Customer et Carrier sont automatiquement mis en majuscule via mb_strtoupper dans setName().

Conventions frontend

  • SSR désactivé. Tailwind avec palette custom primary (ex: bg-primary-500).
  • useApi (composables/useApi.ts) : méthodes get/post/put/patch/delete avec content-types par défaut.
    • Toasts personnalisables via toastErrorMessage/toastSuccessMessage ou clés i18n toastErrorKey/toastSuccessKey.
    • Utilise useNuxtApp().$i18n (pas useI18n) pour fonctionner hors setup.
  • Validation formulaires avec Zod ; helpers dans utils/zod-errors.ts.
  • Nav active : NuxtLink avec slot custom.
  • PDFs : usePdfPrinter (receipt réception, rapport poids cases).

Validation required & erreurs visuelles

  • Les champs required utilisent l'attribut HTML natif forwardé via v-bind="attrs" dans les composants UI.
  • La bordure rouge n'apparaît qu'après soumission grâce à la classe CSS submitted ajoutée sur le <form> au clic sur le bouton Valider (@click="submitted = true").
  • Règles CSS globales dans main.css : .submitted :invalid (bordure + texte rouge), .submitted :has(:invalid) > label et .submitted label:has(:invalid) (labels rouges).
  • Pour les validations manuelles (checkboxes, radio groups), les messages d'erreur utilisent invisible (pas hidden) pour garder l'espace réservé et éviter les décalages de layout.
  • Les dates de l'API sont renvoyées au format Y-m-d H:i ; les formulaires utilisent .slice(0, 10) pour extraire la date seule (compatible <input type="date">).

Workflow réception/expédition (mutualisé)

  • Factory service createWorkflowService et factory store useWorkflowStoreLogic pour éviter la duplication.
  • Composables partagés : useLiotHandling (logique LIOT), useFormDataLoading (users, trucks, carriers), useAddressSync (sync adresse fournisseur/client).
  • useWeighing : une seule fonction paramétrée pour réception et expédition (remplace useWeighing + useWeighingShipment).
  • Configs workflow dans config/reception.config.ts et config/shipment.config.ts (étapes, labels pesée, filename PDF).
  • WorkflowWeight composant partagé pour les étapes de pesée (remplace reception-weight.vue et shipment-weight.vue).
  • WorkflowWaitingList composant partagé pour les listes en attente, avec support colonnes dynamiques, slot actions, et prop showActions.

Domaine métier clé

Réception (pesée pont-bascule)

  • Entité principale Reception : date_reception (DateTimeImmutable, format lecture Y-m-d H:i, écriture Y-m-d), identification_number (auto N-BR-####), current_step (défaut 0), is_valid (défaut false).
  • Weight (1-N avec Reception, cascade remove + orphanRemoval) : type (gross/tare), dsd, weight, weighed_at.
  • Endpoint pesée : /receptions/weighPontBasculeReading (dsd, weight, weighedAt).
  • Endpoint suppression : DELETE /receptions/{id} — supprime en cascade weights, pelletBuildings, bovines.
  • Parsing payload pont-bascule : Service/PontBasculePayloadDecoder.php.
  • Exception : PontBasculeException (messages en français, mappée 500).
  • Store Pinia reception.ts = source de vérité pour la réception en cours.
  • UI multi-étapes dans pages/reception/[[id]].vue basée sur currentStep.
  • PrePersist : injecte l'heure courante sur receptionDate à la création ; setReceptionDate préserve l'heure existante au PATCH.

Expédition

  • Entité Shipment : même pattern que Reception, shipment_date (format lecture Y-m-d H:i, écriture Y-m-d).
  • Endpoint suppression : DELETE /shipments/{id}.
  • PrePersist : injecte l'heure courante sur shipmentDate ; setShipmentDate préserve l'heure au PATCH.

LIOT (transport)

  • Si carrier code = LIOT : afficher sélecteurs driver + vehicle, masquer saisie plaque manuelle.
  • Liste véhicules filtrée par type de camion et transporteur.
  • Le véhicule sélectionné alimente license_plate.
  • Logique mutualisée dans composables/useLiotHandling.ts.

Bovins & infrastructure

  • Bovine : nationalNumber (unique), receivedWeight, arrivalDate, buildingCase (ManyToOne).
  • BuildingCase a bovines (OneToMany).
  • Rapport PDF cases : GET /building_cases/{id}/weights-report → template Twig, projection depuis arrivalDate, gain journalier fixe 1.3 kg/jour.

Données de référence

  • ReceptionType, MerchandiseType, PelletType, Building, Supplier (avec Address via join table, createdBy → User), Customer (avec Address via join table, createdBy → User), Truck, Carrier, Driver, Vehicle.
  • Address : champ label nullable (déprécié, retiré du front et du address:write), expose fullAddress via getter. countryCode par défaut FR côté front.

Seed & fixtures

  • Commande app:seed : seed infrastructure (statut, building_layout, building_case, building_case_position) puis bovins.
  • Utilise des flush intermédiaires pour que les queries find fonctionnent sur les records fraîchement créés.
  • upsertAddress cherche par street|postalCode (plus par label).
  • Fixtures : BuildingInfrastructureFixtures + BovineFixtures (via dépendances AppFixtures).

Environnement

  • API base dev : http://localhost:8080/api (via NUXT_PUBLIC_API_BASE dans frontend/.env)
  • CORS : Nelmio, configurable via CORS_ALLOW_ORIGIN dans .env
  • Locale par défaut : fr — traductions dans frontend/i18n/locales/fr.json
  • Docker env : docker/.env.docker (défaut) avec override possible via docker/.env.docker.local