# Prompt d'implémentation — M5 · ERP-182 (1.2) — Migrer le schéma M5 Projet **Starseed**. Tâche **back / migration**. Lis `CLAUDE.md` (règles n°11 et n°12), `.claude/rules/backend.md` (§ Migrations) et la spec : `docs/specs/M5-tickets-pesee/spec-back.md` (§ 3.2, § 3.2.bis, § 2.5, § 2.7). ## Mission Écrire **une** migration Doctrine au namespace racine `DoctrineMigrations` (`migrations/VersionYYYYMMDDHHMMSS.php`, postérieure aux existantes) qui crée tout le schéma M5. ## Étapes 1. **`site.code`** : `ALTER TABLE site ADD COLUMN code VARCHAR(8)` **NULLABLE** → backfill `UPDATE site SET code = LEFT(postal_code, 2) WHERE code IS NULL` → index unique `uq_site_code` (tolère les NULL multiples Postgres). - ⚠ **NE PAS poser `SET NOT NULL` ici.** Sur `make db-reset`, les fixtures `SitesFixtures` insèrent des sites via l'ORM, qui ne connaît `code` que si la propriété est mappée sur l'entité `Site.php` (fait en ERP-183) → sinon `INSERT` sans `code` → violation `NOT NULL` → db-reset plante. Le `NOT NULL` est posé en **ERP-183** (2ᵉ migration) une fois `Site::code` mappé + peuplé. Cf. spec § 2.5. 2. Table **`weighing_ticket_counter (site_id PK → site, last_value INT NOT NULL DEFAULT 0)`** (séquence numéro par site, RG-5.02). 3. Table **`weighbridge_dsd_counter (site_id PK → site, last_value INT NOT NULL DEFAULT 0)`** (compteur DSD par site, RG-5.04). 4. Table **`weighing_ticket`** : copier le DDL de la spec § 3.2 (colonnes `site_id`, `number`, contrepartie `counterparty_type`/`client_id`/`supplier_id`/`other_label`, `immatriculation`/`plate_free_format`, `empty_*`, `full_*`, `net_weight`, `deleted_at` + 4 colonnes Timestampable/Blamable). - Convention `INT GENERATED BY DEFAULT AS IDENTITY`, `TIMESTAMP(0) WITHOUT TIME ZONE` (§ 2.2). - CHECK : `counterparty_type`, `empty_mode`/`full_mode`, et les **3 branches contrepartie** (RG-5.03). - Index unique `(site_id, number)` + index FK (`site`, `client`, `supplier`, `deleted_at`, `created_by`, `updated_by`). 5. **Règle ABSOLUE n°12** : `COMMENT ON COLUMN` (FR, ≤ 200 car., sémantique + RG) sur **chaque** colonne créée — cf. échantillon § 3.2.bis. Les 4 colonnes Timestampable/Blamable via `addStandardTimestampableBlamableComments($schema, 'weighing_ticket')`. Bonus `COMMENT ON TABLE`. 6. Écrire `down()` symétrique (drop tables + drop colonne `site.code`). ## Garde-fous - Noms de colonnes **en minuscules** (Postgres). - FK cross-module (`user`, `client`, `supplier`, `site`) → la migration **doit** vivre au namespace racine (règle n°11), sinon `make db-reset` casse l'ordre. - `ON DELETE` : `site` = RESTRICT, `client`/`supplier` = RESTRICT, `created_by`/`updated_by` = SET NULL, compteurs = CASCADE. ## Vérification - `make db-reset` puis `make migration-migrate` (BDD fraîche) → OK. - `make test` : `ColumnsHaveSqlCommentTest` **vert** (aucune colonne `public` sans `col_description`). - `make php-cs-fixer-allow-risky`.