Les tables `qualimat_carrier` et `qualimat_sync_log` sont des tables DBAL
brutes (referentiel synchronise par `app:qualimat:sync`, hors ORM). Sans
exclusion du `schema_filter`, `doctrine:schema:update --force` (lance par le
bootstrap CI / make test-db-setup juste apres les migrations) les considere
comme orphelines et genere un DROP TABLE -> la base de test perd les tables et
SyncQualimatCommandTest casse (relation qualimat_carrier does not exist).
Meme traitement que `audit_log` : creation/suppression pilotees par migration,
schema_filter les ignore.
- garde-fou anti-desactivation de masse : fetchRemote leve sur un payload
non-list (2xx inattendu) et la commande abandonne sans ecriture si aucune
ligne exploitable, au lieu de soft-delete tout le referentiel
- verrou consultatif pg_try_advisory_lock pour serialiser les runs (anti-overlap)
- deduplication par SIRET dans le mapper (rows_upserted = transporteurs distincts)
- upsert par paquets (INSERT groupe) au lieu d'un aller-retour par ligne
- migration des tables qualimat deplacee vers le namespace modulaire Transport
(+ enregistrement du path dans doctrine_migrations.yaml)
- tests : deduplication + abandon sur source vide
Commande console app:qualimat:sync : récupère les opérateurs de transport agréés depuis l'API publique qualimat.org, normalise et synchronise une table référentielle (upsert sur le SIRET + soft-delete des absents + journal). Prévue pour un cron quotidien.
- migration : tables qualimat_carrier + qualimat_sync_log (COMMENT ON COLUMN sur chaque colonne)
- QualimatRowMapper : normalisation pure (SIRET sans espaces, date dd/mm/yyyy -> ISO, skip sans SIRET) + tests unitaires
- SyncQualimatCommand : options --file / --ppp / --dry-run, upsert DBAL transactionnel
- activation de framework.http_client
- tests fonctionnels de la commande (upsert/normalisation/journal/soft-delete)
Module Transport (ID transport, non requis) destiné à héberger les référentiels externes synchronisés par commandes console (codes IDTF ERP-149, transporteurs QUALIMAT ERP-39).
- TransportModule.php avec permissions() vide à ce stade
- activation dans config/modules.php
- layer Nuxt front minimal (pas d'écran ni d'item sidebar)