Files
Starseed/docs/specs/M4-transporteurs/prompts/WT3-migration-entites.md
T
Matthieu d9313dbec8 feat(transport) : schéma + entités Carrier + contrat lecture (ERP-155/157)
Schéma BDD du répertoire transporteurs (M4) + entités + contrat de lecture
(liste + détail), socle du front.

- Migration Version20260615150000 : tables carrier / carrier_address /
  carrier_contact / carrier_price (FK cross-module, CHECK enum, index partiel
  uq_carrier_name_active, COMMENT ON COLUMN). uploaded_document et
  qualimat_carrier réutilisées (non recréées).
- Entités Carrier* (#[Auditable], Timestampable/Blamable) + ApiResource
  LECTURE seule (GetCollection + Get via CarrierProvider, anti-N+1, exclusion
  archivés + ?includeArchived). Écriture (POST/PATCH + Processor) reportée WT4+.
- QualimatCarrier : mapping ORM lecture seule sur la table référentielle
  existante (sortie du schema_filter, mapping aligné DDL ERP-39, schema:update
  no-op) + endpoint de recherche read-only (§ 4.7).
- Relations cross-module des prix (Client/Supplier/adresses) via contrats
  Shared (ClientInterface, SupplierInterface, ClientAddressInterface,
  SupplierAddressInterface) + resolve_target_entities — sans import inter-module
  (règle n°1). Ajout du groupe supplier_address:read aux champs de
  SupplierAddress pour l'embed.
- Garde-fous : ColumnCommentsCatalog (carrier* + qualimat_carrier), makefile
  test-db-setup (index partiel carrier), i18n audit (transport_carrier*),
  EntitiesAreTimestampableBlamableTest (QualimatCarrier whitelisté).
- CarrierSerializationContractTest : contrat JSON liste + détail vérifié
  (embeds objet, booléens, enveloppe Hydra) ; JSON réel capturé dans
  spec-back § 4.0.bis.

make db-reset OK, make test vert (731), make nuxt-test vert (480),
php-cs-fixer OK.
2026-06-15 19:15:12 +02:00

5.6 KiB

WT3 — Migration + entités Carrier* + ApiResource + Provider (tickets 1.3 + 1.5 / ERP-155 + ERP-157)

Worktree pivot : il livre le CONTRAT JSON qui débloque tout le front. Mode STACK, sans worktree (repo principal) — base = branche de WT2 :

cd /home/matthieu/dev_malio/Starseed && git fetch origin
git checkout -b feat/erp-155-carrier-schema-entities origin/feat/erp-153-rbac

Base : feat/erp-153-rbac (contient ERP-150 + WT1 + RBAC WT2). Quand #111 sera mergé dans develop, la PR de WT3 se recible automatiquement sur develop.


Prompt à coller

Projet Starseed (modular monolith DDD, Symfony 8 / API Platform 4). Lis CLAUDE.md, .claude/rules/backend.md, .claude/rules/architecture.md. Charge le skill backend-entity-conventions (patterns entités/migrations complets).

Mission : créer le schéma BDD du répertoire transporteurs + les entités + le contrat de lecture (liste + détail). Tu poses le contrat JSON sur lequel le front s'appuiera — c'est le livrable critique.

Spec : spec-back.md § 3.2 / 3.3 / 3.4 / 4.0 / 4.1 / 4.2. Miroir = le module Supplier : src/Module/Commercial/Domain/Entity/Supplier*.php, …/Infrastructure/ApiPlatform/State/Provider/SupplierProvider.php, …/Serializer/SupplierReadGroupContextBuilder.php. Carrier vit dans src/Module/Transport/.

Étape A — Migration (migrations/, namespace racine DoctrineMigrations)

  • PAS de migration modulaire : même si la spec dit « modulaire », toute migration va dans migrations/ namespace racine (tri FQCN cassant sinon). Postérieure à la dernière présente — vérifie ls migrations/ (à ce jour Version20260615120000).
  • Tables carrier, carrier_address, carrier_contact, carrier_price + FK : qualimat_carrier, uploaded_document, client, client_address, supplier, supplier_address, site, user.
  • certification_type nullable (null en cas LIOT) + CHECK enum ; CHECK sur container_type, direction, pricing_unit, price_state, branches Prix client/fournisseur.
  • Index partiel uq_carrier_name_active : LOWER(name) WHERE non archivé ET non supprimé.
  • COMMENT ON COLUMN sur TOUTES les colonnes (FR, ≤200 car.) + helper standard pour les 4 colonnes Timestampable/Blamable. Bonus COMMENT ON TABLE.

Étape B — Entités + repos

  • Carrier, CarrierAddress, CarrierContact, CarrierPrice : #[Auditable], implements TimestampableInterface, BlamableInterface + use TimestampableBlamableTrait. Repos *RepositoryInterface (Domain) + Doctrine*Repository (Infrastructure).
  • ApiResource Carrier (attribut sur l'entité, comme Supplier) : GetCollection + Get + Post + Patch avec security (§ 3.3). PAS de Delete.
  • Groupes : carrier:read, carrier:item:read, qualimat:read. Embed au détail (pas IRI) : client:read/client_address:read/supplier:read/supplier_address:read/site:read + qualimatCarrier. ⚠ les adresses de l'onglet Prix sont des ClientAddress/SupplierAddress distinctes.
  • CarrierProvider paginé (ApiPlatform\Doctrine\Orm\Paginator), liste sans cloisonnement site (§ 2.3), anti-N+1 (fetch joins, § 2.11), exclut les archivés par défaut + ?includeArchived=true.
  • Piège booléen : #[SerializedName('isArchived')] sur le getter.

Gardes-fous qui CASSENT make test (à traiter dans CE worktree)

  • ColumnsHaveSqlCommentTest → COMMENT partout + ajouter les blocs carrier, carrier_address, carrier_contact, carrier_price dans src/Shared/Infrastructure/Database/ColumnCommentsCatalog.php (sinon test-db-setup drope les COMMENT).
  • makefile test-db-setup : l'index partiel uq_carrier_name_active n'est PAS exprimé par schema:updateajoute-le à la ligne dbal:run-sql du target test-db-setup du makefile, sinon make test casse.
  • AuditableEntitiesHaveI18nLabelTest → ajoute dans frontend/i18n/locales/fr.json les clés audit.entity.transport_carrier, transport_carrieraddress, transport_carriercontact, transport_carrierprice (clé = strtolower(module)+'_'+strtolower(Entity)).
  • EntitiesAreTimestampableBlamableTest, EntityConstraintsHaveFrenchMessageTest (messages FR + Length.max = longueur colonne), CollectionsArePaginatedTest.

Scope STRICT : schéma + entités + ApiResource lecture + Provider + i18n audit. PAS le Processor d'écriture (→ WT4), PAS les sous-ressources POST/PATCH adresses/contacts/prix (→ WT6/7/8), PAS l'export (→ WT9). Mets un CarrierFixtures minimal (1-2 lignes) juste pour faire tourner tes tests de lecture ; les fixtures complètes sont faites par WT10 — n'y investis pas.

Tests à écrire : liste exclut archivés / ?includeArchived=true ; enveloppe Hydra (member/totalItems) ; isArchived présent dans le JSON ; embeds détail présents (pas IRI).

LIVRABLE GATE : une fois vert, capture le JSON réel liste + détail (curl ou test) et colle-le dans spec-back.md § 4.0.bis. C'est le signal pour démarrer le front. Préviens la conv maître.

Fini quand : make db-reset OK + make test vert + make php-cs-fixer-allow-risky. Commit (--no-verify si test vert), puis ouvre la PR :

git push -u origin feat/erp-155-carrier-schema-entities
tea pr create --base feat/erp-153-rbac --head feat/erp-155-carrier-schema-entities \
  --title "feat(transport) : schéma + entités Carrier + contrat lecture (ERP-155/157)" \
  --description "Migration + entités Carrier* + ApiResource lecture + Provider + i18n audit + contrat JSON. Tickets ERP-155, ERP-157."

Puis labellise via l'API Gitea. Cible develop. Aucune mention IA.