docs(commercial) : refonte contact — suppression du contact inline (specs M1 + M2)
Le contact principal inline (firstName/lastName/phonePrimary/phoneSecondary/email) est retiré des entités tiers : il vit désormais uniquement dans ClientContact / SupplierContact (onglet Contacts). - M1 (spec-back / spec-front / cahier-test) : contact inline retiré du modèle Client ; RG-1.01 et RG-1.02 marquées supprimées (équivalent RG-1.05 / RG-1.14) ; décisions D1 (recherche) et D2 (export) décrites ; version V1. - M2 (spec-back / spec-front) : contact inline retiré du modèle Supplier dès la conception ; RG-2.01 et RG-2.02 supprimées (équivalent RG-2.04 / RG-2.13) ; version V0.2. Fichiers M2 introduits ici car non encore versionnés sur develop. - docs/specs/M1-clients/refonte-contact/ : décision (README) + tickets (M1 back/front/ specs, M2 specs) + prompts d'implémentation + amendement des tickets M2 existants.
This commit is contained in:
@@ -0,0 +1,135 @@
|
||||
# M1 · Ticket 1/3 (Backend) — Supprimer le contact inline du `Client`
|
||||
|
||||
## 1. Objectif
|
||||
|
||||
Retirer de l'entité `Client` (et de la table `client`) les **5 champs du contact
|
||||
principal inline** : `firstName`, `lastName`, `phonePrimary`, `phoneSecondary`, `email`.
|
||||
La gestion des contacts passe désormais **exclusivement** par la sous-entité
|
||||
`ClientContact` (onglet « Contacts »), déjà en place et déjà porteuse des mêmes champs.
|
||||
|
||||
Le code M1 est **déjà livré en prod** : ce ticket inclut donc une **migration de données**
|
||||
(backfill) pour ne perdre aucune information de contact existante avant de supprimer les
|
||||
colonnes.
|
||||
|
||||
Contexte et justification : voir `README.md` du dossier `refonte-contact`.
|
||||
|
||||
## 2. Périmètre
|
||||
|
||||
### IN
|
||||
|
||||
- Migration Doctrine : **backfill puis suppression** des 5 colonnes de `client`.
|
||||
- `Client` (entité) : supprimer les 5 propriétés, getters/setters, annotations ORM /
|
||||
`Assert` / `Groups`.
|
||||
- `ClientProcessor` : retirer les 5 champs de `MAIN_FIELDS`, `changedBusinessFields()`,
|
||||
`normalize()` ; supprimer `validateMainContact()` (RG-1.01 — n'a plus d'objet).
|
||||
- `DoctrineClientRepository::applySearch()` : trancher D1 (recherche) et l'appliquer.
|
||||
- `ClientExportController` : trancher D2 (colonnes export) et l'appliquer.
|
||||
- `ClientFixtures` : retirer les 5 paramètres inline de `ensureClient()` ; garantir que
|
||||
chaque client seedé possède au moins 1 `ClientContact` (déjà géré par `addContact()`).
|
||||
- Tests PHPUnit : mettre à jour / retirer les cas qui exercent ces 5 champs sur `Client`.
|
||||
|
||||
### OUT
|
||||
|
||||
- Toute modification de `ClientContact` / `ClientContactProcessor` : **inchangés** (c'est la
|
||||
cible, les champs y restent). `ClientFieldNormalizer` reste tel quel (toujours appelé par
|
||||
`ClientContactProcessor`).
|
||||
- Le front (formulaires, vues, types, i18n) → **ticket 2/3**.
|
||||
- Les specs (`spec-back.md`, `spec-front.md`, cahier de test) → **ticket 3/3**.
|
||||
|
||||
## 3. Fichiers à modifier
|
||||
|
||||
| Fichier | Action |
|
||||
|---|---|
|
||||
| `src/Module/Commercial/Domain/Entity/Client.php` | Supprimer props `firstName` (~l.158), `lastName` (~l.163), `phonePrimary` (~l.168), `phoneSecondary` (~l.172), `email` (~l.178) + leurs getters/setters (~l.329-382) + groupes `client:read`/`client:write:main` + `Assert\*`. |
|
||||
| `src/Module/Commercial/Infrastructure/ApiPlatform/State/Processor/ClientProcessor.php` | Retirer les 5 clés de `MAIN_FIELDS` (~l.63) ; de `changedBusinessFields()` (~l.277-281) ; les 6 lignes de `normalize()` qui touchent email/phone/first/last/secondary (~l.433-441) ; supprimer `validateMainContact()` (~l.447-456) et son appel. |
|
||||
| `src/Module/Commercial/Infrastructure/Doctrine/DoctrineClientRepository.php` | `applySearch()` (~l.110-124) : appliquer **D1**. |
|
||||
| `src/Module/Commercial/Infrastructure/Controller/ClientExportController.php` | `buildHeaders()` (~l.94-114) + `buildRows()` (~l.121-143) : appliquer **D2**. |
|
||||
| `src/Module/Commercial/Infrastructure/DataFixtures/ClientFixtures.php` | `ensureClient()` (~l.357-395) : retirer firstName/lastName/phonePrimary/phoneSecondary/email ; conserver `addContact()`. |
|
||||
| `migrations/Version<timestamp>.php` (NOUVELLE) | Backfill + `DROP COLUMN` (cf. § 4). |
|
||||
| `tests/Module/Commercial/**` | Voir § 5. |
|
||||
|
||||
## 4. Migration Doctrine — backfill puis suppression
|
||||
|
||||
> Migration **modulaire** (`src/Module/Commercial/Infrastructure/Doctrine/Migrations/`) : ce
|
||||
> n'est PAS une migration d'initialisation, le schéma `client` / `client_contact` existe
|
||||
> déjà (règle ABSOLUE n°11).
|
||||
|
||||
### `up()`
|
||||
|
||||
1. **Backfill — ne créer un contact que pour les clients qui n'en ont aucun**, afin de ne
|
||||
pas dupliquer le contact déjà recopié à la création (`prefillFirstContact`) :
|
||||
|
||||
```sql
|
||||
INSERT INTO client_contact
|
||||
(client_id, first_name, last_name, phone_primary, phone_secondary, email, position, created_at, updated_at)
|
||||
SELECT c.id, c.first_name, c.last_name, c.phone_primary, c.phone_secondary, c.email, 0, NOW(), NOW()
|
||||
FROM client c
|
||||
WHERE NOT EXISTS (SELECT 1 FROM client_contact cc WHERE cc.client_id = c.id)
|
||||
AND (c.first_name IS NOT NULL OR c.last_name IS NOT NULL);
|
||||
```
|
||||
|
||||
> Le `WHERE ... first_name OU last_name IS NOT NULL` respecte le CHECK
|
||||
> `chk_client_contact_name`. Les rares clients sans nom de contact ET sans contact
|
||||
> existant ne reçoivent pas de ligne (cas théorique : `phone_primary`/`email` étaient
|
||||
> `NOT NULL` mais les noms nullables).
|
||||
|
||||
2. **Supprimer les 5 colonnes** :
|
||||
|
||||
```sql
|
||||
ALTER TABLE client
|
||||
DROP COLUMN first_name,
|
||||
DROP COLUMN last_name,
|
||||
DROP COLUMN phone_primary,
|
||||
DROP COLUMN phone_secondary,
|
||||
DROP COLUMN email;
|
||||
```
|
||||
|
||||
> Pas de `COMMENT ON COLUMN` à poser (on supprime). Vérifier qu'aucun index ne portait
|
||||
> sur `email` (l'index unique `uq_client_email_active` a déjà été supprimé — décision Q4 /
|
||||
> RG-1.17, cf. `ClientMigrationTest`).
|
||||
|
||||
### `down()` (best-effort)
|
||||
|
||||
1. Recréer les 5 colonnes (`phone_primary`/`email` en `NOT NULL` impose un défaut transitoire
|
||||
ou un re-remplissage depuis le contact `position = 0`).
|
||||
2. Re-remplir depuis `client_contact` (`position = 0`) si possible.
|
||||
3. Reposer les `COMMENT ON COLUMN` d'origine (textes RG-1.19/1.20/1.21/1.01/1.17 — cf.
|
||||
`migrations/Version20260601000000.php` l.251-255).
|
||||
|
||||
> `down()` ne peut pas restaurer parfaitement les données (ambiguïté si plusieurs contacts).
|
||||
> Documenter cette limite dans le docblock de la migration.
|
||||
|
||||
## 5. Tests à mettre à jour
|
||||
|
||||
| Fichier | Action |
|
||||
|---|---|
|
||||
| `tests/Module/Commercial/Api/ClientApiTest.php` | Retirer firstName/lastName/phone/email des payloads POST/PATCH `client` et des assertions JSON. |
|
||||
| `tests/.../ClientFormulaireMainTest.php` | Supprimer les tests RG-1.01 (firstName/lastName) et RG-1.02 (téléphones) **côté Client** — ils basculent côté `ClientContact` (couverts ailleurs). |
|
||||
| `tests/.../ClientExportControllerTest.php` | Aligner les en-têtes/lignes attendus sur **D2**. |
|
||||
| `tests/.../ClientMigrationTest.php` | Asserter que les 5 colonnes **n'existent plus** sur `client` ; vérifier le backfill (un client sans contact obtient bien 1 `client_contact`). |
|
||||
| `tests/.../ClientFieldNormalizerTest.php` | Conserver les tests du normalizer (toujours utilisé par `ClientContact`) ; retirer les cas spécifiques aux champs `Client` s'il y en a. |
|
||||
| RG-1.01/1.02 (matrice) | Ne plus tester sur `Client` ; vérifier qu'ils restent couverts sur `ClientContact` (RG-1.05). |
|
||||
|
||||
## 6. Décisions à trancher (cf. README § 3)
|
||||
|
||||
- **D1 — recherche** : recommandé = `LEFT JOIN client_contact` (fuzzy sur
|
||||
`companyName` + contact `first_name`/`last_name`/`email`). Attention au `DISTINCT` /
|
||||
risque de doublons de lignes si plusieurs contacts matchent (grouper par `client.id`).
|
||||
- **D2 — export** : recommandé = alimenter les colonnes contact depuis le contact de plus
|
||||
petit `position` (fetch-join `contacts` pour éviter le N+1).
|
||||
|
||||
## 7. Critères d'acceptation (DoD)
|
||||
|
||||
- [ ] Les colonnes `first_name`, `last_name`, `phone_primary`, `phone_secondary`, `email`
|
||||
n'existent plus sur la table `client`.
|
||||
- [ ] La migration est jouable sur une base seedée sans perte de contact (backfill vérifié)
|
||||
et `down()` documenté comme best-effort.
|
||||
- [ ] `Client`, `ClientProcessor`, `DoctrineClientRepository`, `ClientExportController`,
|
||||
`ClientFixtures` ne référencent plus les 5 champs.
|
||||
- [ ] D1 et D2 implémentées conformément à la décision validée.
|
||||
- [ ] `ClientContact` / `ClientContactProcessor` / `ClientFieldNormalizer` inchangés.
|
||||
- [ ] `make test` vert (notamment `tests/Architecture/ColumnsHaveSqlCommentTest` et
|
||||
`EntitiesAreTimestampableBlamableTest`).
|
||||
- [ ] `make php-cs-fixer-allow-risky` ne signale rien sur les fichiers touchés.
|
||||
- [ ] Aucune régression du contrat de sérialisation : capturer le JSON réel de
|
||||
`GET /api/clients/{id}` et vérifier l'absence des 5 champs (réflexe RETEX M1).
|
||||
@@ -0,0 +1,58 @@
|
||||
# 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).
|
||||
@@ -0,0 +1,74 @@
|
||||
# M1 · Ticket 2/3 (Frontend) — Retirer le bloc contact principal des écrans Client
|
||||
|
||||
## 1. Objectif
|
||||
|
||||
Retirer le **bloc « contact principal »** (Nom, Prénom, Téléphone, Téléphone 2, Email) des
|
||||
trois écrans Client — **création**, **consultation**, **modification** — ainsi que des
|
||||
types, mappeurs, validations et clés i18n associés. La saisie des contacts se fait
|
||||
désormais uniquement dans l'**onglet « Contacts »** (composant `ClientContactBlock`, déjà
|
||||
en place et inchangé).
|
||||
|
||||
Dépend du **ticket 1/3 (back)** : l'API ne renvoie/n'accepte plus ces 5 champs sur `client`.
|
||||
Contexte : voir `README.md` du dossier `refonte-contact`.
|
||||
|
||||
## 2. Périmètre
|
||||
|
||||
### IN — fichiers `frontend/modules/commercial/`
|
||||
|
||||
| Fichier | Action |
|
||||
|---|---|
|
||||
| `pages/clients/new.vue` | Supprimer le bloc principal Nom/Prénom/Téléphones/Email (~l.27-63), l'état `main.firstName/lastName/email`, `mainPhones` (~l.445-459), la fonction `prefillFirstContact()` (~l.658-665) et son appel, le mapping payload POST `phonePrimary/phoneSecondary` (~l.513-524). Adapter `isMainValid` (~l.479-493) : la validation principale ne porte plus que sur `companyName` (+ relation/catégories selon RG existantes). L'onglet **Contacts** devient le point de saisie des coordonnées ; garantir au moins un `ClientContactBlock` vide au départ. |
|
||||
| `pages/clients/[id]/edit.vue` | Supprimer les 5 champs du bloc principal (~l.32-73). `mapMainDraft()` et `buildMainPayload()` ne portent plus ces champs. L'onglet Contacts reste éditable. |
|
||||
| `pages/clients/[id]/index.vue` | Supprimer l'affichage lecture seule des 5 champs du bloc principal (~l.49-104, partie contact). Conserver l'onglet Contacts (lecture seule). |
|
||||
| `types/clientForm.ts` | `MainFormDraft` : retirer `firstName`, `lastName`, `email`, `phonePrimary`, `phoneSecondary`, `hasSecondaryPhone`. Garder `ContactFormDraft` (inchangé). |
|
||||
| `types/clientConsultation.ts` | `ClientDetail` : retirer `firstName/lastName/phonePrimary/phoneSecondary/email` (les commentaires « Contact principal »). Garder `ContactRead`. |
|
||||
| `utils/clientEdit.ts` | `mapMainDraft()` et `buildMainPayload()` : retirer les 5 champs. Garder `buildContactPayload()`. |
|
||||
| `utils/clientConsultation.ts` | Retirer toute lecture des 5 champs inline du client (garder `mapContactToDraft`, `contactOptionsOf`). |
|
||||
| `i18n/locales/fr.json` | Retirer `commercial.clients.form.main.firstName/lastName/email/phonePrimary/phoneSecondary/addPhone`. **Conserver** tout le bloc `commercial.clients.form.contact.*`. Vérifier qu'aucune autre vue ne référence les clés retirées. |
|
||||
| `**/__tests__/*.spec.ts` | Mettre à jour `clientFormRules.spec.ts`, `clientEdit.spec.ts`, `clientConsultation.spec.ts` (cf. § 4). |
|
||||
|
||||
### OUT
|
||||
|
||||
- `ClientContactBlock.vue`, l'onglet Contacts, `useClient`, la liste/répertoire
|
||||
(`pages/clients/index.vue` — ses colonnes n'affichent déjà pas le contact inline) :
|
||||
**inchangés**.
|
||||
- Le back → ticket 1/3. Les specs → ticket 3/3.
|
||||
|
||||
## 3. Comportement attendu après modification
|
||||
|
||||
- **Création** : le formulaire principal demande l'entreprise (et relation/catégories selon
|
||||
l'existant), plus de Nom/Prénom/Téléphone/Email inline. L'utilisateur renseigne les
|
||||
coordonnées dans l'onglet **Contacts**. La création reste valide tant qu'il y a
|
||||
`companyName` **et** ≥ 1 bloc Contact valide (Nom OU Prénom) — RG-1.05/RG-1.14 inchangées.
|
||||
- **Consultation** : plus de bloc contact principal ; l'onglet Contacts affiche les
|
||||
contacts.
|
||||
- **Modification** : idem ; le PATCH du groupe `client:write:main` n'envoie plus les 5
|
||||
champs.
|
||||
|
||||
## 4. Tests Vitest à mettre à jour
|
||||
|
||||
- `clientFormRules.spec.ts` : la validité du « principal » ne dépend plus de
|
||||
firstName/email/phone ; conserver `isContactNamed()` (RG-1.05) sur les blocs Contacts.
|
||||
- `clientEdit.spec.ts` : `buildMainPayload()` ne contient plus les 5 champs ; `mapMainDraft()`
|
||||
non plus.
|
||||
- `clientConsultation.spec.ts` : retirer les assertions sur les 5 champs inline.
|
||||
|
||||
## 5. Tips & rappels projet
|
||||
|
||||
- `useApi()` obligatoire (jamais `$fetch`/`ofetch`). Composants `Malio*` obligatoires.
|
||||
- État de tableau jamais dans l'URL (règle inchangée).
|
||||
- Les valeurs sont **normalisées côté serveur** (Capitalize / chiffres / lowercase) : le
|
||||
front envoie la saisie et réaffiche la valeur renvoyée — ne pas réintroduire de
|
||||
normalisation front.
|
||||
- Ne pas créer de clé i18n orpheline ni laisser de clé `form.main.*` morte.
|
||||
|
||||
## 6. Critères d'acceptation (DoD)
|
||||
|
||||
- [ ] Les 3 écrans n'affichent plus Nom/Prénom/Téléphone/Téléphone 2/Email en bloc principal.
|
||||
- [ ] Le parcours de création fonctionne avec `companyName` + onglet Contacts (≥ 1 contact).
|
||||
- [ ] `MainFormDraft` / `ClientDetail` ne déclarent plus les 5 champs ; `mapMainDraft` /
|
||||
`buildMainPayload` non plus.
|
||||
- [ ] Aucune clé i18n `form.main.firstName/lastName/email/phone*` restante ni référencée.
|
||||
- [ ] `make nuxt-test` vert.
|
||||
- [ ] Vérification visuelle du golden path (`make dev-nuxt`, port 3004) : création →
|
||||
consultation → modification d'un client sans bloc contact inline.
|
||||
@@ -0,0 +1,47 @@
|
||||
# Prompt d'implémentation — M1 · Ticket 2/3 (Frontend)
|
||||
|
||||
Projet **Starseed** (Nuxt 4 / Vue 3 Composition API / TypeScript / @malio/layer-ui).
|
||||
Lis `CLAUDE.md` et `.claude/rules/frontend.md` avant de coder. Commentaires en français,
|
||||
code en anglais, 4 espaces d'indentation.
|
||||
|
||||
## Mission
|
||||
|
||||
Retirer le **bloc « contact principal »** (Nom, Prénom, Téléphone, Téléphone 2, Email) des
|
||||
écrans Client (création / consultation / modification) et de tout le code associé (types,
|
||||
mappeurs, validations, i18n). Les contacts restent gérés par l'onglet **Contacts**
|
||||
(`ClientContactBlock`, inchangé).
|
||||
|
||||
Spec détaillée : `docs/specs/M1-clients/refonte-contact/M1-ticket-02-front.md` (lis-la en
|
||||
entier + le `README.md` du dossier). Ce ticket dépend du ticket back (l'API ne porte plus
|
||||
les 5 champs sur `client`).
|
||||
|
||||
## Étapes
|
||||
|
||||
1. Explorer `frontend/modules/commercial/` : `pages/clients/new.vue`, `[id]/edit.vue`,
|
||||
`[id]/index.vue`, `types/clientForm.ts`, `types/clientConsultation.ts`,
|
||||
`utils/clientEdit.ts`, `utils/clientConsultation.ts`, `i18n/locales/fr.json`.
|
||||
2. Supprimer le bloc principal des 3 écrans + l'état réactif `main.firstName/lastName/email`,
|
||||
`mainPhones`, `prefillFirstContact()`.
|
||||
3. Adapter `isMainValid` : ne dépend plus que de `companyName` (+ relation/catégories selon
|
||||
l'existant). La garantie « ≥ 1 contact valide » reste portée par l'onglet Contacts.
|
||||
4. Nettoyer les types (`MainFormDraft`, `ClientDetail`) et les mappeurs (`mapMainDraft`,
|
||||
`buildMainPayload`, `clientConsultation`).
|
||||
5. Retirer les clés i18n `form.main.firstName/lastName/email/phonePrimary/phoneSecondary/addPhone` ;
|
||||
vérifier par recherche qu'aucune vue ne les utilise plus. **Garder** `form.contact.*`.
|
||||
6. Mettre à jour les specs Vitest (`clientFormRules`, `clientEdit`, `clientConsultation`).
|
||||
|
||||
## Garde-fous
|
||||
|
||||
- `useApi()` uniquement ; composants `Malio*` uniquement ; pas d'état tableau dans l'URL.
|
||||
- Ne touche pas `ClientContactBlock.vue`, l'onglet Contacts, ni la liste/répertoire.
|
||||
- Pas de normalisation front (le serveur normalise).
|
||||
|
||||
## Vérification finale
|
||||
|
||||
```bash
|
||||
make nuxt-test # Vitest vert
|
||||
make dev-nuxt # port 3004 — golden path manuel
|
||||
```
|
||||
|
||||
Golden path à vérifier dans le navigateur : créer un client (entreprise + 1 contact dans
|
||||
l'onglet Contacts), le consulter, le modifier — sans aucun bloc contact inline.
|
||||
@@ -0,0 +1,51 @@
|
||||
# M1 · Ticket 3/3 (Specs) — Acter la suppression du contact inline dans les specs M1
|
||||
|
||||
## 1. Objectif
|
||||
|
||||
Mettre à jour la **documentation fonctionnelle/technique M1** pour refléter la décision :
|
||||
le contact principal inline est supprimé du `Client`, les contacts vivent uniquement dans
|
||||
`ClientContact`. Les specs sont la **source de vérité** du projet (cf. `workflow.md`) : elles
|
||||
doivent décrire le modèle cible, pas l'ancien.
|
||||
|
||||
> Idéalement réalisé **avant** les tickets 1 et 2 (la spec guide le code), mais peut être
|
||||
> fait en parallèle. À minima, ne pas merger le code sans aligner la spec.
|
||||
|
||||
## 2. Fichiers à modifier
|
||||
|
||||
| Fichier | Sections concernées |
|
||||
|---|---|
|
||||
| `docs/specs/M1-clients/spec-back.md` | § 3.1 diagramme E-R (retirer les 5 colonnes du bloc `client`) ; § 3.2 migration SQL `CREATE TABLE client` (retirer `first_name`/`last_name`/`phone_primary`/`phone_secondary`/`email` + leurs COMMENT) ; § 3.4 squelette entité `Client` (retirer les 5 props) ; § 4.3 exemple payload `POST /api/clients` (retirer les 5 champs) ; § 4.1 filtre `?search=` (refléter D1) ; § 4.6 export (refléter D2) ; § 7 RG (voir § 3 ci-dessous) ; § 8 cahier de tests (déplacer RG-1.01/1.02 vers ClientContact). |
|
||||
| `docs/specs/M1-clients/spec-front.md` | « Formulaire principal » (l.85-103) : retirer les lignes Nom/Prénom/Téléphone/Téléphone 2/Email ; écrans Consultation / Modification ; règles de formatage. Préciser que les coordonnées se saisissent dans l'onglet Contact. |
|
||||
| `docs/specs/M1-clients/cahier-test-back-M1.md` | Retirer / requalifier les lignes RG-1.01 et RG-1.02 (désormais couvertes par RG-1.05 sur `ClientContact`). |
|
||||
|
||||
## 3. Traitement des règles de gestion
|
||||
|
||||
- **RG-1.01** (firstName OU lastName obligatoire sur Client) → marquer **supprimée** :
|
||||
« Remplacée par RG-1.05 (≥ 1 contact valide) + RG-1.14 (≥ 1 bloc Contact). Le contact
|
||||
principal inline n'existe plus. »
|
||||
- **RG-1.02** (max 2 téléphones sur Client) → marquer **supprimée du Client** (reste
|
||||
applicable aux blocs `ClientContact`).
|
||||
- **RG-1.19 / RG-1.20 / RG-1.21** (normalisation) → préciser que le **scope `Client`
|
||||
disparaît** ; la normalisation reste sur `ClientContact` (et `ClientAddress.billingEmail`
|
||||
pour RG-1.21).
|
||||
- Ne **pas renuméroter** les RG existantes (éviter le drift avec le code/tests) : marquer
|
||||
« supprimée / requalifiée » en place, avec date et renvoi à la décision.
|
||||
|
||||
## 4. Forme
|
||||
|
||||
- Bumper la version des deux specs (`version: V0` → `V1`) dans le frontmatter, avec une
|
||||
entrée d'historique : date `2026-06-03`, motif « Suppression du contact inline du Client
|
||||
(refonte-contact) », auteur.
|
||||
- Ajouter un encadré « Décision » en tête de la section modèle de données, renvoyant au
|
||||
`README.md` du dossier `refonte-contact`.
|
||||
- Conserver le style des specs (sections numérotées, tableaux RG, exemples JSON).
|
||||
|
||||
## 5. Critères d'acceptation (DoD)
|
||||
|
||||
- [ ] `spec-back.md` : aucune mention des 5 colonnes inline dans le modèle `client`
|
||||
(E-R + SQL + entité + payload) ; RG-1.01/1.02 marquées supprimées ; D1/D2 décrites.
|
||||
- [ ] `spec-front.md` : le formulaire principal ne liste plus les champs de contact ;
|
||||
l'onglet Contact est présenté comme seul lieu de saisie des coordonnées.
|
||||
- [ ] `cahier-test-back-M1.md` : RG-1.01/1.02 retirées/requalifiées.
|
||||
- [ ] Versions bumpées (V1) + historique daté dans les deux specs.
|
||||
- [ ] Cohérence vérifiée avec les tickets 1 et 2 (mêmes décisions D1/D2).
|
||||
@@ -0,0 +1,38 @@
|
||||
# Prompt d'implémentation — M1 · Ticket 3/3 (Specs)
|
||||
|
||||
Projet **Starseed**. Tâche **documentaire** : mettre à jour les specs M1 Clients pour acter
|
||||
la suppression du contact principal inline du `Client`. Les specs sont la source de vérité ;
|
||||
elles doivent décrire le modèle cible.
|
||||
|
||||
## Mission
|
||||
|
||||
Modifier `docs/specs/M1-clients/spec-back.md`, `spec-front.md` et `cahier-test-back-M1.md`
|
||||
pour retirer le contact inline du `Client` (5 champs `firstName/lastName/phonePrimary/
|
||||
phoneSecondary/email`) — les contacts vivent uniquement dans `ClientContact`.
|
||||
|
||||
Spec du ticket : `docs/specs/M1-clients/refonte-contact/M1-ticket-03-specs.md` (lis-la + le
|
||||
`README.md` du dossier, qui contient la décision, les RG impactées et les décisions D1/D2).
|
||||
|
||||
## Étapes
|
||||
|
||||
1. Lire les 3 fichiers de specs M1 visés, repérer toutes les occurrences des 5 champs
|
||||
(diagramme E-R, CREATE TABLE client, squelette entité, payload POST, filtre search,
|
||||
export, RG, cahier de test).
|
||||
2. Retirer les 5 colonnes du modèle `client` (E-R + SQL + entité + exemple JSON).
|
||||
3. Marquer **supprimées** RG-1.01 et RG-1.02 (renvoi à RG-1.05/RG-1.14 sur `ClientContact`),
|
||||
restreindre le scope de RG-1.19/1.20/1.21 à `ClientContact`. **Ne pas renuméroter** les RG.
|
||||
4. Refléter les décisions D1 (recherche) et D2 (export) une fois tranchées.
|
||||
5. Côté `spec-front.md` : retirer les champs de contact du formulaire principal ; présenter
|
||||
l'onglet Contact comme seul lieu de saisie.
|
||||
6. Bumper `version: V0 → V1` + ajouter une entrée d'historique datée (2026-06-03).
|
||||
|
||||
## Garde-fous
|
||||
|
||||
- Ne touche pas au code, uniquement aux `.md` de specs.
|
||||
- Garde le style existant (sections numérotées, tableaux RG, exemples JSON).
|
||||
- Cohérence stricte avec les tickets 1 (back) et 2 (front) : mêmes décisions D1/D2.
|
||||
|
||||
## Vérification
|
||||
|
||||
Relire les 3 fichiers : plus aucune mention des 5 champs inline dans le modèle `client` ;
|
||||
RG-1.01/1.02 marquées supprimées ; versions à V1 avec historique.
|
||||
@@ -0,0 +1,57 @@
|
||||
# Amendement des tickets M2 existants — suppression du contact inline du `Supplier`
|
||||
|
||||
Les 14 tickets M2 (n° 84–97, groupe Lesstime « M2 — Répertoire fournisseurs ») ont été
|
||||
rédigés sur le modèle initial **avec** contact inline. La décision `refonte-contact` les
|
||||
amende : `Supplier` ne porte **plus** les 5 champs `firstName/lastName/phonePrimary/
|
||||
phoneSecondary/email` ; les contacts vivent uniquement dans `SupplierContact` (onglet
|
||||
Contacts). Comme M2 n'est pas codé, il suffit de **ne jamais créer** ces colonnes/champs.
|
||||
|
||||
## Bandeau injecté en tête des tickets impactés
|
||||
|
||||
> ⚠️ **AMENDEMENT 2026-06-03 — refonte-contact.** Le contact principal inline est
|
||||
> **supprimé** du `Supplier` : ne pas créer/saisir les colonnes ni les champs `firstName`,
|
||||
> `lastName`, `phonePrimary`, `phoneSecondary`, `email` sur l'entité/le formulaire
|
||||
> `Supplier`. Les contacts sont gérés **uniquement** via `SupplierContact` (onglet
|
||||
> Contacts). RG-2.01 et RG-2.02 sont supprimées (équivalent assuré par RG-2.04 / RG-2.13).
|
||||
> RG-2.12 ne s'applique qu'à `companyName` + `SupplierContact`. Décisions transverses
|
||||
> recherche (D1) et export (D2) : cf. `docs/specs/M1-clients/refonte-contact/README.md`.
|
||||
|
||||
## Tickets à amender
|
||||
|
||||
### Back
|
||||
|
||||
| Ticket | n° | Impact |
|
||||
|---|---|---|
|
||||
| migration BDD M2 (supplier + sous-collections) | #85 | Retirer `first_name/last_name/phone_primary/phone_secondary/email` du `CREATE TABLE supplier` et leurs `COMMENT ON COLUMN`. `supplier_contact` inchangé. |
|
||||
| entités + repositories M2 | #86 | `Supplier` : retirer les 5 props + `Assert\Callback` RG-2.01. `SupplierContact` inchangé. |
|
||||
| SupplierProvider + SupplierProcessor | #87 | Retirer la validation RG-2.01, la normalisation des champs inline, leur présence dans `MAIN_FIELDS` / changedFields. Recherche selon D1. |
|
||||
| export XLSX fournisseurs | #91 | Colonnes contact selon D2 (depuis le contact principal, ou supprimées). |
|
||||
| tests PHPUnit M2 | #92 | RG-2.01/2.02 testées sur `SupplierContact` (pas `Supplier`) ; contrat de sérialisation sans les 5 champs inline sur le supplier. |
|
||||
|
||||
### Front
|
||||
|
||||
| Ticket | n° | Impact |
|
||||
|---|---|---|
|
||||
| page Ajouter un fournisseur (`/suppliers/new`) + `useSupplierForm` | #94 | Retirer le bloc contact principal du formulaire + le pré-remplissage du 1er contact. Saisie des coordonnées dans l'onglet Contacts. |
|
||||
| page Consultation fournisseur (`/suppliers/{id}`) | #95 | Retirer l'affichage du bloc contact principal. |
|
||||
| page Modification fournisseur (`/suppliers/{id}/edit`) | #96 | Retirer les 5 champs du bloc principal ; payload `supplier:write:main` sans ces champs. |
|
||||
|
||||
### Léger
|
||||
|
||||
| Ticket | n° | Impact |
|
||||
|---|---|---|
|
||||
| page Répertoire fournisseurs + datatable | #93 | Recherche « nom / contact / email » selon D1. Datatable : colonnes inchangées (pas de contact inline en colonne). |
|
||||
| i18n + sidebar fournisseurs | #97 | Ne pas créer les clés i18n `form.main.firstName/lastName/email/phone*` (garder `form.contact.*`). |
|
||||
|
||||
## Tickets NON impactés
|
||||
|
||||
- #84 (taxonomie FOURNISSEUR), #88 (sous-ressources contacts/adresses/ribs —
|
||||
`SupplierContact` est la cible, inchangé), #89 (validators Information Commerciale /
|
||||
catégorie / RG-2.07-2.08), #90 (RBAC fournisseurs).
|
||||
|
||||
## Méthode d'amendement
|
||||
|
||||
Pour chaque ticket impacté : **préfixer** la description existante du bandeau ci-dessus
|
||||
(sans rien supprimer du contenu d'origine), via `mcp__lesstime__update-task`
|
||||
(`description` = bandeau + description actuelle). La méthode préserve l'historique et reste
|
||||
réversible (retirer le bandeau).
|
||||
@@ -0,0 +1,55 @@
|
||||
# M2 · Ticket Specs — Retirer le contact inline du `Supplier` dans les specs M2
|
||||
|
||||
## 1. Objectif
|
||||
|
||||
Mettre à jour les specs **M2 Fournisseurs** déjà rédigées pour **ne plus inclure** le contact
|
||||
principal inline sur le `Supplier`. M2 est le jumeau strict de M1 (`Supplier` /
|
||||
`SupplierContact` / `SupplierAddress` / `SupplierRib`) et n'est **pas encore codé** : il faut
|
||||
donc corriger la conception **en amont**, pour que les 14 tickets M2 « prêts à dev » soient
|
||||
implémentés directement sans les 5 colonnes inline.
|
||||
|
||||
> Pendant de M1 ticket 3/3, mais côté M2 : **aucune migration de suppression ni backfill** —
|
||||
> on retire simplement le contact inline du modèle cible. Contexte : `README.md` du dossier
|
||||
> `refonte-contact`.
|
||||
|
||||
## 2. Fichiers à modifier
|
||||
|
||||
| Fichier | Sections concernées |
|
||||
|---|---|
|
||||
| `docs/specs/M2-suppliers/spec-back.md` | § 3.1 diagramme E-R (l.175-179 : retirer les 5 colonnes du bloc `supplier`) ; § 3.2 `CREATE TABLE supplier` (l.227-231) ; § 3.4 squelette entité `Supplier` (l.496-517 : props + `Assert\Callback` RG-2.01) ; § 4 exemples payload POST/GET (l.782-805, 867-871) ; recherche `?search=` (l.847 : refléter D1) ; export (refléter D2) ; § contrat de sérialisation (l.725, 729) ; § 7 RG (voir § 3). |
|
||||
| `docs/specs/M2-suppliers/spec-front.md` | « Formulaire principal » (l.105-117 : retirer Nom/Prénom/Téléphone/Téléphone 2/Email) ; onglet « Contact » (l.140-157 : retirer la phrase de pré-remplissage depuis le formulaire principal, l.142) ; écrans Consultation/Modification ; règles de formatage (l.283-285) ; recherche (l.76 : refléter D1). |
|
||||
|
||||
## 3. Traitement des règles de gestion M2
|
||||
|
||||
- **RG-2.01** (firstName OU lastName obligatoire sur Supplier) → **supprimée** : remplacée
|
||||
par RG-2.04 (≥ 1 contact valide) + RG-2.13 (≥ 1 bloc Contact). Le contact inline n'existe
|
||||
plus sur `Supplier`.
|
||||
- **RG-2.02** (max 2 téléphones sur Supplier) → **supprimée du Supplier** (reste sur
|
||||
`SupplierContact`).
|
||||
- **RG-2.12** (normalisation Capitalize / chiffres / lowercase) → restreindre le scope :
|
||||
s'applique à `companyName` (UPPERCASE) et aux champs de `SupplierContact` ; **plus** aux
|
||||
champs inline du `Supplier` (qui disparaissent).
|
||||
- Ne pas renuméroter les RG : marquer « supprimée / requalifiée » en place, avec date.
|
||||
|
||||
## 4. Forme
|
||||
|
||||
- Bumper la version des deux specs M2 + entrée d'historique datée (2026-06-03, motif
|
||||
« Suppression du contact inline du Supplier — alignement refonte-contact M1 »).
|
||||
- Encadré « Décision » renvoyant au `README.md` du dossier `refonte-contact`.
|
||||
- Garder le style des specs M2.
|
||||
|
||||
## 5. Lien avec les tickets M2 existants
|
||||
|
||||
La mise à jour des specs doit être cohérente avec l'**amendement des tickets M2** (voir
|
||||
`M2-amendement-tickets.md`) : tickets back #85/#86/#87/#91/#92 et front #94/#95/#96 (+ #93/#97
|
||||
légers). Specs et tickets décrivent le **même** modèle cible (sans contact inline).
|
||||
|
||||
## 6. Critères d'acceptation (DoD)
|
||||
|
||||
- [ ] `spec-back.md` M2 : aucune mention des 5 colonnes inline dans le modèle `supplier`
|
||||
(E-R + SQL + entité + payloads + sérialisation) ; RG-2.01/2.02 marquées supprimées ;
|
||||
D1/D2 décrites.
|
||||
- [ ] `spec-front.md` M2 : formulaire principal sans champs de contact ; onglet Contact
|
||||
présenté comme seul lieu de saisie (sans pré-remplissage depuis le principal).
|
||||
- [ ] Versions bumpées + historique daté.
|
||||
- [ ] Cohérence avec l'amendement des tickets M2.
|
||||
@@ -0,0 +1,36 @@
|
||||
# Prompt d'implémentation — M2 · Ticket Specs
|
||||
|
||||
Projet **Starseed**. Tâche **documentaire**. Mettre à jour les specs M2 Fournisseurs
|
||||
(`docs/specs/M2-suppliers/spec-back.md` + `spec-front.md`) pour retirer le contact principal
|
||||
inline du `Supplier` (5 champs `firstName/lastName/phonePrimary/phoneSecondary/email`).
|
||||
|
||||
M2 n'est **pas encore codé** : on corrige la conception en amont, **sans** migration ni
|
||||
backfill (contrairement à M1). Les contacts vivent uniquement dans `SupplierContact`.
|
||||
|
||||
Spec du ticket : `docs/specs/M1-clients/refonte-contact/M2-ticket-specs.md` (lis-la + le
|
||||
`README.md` du dossier).
|
||||
|
||||
## Étapes
|
||||
|
||||
1. Lire `spec-back.md` et `spec-front.md` M2 ; repérer toutes les occurrences des 5 champs
|
||||
(E-R l.175-179, CREATE TABLE supplier l.227-231, entité l.496-517, payloads l.782-805 /
|
||||
867-871, sérialisation l.725-729, RG-2.01/2.02/2.12, recherche, export, formulaire
|
||||
principal front l.105-117, pré-remplissage onglet Contact l.142).
|
||||
2. Retirer les 5 colonnes du modèle `supplier`.
|
||||
3. Marquer **supprimées** RG-2.01 et RG-2.02 (renvoi RG-2.04/RG-2.13) ; restreindre RG-2.12
|
||||
à `companyName` + `SupplierContact`. Ne pas renuméroter.
|
||||
4. Refléter D1 (recherche : LEFT JOIN supplier_contact recommandé) et D2 (export depuis le
|
||||
contact principal recommandé).
|
||||
5. Front : retirer les champs de contact du formulaire principal ; retirer la phrase de
|
||||
pré-remplissage du 1er bloc Contact ; présenter l'onglet Contact comme seul lieu de saisie.
|
||||
6. Bumper la version + historique daté (2026-06-03).
|
||||
|
||||
## Garde-fous
|
||||
|
||||
- Uniquement les `.md` de specs M2. Style existant conservé.
|
||||
- Cohérence stricte avec l'amendement des tickets M2 et avec la décision M1 (jumeau).
|
||||
|
||||
## Vérification
|
||||
|
||||
Relire les 2 specs : plus aucune mention des 5 champs inline dans le modèle `supplier` ;
|
||||
RG-2.01/2.02 supprimées ; versions bumpées.
|
||||
@@ -0,0 +1,84 @@
|
||||
# Refonte « contact » — suppression du contact inline des tiers (Client M1 + Supplier M2)
|
||||
|
||||
> Dossier de tickets transverse. Source de vérité de la décision et de son découpage.
|
||||
> Rédigé le 2026-06-03. Owner : Matthieu.
|
||||
|
||||
## 1. Décision
|
||||
|
||||
Le **contact « principal » inline** (les 5 colonnes plates `first_name`, `last_name`,
|
||||
`phone_primary`, `phone_secondary`, `email`) est **supprimé de l'entité tier** (`Client`,
|
||||
puis `Supplier`). La gestion des contacts passe **exclusivement** par la sous-entité
|
||||
dédiée (`ClientContact` / `SupplierContact`), c.-à-d. l'**onglet « Contacts »**.
|
||||
|
||||
### Pourquoi
|
||||
|
||||
- **Modèle unique, zéro duplication.** Aujourd'hui le contact est saisi deux fois : une
|
||||
fois dans le bloc principal (inline sur le tier) et une fois dans l'onglet Contacts
|
||||
(sous-entité). À la création, le front recopie même l'un dans l'autre
|
||||
(`prefillFirstContact`). Deux sources pour la même information = risque de divergence.
|
||||
- **Cohérence métier.** Un tier peut avoir plusieurs contacts ; il n'y a pas de raison
|
||||
qu'un seul soit « privilégié » au niveau de la table tier. La notion de contact
|
||||
appartient à la collection de contacts.
|
||||
- **Garantie préservée.** L'invariant « il y a toujours au moins un contact » est déjà
|
||||
assuré par la sous-entité : RG-1.05/RG-1.14 (M1) et RG-2.04/RG-2.13 (M2) imposent
|
||||
**≥ 1 bloc Contact valide** (Nom OU Prénom). Supprimer le contact inline ne crée donc
|
||||
aucun trou : le contact reste obligatoire, mais au bon endroit.
|
||||
|
||||
### Règles de gestion impactées
|
||||
|
||||
| RG | Avant | Après |
|
||||
|---|---|---|
|
||||
| RG-1.01 / RG-2.01 (firstName OU lastName obligatoire **sur le tier**) | sur `Client` / `Supplier` | **supprimée** du tier — équivalent assuré par RG-1.05 / RG-2.04 sur la sous-entité |
|
||||
| RG-1.02 / RG-2.02 (max 2 téléphones **sur le tier**) | sur le tier | **supprimée** du tier — reste sur la sous-entité |
|
||||
| RG-1.19/1.20/1.21 — RG-2.12 (normalisation Capitalize / chiffres / lowercase) | appliquée aux champs **du tier ET** de la sous-entité | ne s'applique plus aux champs du tier (qui n'existent plus) — **inchangée** sur la sous-entité |
|
||||
|
||||
## 2. Périmètre & découpage
|
||||
|
||||
### M1 — Clients (code DÉJÀ livré → suppression + migration de données)
|
||||
|
||||
| # | Ticket | Tag | Effort |
|
||||
|---|--------|-----|--------|
|
||||
| 1 | `M1-ticket-01-back` — supprimer le contact inline du `Client` (migration + backfill + entité + processor + provider + export + fixtures + tests) | Backend | M |
|
||||
| 2 | `M1-ticket-02-front` — retirer le bloc contact principal des écrans création / consultation / modification | Frontend | M |
|
||||
| 3 | `M1-ticket-03-specs` — acter la décision dans les specs M1 (back + front + cahier de test) | Maintenance | S |
|
||||
|
||||
### M2 — Fournisseurs (NON codé → on retire le contact inline dès la conception)
|
||||
|
||||
| # | Action | Tag | Effort |
|
||||
|---|--------|-----|--------|
|
||||
| 4 | `M2-ticket-specs` — mettre à jour les specs M2 déjà écrites (back + front) pour retirer le contact inline du `Supplier` | Maintenance | S |
|
||||
| — | `M2-amendement-tickets` — amender les tickets M2 existants (n° 84–97) impactés (migration, entités, processor, export, front, tests, i18n) | — | — |
|
||||
|
||||
> M2 ne nécessite **pas** de migration de suppression ni de backfill : il suffit de **ne
|
||||
> jamais créer** les 5 colonnes inline sur `supplier`. Le travail M2 est donc un
|
||||
> ajustement de specs + un amendement des tickets « prêts à dev ».
|
||||
|
||||
## 3. Décisions transverses à trancher (mêmes pour M1 et M2)
|
||||
|
||||
Deux comportements s'appuyaient sur les colonnes inline du tier. À la suppression, il faut
|
||||
choisir leur nouvelle source. Recommandation par défaut entre parenthèses.
|
||||
|
||||
- **D1 — Recherche serveur** (`?search=`). Aujourd'hui : fuzzy sur `companyName` +
|
||||
`lastName` + `email` **du tier**. Après suppression, deux options :
|
||||
- (a) restreindre la recherche à `companyName` seul (simple, mais perte de la recherche
|
||||
par contact) ;
|
||||
- (b) **[recommandé]** étendre la recherche en `LEFT JOIN` sur la sous-entité contact
|
||||
(`first_name` / `last_name` / `email` du contact), pour préserver l'UX « recherche par
|
||||
nom / contact / email » annoncée dans la barre de recherche.
|
||||
- **D2 — Colonnes de l'export XLSX** (Nom contact / Prénom / Téléphone / Téléphone 2 /
|
||||
Email). Après suppression :
|
||||
- (a) supprimer ces colonnes ;
|
||||
- (b) **[recommandé]** les alimenter depuis le **contact principal** (le contact de plus
|
||||
petit `position`), pour garder un export utile.
|
||||
|
||||
Ces deux décisions sont à valider par le métier (Matthieu) avant implémentation et sont
|
||||
rappelées dans chaque ticket concerné.
|
||||
|
||||
## 4. Fichiers de ce dossier
|
||||
|
||||
- `README.md` (ce fichier) — décision + découpage.
|
||||
- `M1-ticket-01-back.md` / `.prompt.md` — description + prompt d'implémentation.
|
||||
- `M1-ticket-02-front.md` / `.prompt.md`.
|
||||
- `M1-ticket-03-specs.md` / `.prompt.md`.
|
||||
- `M2-ticket-specs.md` / `.prompt.md`.
|
||||
- `M2-amendement-tickets.md` — bandeau d'amendement + liste des tickets M2 à mettre à jour.
|
||||
Reference in New Issue
Block a user