# Prompt d'implémentation — M1 · Ticket 1/3 (Backend) Tu travailles sur le projet **Starseed** (Symfony 8 / API Platform 4 / Doctrine / PostgreSQL). Lis `CLAUDE.md` et `.claude/rules/backend.md` avant de coder. Commentaires en français, code en anglais, `declare(strict_types=1);` partout. ## Mission Supprimer le **contact principal inline** de l'entité `Client` : les 5 champs `firstName`, `lastName`, `phonePrimary`, `phoneSecondary`, `email`. Les contacts sont gérés uniquement via la sous-entité `ClientContact` (onglet Contacts), déjà en place. Le code est déjà en prod → migration avec **backfill** avant `DROP`. La spec détaillée du ticket est dans `docs/specs/M1-clients/refonte-contact/M1-ticket-01-back.md`. Lis-la en entier, ainsi que le `README.md` du même dossier (décision + RG impactées + D1/D2). ## Étapes 1. **Explorer** : `Client.php`, `ClientProcessor.php`, `DoctrineClientRepository.php`, `ClientExportController.php`, `ClientFixtures.php`, et `ClientContact.php` (pour confirmer que la cible porte bien les mêmes champs). 2. **Demander la validation des décisions D1 (recherche) et D2 (export)** avant de coder — défauts recommandés : D1 = LEFT JOIN sur `client_contact`, D2 = colonnes export depuis le contact `position` minimal. Ne pas inventer un autre comportement. 3. **Migration** (`src/Module/Commercial/Infrastructure/Doctrine/Migrations/`) : backfill `INSERT INTO client_contact ... WHERE NOT EXISTS(...)` puis `ALTER TABLE client DROP COLUMN ...` (les 5). `down()` best-effort documenté. Voir le SQL exact dans la spec § 4. 4. **Entité** : retirer les 5 props + getters/setters + `#[ORM\Column]` + `#[Assert\*]` + `#[Groups(['client:read','client:write:main'])]`. 5. **Processor** : retirer de `MAIN_FIELDS`, `changedBusinessFields()`, `normalize()` ; supprimer `validateMainContact()` et son appel. 6. **Repository** : `applySearch()` selon D1. 7. **Export** : `buildHeaders()` / `buildRows()` selon D2. 8. **Fixtures** : alléger `ensureClient()` ; garder `addContact()`. 9. **Tests** : mettre à jour `ClientApiTest`, `ClientFormulaireMainTest`, `ClientExportControllerTest`, `ClientMigrationTest`, `ClientFieldNormalizerTest` (cf. spec § 5). Ajouter une assertion que le backfill crée bien un contact pour un client qui n'en avait pas. ## Garde-fous - Ne touche **pas** `ClientContact`, `ClientContactProcessor`, `ClientFieldNormalizer`. - Respecte les règles ABSOLUES : pagination, `#[Auditable]`, COMMENT ON COLUMN (ici on supprime → pas de commentaire à poser, mais ne pas casser le garde-fou). - Les RG-1.01 et RG-1.02 disparaissent **du Client** : leur équivalent (RG-1.05 / RG-1.14) vit déjà sur `ClientContact`, ne le duplique pas. ## Vérification finale (obligatoire avant de dire « fini ») ```bash make db-reset && make migration-migrate # migration rejouable sur base fraîche make test # PHPUnit vert make php-cs-fixer-allow-risky # lint ``` Puis capture le JSON réel de `GET /api/clients/{id}` (avec un JWT) et confirme que les 5 champs ont disparu de la réponse et que `contacts[]` porte bien l'info (réflexe RETEX M1 : on valide sur le contrat réel, pas sur les annotations).