flow-create
Cree un nouveau flow d'automatisation de formulaire web complet.
Declenchement
/flow-create {platform} {product}
Exemples :
/flow-create alptis prevoyance-tns
/flow-create swisslifeone sante-famille
Journal de bord
IMPORTANT : Tout au long du processus, maintenir un fichier journal qui documente chaque action.
Fichier journal
.claude/flow-logs/{platform}-{product}-create.md
Format du journal
# Journal de creation : {platform} {product}
**Debut** : {date et heure}
**Branche** : flow/{platform}-{product}
**Status** : EN COURS | TERMINE | BLOQUE
---
## Phase 0 : Verification initiale
**Debut** : {timestamp}
- [x] Flow existe deja : NON
- [x] Credentials trouves : ALPTIS_TEST_USERNAME, ALPTIS_TEST_PASSWORD
- [x] Branche creee : flow/{platform}-{product}
**Fin** : {timestamp}
**Duree** : 2 min
---
## Phase 1 : Exploration
**Debut** : {timestamp}
### Actions
- Creation du test d'exploration : `e2e/{platform}/{product}/.detailed/explore-selectors.spec.ts`
- Lancement exploration headless...
### Resultats exploration
- Sections trouvees : 4
- Champs totaux : 18
- Selectors STABLE : 12
- Selectors UNSTABLE : 6
### Champs identifies
| Section | Champ | Type | Selector | Stabilite |
|---------|-------|------|----------|-----------|
| 1 | date_effet | date | input[placeholder='...'] | MODERATE |
| 2 | nom | text | #nom | STABLE |
| ... | ... | ... | ... | ... |
- Cartographie generee : `src/main/flows/cartography/{platform}/{platform}-{product}-exhaustive-mapping.json`
**Fin** : {timestamp}
**Duree** : 15 min
**Commit** : feat({platform}/{product}): add form cartography
---
## Phase 2 : Scaffolding
**Debut** : {timestamp}
### Fichiers crees
- `src/main/flows/config/products/{platform}-{product}.ts`
- `src/main/flows/platforms/{platform}/products/{product}/transformers/types.ts`
- `src/main/flows/platforms/{platform}/products/{product}/transformers/LeadTransformer.ts`
- ... (liste complete)
**Fin** : {timestamp}
**Duree** : 10 min
**Commit** : feat({platform}/{product}): scaffold flow structure
---
## Phase 3 : Implementation
**Debut** : {timestamp}
### Section 1 : Mise en place
- Selectors implementes : 3/3
- Operations utilisees : DateOperations, ToggleOperations
- Test detaille : PASS
- Commit : feat({platform}/{product}): implement section 1 - Mise en place
### Section 2 : Adherent
- Selectors implementes : 8/8
- Operations utilisees : DateOperations, DropdownOperations, RadioOperations
- Test detaille : PASS
- Commit : feat({platform}/{product}): implement section 2 - Adherent
### Section 3 : Conjoint (optionnel)
- Selectors implementes : 4/4
- Test detaille : PASS (avec lead conjoint)
- Commit : feat({platform}/{product}): implement section 3 - Conjoint
### Section 4 : Enfants (dynamique)
- Selectors implementes : 2/2 par enfant
- Logique dynamique : OK (jusqu'a 5 enfants)
- Test detaille : PASS
- Commit : feat({platform}/{product}): implement section 4 - Enfants
**Fin** : {timestamp}
**Duree** : 45 min
---
## Phase 4 : Integration
**Debut** : {timestamp}
- FormFillOrchestrator : OK
- Enregistrement PRODUCT_CONFIGS : OK
- Test single lead (LEAD_INDEX=0) : PASS
**Fin** : {timestamp}
**Duree** : 10 min
**Commit** : feat({platform}/{product}): integrate flow with FlowEngine
---
## Phase 5 : Tests bulk
**Debut** : {timestamp}
### Premier run
- Leads testes : 22
- Resultats : 18 PASS, 4 FAIL
- Problemes identifies :
- Lead #5 : profession non mappee "consultant senior"
- Lead #12 : date format invalide
- Lead #15, #18 : meme probleme profession
### Corrections
- Ajout mapping "consultant senior" -> PROFESSIONS_LIBERALES
- Fix parsing date avec format alternatif
### Second run
- Leads testes : 22
- Resultats : 22 PASS, 0 FAIL
**Fin** : {timestamp}
**Duree** : 20 min
**Commit** : test({platform}/{product}): add test fixtures and bulk validation
---
## Phase 6 : Validation
**Debut** : {timestamp}
### Status final
- Sections implementees : 4/4
- Tests bulk : 22/22 PASS (100%)
- Commits : 8
### En attente
- Review utilisateur
- Merge de la branche
**Fin** : {timestamp}
---
## Problemes rencontres
### Probleme 1 : Dropdown ville ne se charge pas
**Symptome** : Timeout sur selection ville
**Cause** : Le dropdown attend que le code postal soit valide
**Solution** : Ajouter waitForTimeout(2000) apres remplissage code postal
### Probleme 2 : Profession non mappee
**Symptome** : 4 leads en echec avec erreur "Unknown profession"
**Cause** : Mapping manquant pour "consultant senior"
**Solution** : Ajout dans profession-mapper.ts
---
## Resume
- **Temps total** : 1h42
- **Commits** : 8
- **Tests** : 22/22 PASS
- **Status** : PRET POUR REVIEW
Regles du journal
- Creer le fichier au debut de la Phase 0
- Mettre a jour en temps reel a chaque action importante
- Documenter les problemes rencontres et leurs solutions
- Inclure les timestamps pour chaque phase
- Lister tous les fichiers crees/modifies
- Noter les resultats de tests (PASS/FAIL avec details)
Workflow complet
Phase 0 : Verification initiale
Verifier si le flow existe deja
ls src/main/flows/config/products/{platform}-{product}.ts
Si le flow existe, suggerer /flow-fix a la place.
Verifier les credentials
grep -q "{PLATFORM}_USERNAME" .env && grep -q "{PLATFORM}_PASSWORD" .env
Variables requises :
- Pour Alptis :
ALPTIS_TEST_USERNAME, ALPTIS_TEST_PASSWORD
- Pour SwissLife :
SWISSLIFE_USERNAME, SWISSLIFE_PASSWORD
Si manquants, demander a l'utilisateur de les ajouter au fichier .env.
Creer la branche de travail
git checkout -b flow/{platform}-{product}
COMMIT : chore: create branch flow/{platform}-{product}
Phase 1 : Exploration du formulaire
L'exploration se fait en mode headless (pas de fenetre visible).
Creer le test d'exploration Playwright
Creer le fichier : e2e/{platform}/{product}/.detailed/explore-selectors.spec.ts
Template base sur : e2e/swisslifeone/slsis/.detailed/inspect-section6-selectors.spec.ts
import { test } from '@playwright/test';
import { create{Platform}Services } from '@/main/flows/engine/services';
import { get{Platform}Credentials } from '@/main/flows/config';
test.describe('Selector Exploration - {Product}', () => {
test('Explore all form sections', async ({ page }) => {
test.setTimeout(600000); // 10 minutes
// 1. Auth
const services = create{Platform}Services(get{Platform}Credentials());
await services.auth.login(page);
// 2. Navigate to form
await page.goto('{FORM_URL}');
await page.waitForLoadState('networkidle');
// 3. For each section: inspect elements
console.log('\n====== SECTION 1 ======');
const snapshot1 = await page.locator('body').ariaSnapshot();
console.log('ARIA Snapshot:', snapshot1.substring(0, 2000));
// 4. Inspect all inputs
const inputs = await page.locator('input, select, textarea').all();
for (const input of inputs) {
const id = await input.getAttribute('id');
const name = await input.getAttribute('name');
const type = await input.getAttribute('type');
const placeholder = await input.getAttribute('placeholder');
const isVisible = await input.isVisible();
if (isVisible) {
// Evaluate stability
let stability = 'STABLE';
if (!id) stability = 'UNSTABLE';
else if (/^[0-9a-f]{8}-/.test(id)) stability = 'UNSTABLE (UUID)';
console.log({ id, name, type, placeholder, stability });
}
}
// 5. Capture screenshot
await page.screenshot({
path: `src/main/flows/cartography/{platform}/{product}-section1.png`
});
// Repeter pour chaque section...
});
});
Lancer l'exploration en headless
npx playwright test e2e/{platform}/{product}/.detailed/explore-selectors.spec.ts --timeout=600000
Generer le JSON de cartographie
Creer : src/main/flows/cartography/{platform}/{platform}-{product}-exhaustive-mapping.json
Template base sur : src/main/flows/cartography/alptis/alptis-sante-select-exhaustive-mapping.json
{
"product": {
"name": "{Product Display Name}",
"platform": "{platform}",
"url": "https://...",
"cartography_date": "YYYY-MM-DD"
},
"metadata": {
"form_title": "...",
"total_steps": 2,
"framework": "Vue.js | Angular | React",
"design_system": "Totem | Bootstrap | Custom"
},
"form_structure": {
"sections": [
{ "name": "Section 1", "fields_count": 3 },
{ "name": "Section 2", "fields_count": 8 }
]
},
"fields": [
{
"field_id": "nom",
"section": "Adherent",
"type": "text",
"selector": {
"primary": "#nom",
"alternative": "input[placeholder='Ex : Durand']",
"stability": "STABLE"
},
"validation": {
"required": true,
"pattern": "^[a-zA-Z-' ]+$"
}
}
]
}
COMMIT : feat({platform}/{product}): add form cartography
Phase 2 : Scaffolding
Creer l'arborescence complete :
src/main/flows/
├── config/products/{platform}-{product}.ts # ProductConfiguration
└── platforms/{platform}/products/{product}/
├── steps/
│ ├── form-fill/
│ │ ├── FormFillOrchestrator.ts
│ │ ├── index.ts
│ │ ├── selectors/
│ │ │ ├── section1.ts
│ │ │ ├── section2.ts
│ │ │ ├── common.ts
│ │ │ └── index.ts
│ │ ├── sections/
│ │ │ ├── Section1Fill.ts
│ │ │ └── Section2Fill.ts
│ │ └── operations/
│ │ ├── DateOperations.ts
│ │ ├── DropdownOperations.ts
│ │ ├── RadioOperations.ts
│ │ ├── ToggleOperations.ts
│ │ └── index.ts
│ └── navigation/
│ └── index.ts
└── transformers/
├── LeadTransformer.ts
├── types.ts
├── mappers/
│ ├── civilite-mapper.ts
│ ├── profession-mapper.ts
│ └── regime-mapper.ts
└── validators/
├── lead-validator.ts
└── eligibility-validator.ts
e2e/{platform}/{product}/
├── fixtures.ts
├── single-lead-journey.spec.ts
├── bulk-validation.spec.ts
└── .detailed/
├── explore-selectors.spec.ts
├── form-fill.section1.spec.ts
├── form-fill.section2.spec.ts
└── transformer.spec.ts
Fichiers de reference a copier/adapter :
| Type |
Fichier de reference |
| ProductConfiguration |
src/main/flows/config/products/alptis-sante-pro-plus.ts |
| FormFillOrchestrator |
src/main/flows/platforms/alptis/products/sante-pro-plus/steps/form-fill/FormFillOrchestrator.ts |
| Selectors |
src/main/flows/platforms/alptis/products/sante-pro-plus/steps/form-fill/selectors/section2.ts |
| Operations |
src/main/flows/platforms/alptis/products/sante-pro-plus/steps/form-fill/operations/ |
| LeadTransformer |
src/main/flows/platforms/alptis/products/sante-pro-plus/transformers/LeadTransformer.ts |
| Mappers |
src/main/flows/platforms/alptis/products/sante-pro-plus/transformers/mappers/ |
| Fixtures e2e |
e2e/alptis/fixtures.ts |
| Single lead test |
e2e/alptis/sante-pro-plus/single-lead-journey.spec.ts |
COMMIT : feat({platform}/{product}): scaffold flow structure
Phase 3 : Implementation section par section
Pour chaque section du formulaire (en ordre) :
Types : Definir {Product}FormData base sur la cartographie
export type {Product}FormData = {
mise_en_place: {
remplacement_contrat: boolean;
date_effet: string;
};
adherent: {
civilite: 'M.' | 'Mme';
nom: string;
prenom: string;
date_naissance: string;
// ... autres champs
};
conjoint?: { ... };
enfants?: Array<{ ... }>;
};
Mappers : Creer un mapper pour chaque enum
// mappers/profession-mapper.ts
const PROFESSION_MAPPING: Record<string, string> = {
'profession liberale': 'PROFESSIONS_LIBERALES',
"chef d'entreprise": 'CHEFS_D_ENTREPRISE',
// ... base sur la cartographie
};
export function mapProfession(value: string | undefined): string {
if (!value) return 'AUTRES';
return PROFESSION_MAPPING[value.toLowerCase().trim()] ?? 'AUTRES';
}
Selectors : Definir avec stabilite
// selectors/section2.ts
export const SECTION_2_SELECTORS = {
nom: {
primary: '#nom',
stability: 'STABLE',
},
civilite: {
primary: "input[name*='form-radio']",
byValue: (v: 'monsieur' | 'madame') => `input[value='${v}']`,
stability: 'UNSTABLE',
},
date_naissance: {
primary: "input[placeholder='Ex : 01/01/2020']",
note: "Use .nth(1) - first date field is date_effet",
stability: 'MODERATE',
},
} as const;
SectionFill : Implementer le remplissage
// sections/Section2Fill.ts
export class Section2Fill {
async fill(page: Page, data: FormData, logger?: FlowLogger): Promise<void> {
// Civilite
const civiliteSelector = SELECTORS.civilite.byValue(
data.adherent.civilite === 'M.' ? 'monsieur' : 'madame'
);
await page.locator(civiliteSelector).click({ force: true });
// Nom
await page.locator(SELECTORS.nom.primary).fill(data.adherent.nom);
// ... etc
}
}
Test detaille : Tester la section isolement (headless)
npx playwright test e2e/{platform}/{product}/.detailed/form-fill.section{n}.spec.ts
COMMIT apres chaque section : feat({platform}/{product}): implement section {n} - {name}
Phase 4 : Integration
Implementer le FormFillOrchestrator
export class FormFillOrchestrator {
private section1 = new Section1Fill();
private section2 = new Section2Fill();
async fillMiseEnPlace(page: Page, data: FormData, logger?: FlowLogger) {
await this.section1.fill(page, data, logger);
}
async fillAdherent(page: Page, data: FormData, logger?: FlowLogger) {
await this.section2.fill(page, data, logger);
}
// ...
}
Enregistrer dans PRODUCT_CONFIGS
Editer src/main/flows/config/products/index.ts :
import { {PLATFORM}_{PRODUCT} } from "./{platform}-{product}";
export const PRODUCT_CONFIGS: Record<string, ProductConfiguration> = {
// ... existing
[{PLATFORM}_{PRODUCT}.flowKey]: {PLATFORM}_{PRODUCT},
};
Creer ServiceFactory si nouvelle plateforme
Tester single lead (headless)
LEAD_INDEX=0 npx playwright test e2e/{platform}/{product}/single-lead-journey.spec.ts
COMMIT : feat({platform}/{product}): integrate flow with FlowEngine
Phase 5 : Tests bulk et generation de leads
Tester sur tous les leads existants (headless)
npx playwright test e2e/{platform}/{product}/bulk-validation.spec.ts
Si aucun lead compatible : Generer des fixtures JSON programmatiquement
Creer dans src/main/__tests__/fixtures/emails/ :
email-{next}-solo.json : Lead sans conjoint ni enfants
email-{next}-conjoint.json : Lead avec conjoint
email-{next}-enfants.json : Lead avec enfants
email-{next}-both.json : Lead avec conjoint ET enfants
Format :
{
"id": "fixture-{product}-solo",
"subject": "Nouveau lead - {Product} Solo",
"from": "test@fixture.com",
"date": 1700000000000,
"text": "Civilite: M.\nNom: DUPONT\nPrenom: Jean\n..."
}
Iterer jusqu'a 100% de succes
- Si un test echoue : identifier le probleme, corriger, re-tester
- Repeter jusqu'a ce que bulk-validation passe a 100%
COMMIT : test({platform}/{product}): add test fixtures and bulk validation
Phase 6 : Validation utilisateur
Quand tous les tests passent OU si bloque :
Flow {platform}_{product} pret pour review.
Status:
- Sections implementees: {n}/{total}
- Tests bulk: {passed}/{total} leads
- Coverage: {percentage}%
Prochaines etapes:
1. Review du code
2. Merge de la branche
3. Test manuel si necessaire
Demander a l'utilisateur s'il veut :
- Merger la branche
- Faire des ajustements
- Voir les details d'un probleme
Conventions
Nommage
| Element |
Pattern |
Exemple |
| flowKey |
{platform}_{product} |
alptis_sante_select |
| Branche |
flow/{platform}-{product} |
flow/alptis-prevoyance-tns |
| Config file |
{platform}-{product}.ts |
alptis-prevoyance-tns.ts |
Pattern de selectors
{
primary: "#semantic-id", // Le plus stable
alternative: ".class-selector", // Fallback
byValue: (v) => `[value='${v}']`, // Pour radios/options
byRole: "combobox", // Pour Playwright roles
byPosition: ".item:nth(0)", // Si necessaire
fallback: "label:has-text('...')", // Dernier recours
stability: 'STABLE' | 'MODERATE' | 'UNSTABLE',
}
Format commits
{type}({platform}/{product}): {description}
- Detail 1
- Detail 2
Generated with Claude Code
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Types : feat, fix, test, chore, docs
Checklist
1---2name: flow-create3description: Creer un nouveau flow d'automatisation de formulaire complet, incluant exploration du site web, implementation et tests. (project)4---5
6# flow-create
7
8Cree un nouveau flow d'automatisation de formulaire web complet.
9
10## Declenchement
11
12```
13/flow-create {platform} {product}
14```
15
16Exemples :
17- `/flow-create alptis prevoyance-tns`
18- `/flow-create swisslifeone sante-famille`
19
20---
21
22## Journal de bord
23
24**IMPORTANT** : Tout au long du processus, maintenir un fichier journal qui documente chaque action.
25
26### Fichier journal
27```
28.claude/flow-logs/{platform}-{product}-create.md
29```
30
31### Format du journal
32
33```markdown
34# Journal de creation : {platform} {product}
35
36**Debut** : {date et heure}
37**Branche** : flow/{platform}-{product}
38**Status** : EN COURS | TERMINE | BLOQUE
39
40---
41
42## Phase 0 : Verification initiale
43**Debut** : {timestamp}
44
45- [x] Flow existe deja : NON
46- [x] Credentials trouves : ALPTIS_TEST_USERNAME, ALPTIS_TEST_PASSWORD
47- [x] Branche creee : flow/{platform}-{product}
48
49**Fin** : {timestamp}
50**Duree** : 2 min
51
52---
53
54## Phase 1 : Exploration
55**Debut** : {timestamp}
56
57### Actions
58- Creation du test d'exploration : `e2e/{platform}/{product}/.detailed/explore-selectors.spec.ts`
59- Lancement exploration headless...
60
61### Resultats exploration
62- Sections trouvees : 4
63- Champs totaux : 18
64- Selectors STABLE : 12
65- Selectors UNSTABLE : 6
66
67### Champs identifies
68| Section | Champ | Type | Selector | Stabilite |
69|---------|-------|------|----------|-----------|
70| 1 | date_effet | date | input[placeholder='...'] | MODERATE |
71| 2 | nom | text | #nom | STABLE |
72| ... | ... | ... | ... | ... |
73
74- Cartographie generee : `src/main/flows/cartography/{platform}/{platform}-{product}-exhaustive-mapping.json`
75
76**Fin** : {timestamp}
77**Duree** : 15 min
78**Commit** : feat({platform}/{product}): add form cartography
79
80---
81
82## Phase 2 : Scaffolding
83**Debut** : {timestamp}
84
85### Fichiers crees
86- `src/main/flows/config/products/{platform}-{product}.ts`
87- `src/main/flows/platforms/{platform}/products/{product}/transformers/types.ts`
88- `src/main/flows/platforms/{platform}/products/{product}/transformers/LeadTransformer.ts`
89- ... (liste complete)
90
91**Fin** : {timestamp}
92**Duree** : 10 min
93**Commit** : feat({platform}/{product}): scaffold flow structure
94
95---
96
97## Phase 3 : Implementation
98**Debut** : {timestamp}
99
100### Section 1 : Mise en place
101- Selectors implementes : 3/3
102- Operations utilisees : DateOperations, ToggleOperations
103- Test detaille : PASS
104- Commit : feat({platform}/{product}): implement section 1 - Mise en place
105
106### Section 2 : Adherent
107- Selectors implementes : 8/8
108- Operations utilisees : DateOperations, DropdownOperations, RadioOperations
109- Test detaille : PASS
110- Commit : feat({platform}/{product}): implement section 2 - Adherent
111
112### Section 3 : Conjoint (optionnel)
113- Selectors implementes : 4/4
114- Test detaille : PASS (avec lead conjoint)
115- Commit : feat({platform}/{product}): implement section 3 - Conjoint
116
117### Section 4 : Enfants (dynamique)
118- Selectors implementes : 2/2 par enfant
119- Logique dynamique : OK (jusqu'a 5 enfants)
120- Test detaille : PASS
121- Commit : feat({platform}/{product}): implement section 4 - Enfants
122
123**Fin** : {timestamp}
124**Duree** : 45 min
125
126---
127
128## Phase 4 : Integration
129**Debut** : {timestamp}
130
131- FormFillOrchestrator : OK
132- Enregistrement PRODUCT_CONFIGS : OK
133- Test single lead (LEAD_INDEX=0) : PASS
134
135**Fin** : {timestamp}
136**Duree** : 10 min
137**Commit** : feat({platform}/{product}): integrate flow with FlowEngine
138
139---
140
141## Phase 5 : Tests bulk
142**Debut** : {timestamp}
143
144### Premier run
145- Leads testes : 22
146- Resultats : 18 PASS, 4 FAIL
147- Problemes identifies :
148 - Lead #5 : profession non mappee "consultant senior"
149 - Lead #12 : date format invalide
150 - Lead #15, #18 : meme probleme profession
151
152### Corrections
153- Ajout mapping "consultant senior" -> PROFESSIONS_LIBERALES
154- Fix parsing date avec format alternatif
155
156### Second run
157- Leads testes : 22
158- Resultats : 22 PASS, 0 FAIL
159
160**Fin** : {timestamp}
161**Duree** : 20 min
162**Commit** : test({platform}/{product}): add test fixtures and bulk validation
163
164---
165
166## Phase 6 : Validation
167**Debut** : {timestamp}
168
169### Status final
170- Sections implementees : 4/4
171- Tests bulk : 22/22 PASS (100%)
172- Commits : 8
173
174### En attente
175- Review utilisateur
176- Merge de la branche
177
178**Fin** : {timestamp}
179
180---
181
182## Problemes rencontres
183
184### Probleme 1 : Dropdown ville ne se charge pas
185**Symptome** : Timeout sur selection ville
186**Cause** : Le dropdown attend que le code postal soit valide
187**Solution** : Ajouter waitForTimeout(2000) apres remplissage code postal
188
189### Probleme 2 : Profession non mappee
190**Symptome** : 4 leads en echec avec erreur "Unknown profession"
191**Cause** : Mapping manquant pour "consultant senior"
192**Solution** : Ajout dans profession-mapper.ts
193
194---
195
196## Resume
197- **Temps total** : 1h42
198- **Commits** : 8
199- **Tests** : 22/22 PASS
200- **Status** : PRET POUR REVIEW
201```
202
203### Regles du journal
204
2051. **Creer le fichier au debut** de la Phase 0
2062. **Mettre a jour en temps reel** a chaque action importante
2073. **Documenter les problemes** rencontres et leurs solutions
2084. **Inclure les timestamps** pour chaque phase
2095. **Lister tous les fichiers** crees/modifies
2106. **Noter les resultats de tests** (PASS/FAIL avec details)
211
212---
213
214## Workflow complet
215
216### Phase 0 : Verification initiale
217
2181. **Verifier si le flow existe deja**
219 ```bash
220 ls src/main/flows/config/products/{platform}-{product}.ts
221 ```
222 Si le flow existe, suggerer `/flow-fix` a la place.
223
2242. **Verifier les credentials**
225 ```bash
226 grep -q "{PLATFORM}_USERNAME" .env && grep -q "{PLATFORM}_PASSWORD" .env
227 ```
228 Variables requises :
229 - Pour Alptis : `ALPTIS_TEST_USERNAME`, `ALPTIS_TEST_PASSWORD`
230 - Pour SwissLife : `SWISSLIFE_USERNAME`, `SWISSLIFE_PASSWORD`
231
232 Si manquants, demander a l'utilisateur de les ajouter au fichier `.env`.
233
2343. **Creer la branche de travail**
235 ```bash
236 git checkout -b flow/{platform}-{product}
237 ```
238 COMMIT : `chore: create branch flow/{platform}-{product}`
239
240---
241
242### Phase 1 : Exploration du formulaire
243
244L'exploration se fait en mode **headless** (pas de fenetre visible).
245
2461. **Creer le test d'exploration Playwright**
247
248 Creer le fichier : `e2e/{platform}/{product}/.detailed/explore-selectors.spec.ts`
249
250 Template base sur : `e2e/swisslifeone/slsis/.detailed/inspect-section6-selectors.spec.ts`
251
252 ```typescript
253 import { test } from '@playwright/test';
254 import { create{Platform}Services } from '@/main/flows/engine/services';
255 import { get{Platform}Credentials } from '@/main/flows/config';
256
257 test.describe('Selector Exploration - {Product}', () => {
258 test('Explore all form sections', async ({ page }) => {
259 test.setTimeout(600000); // 10 minutes
260
261 // 1. Auth
262 const services = create{Platform}Services(get{Platform}Credentials());
263 await services.auth.login(page);
264
265 // 2. Navigate to form
266 await page.goto('{FORM_URL}');
267 await page.waitForLoadState('networkidle');
268
269 // 3. For each section: inspect elements
270 console.log('\n====== SECTION 1 ======');
271 const snapshot1 = await page.locator('body').ariaSnapshot();
272 console.log('ARIA Snapshot:', snapshot1.substring(0, 2000));
273
274 // 4. Inspect all inputs
275 const inputs = await page.locator('input, select, textarea').all();
276 for (const input of inputs) {
277 const id = await input.getAttribute('id');
278 const name = await input.getAttribute('name');
279 const type = await input.getAttribute('type');
280 const placeholder = await input.getAttribute('placeholder');
281 const isVisible = await input.isVisible();
282
283 if (isVisible) {
284 // Evaluate stability
285 let stability = 'STABLE';
286 if (!id) stability = 'UNSTABLE';
287 else if (/^[0-9a-f]{8}-/.test(id)) stability = 'UNSTABLE (UUID)';
288
289 console.log({ id, name, type, placeholder, stability });
290 }
291 }
292
293 // 5. Capture screenshot
294 await page.screenshot({
295 path: `src/main/flows/cartography/{platform}/{product}-section1.png`
296 });
297
298 // Repeter pour chaque section...
299 });
300 });
301 ```
302
3032. **Lancer l'exploration en headless**
304 ```bash
305 npx playwright test e2e/{platform}/{product}/.detailed/explore-selectors.spec.ts --timeout=600000
306 ```
307
3083. **Generer le JSON de cartographie**
309
310 Creer : `src/main/flows/cartography/{platform}/{platform}-{product}-exhaustive-mapping.json`
311
312 Template base sur : `src/main/flows/cartography/alptis/alptis-sante-select-exhaustive-mapping.json`
313
314 ```json
315 {
316 "product": {
317 "name": "{Product Display Name}",
318 "platform": "{platform}",
319 "url": "https://...",
320 "cartography_date": "YYYY-MM-DD"
321 },
322 "metadata": {
323 "form_title": "...",
324 "total_steps": 2,
325 "framework": "Vue.js | Angular | React",
326 "design_system": "Totem | Bootstrap | Custom"
327 },
328 "form_structure": {
329 "sections": [
330 { "name": "Section 1", "fields_count": 3 },
331 { "name": "Section 2", "fields_count": 8 }
332 ]
333 },
334 "fields": [
335 {
336 "field_id": "nom",
337 "section": "Adherent",
338 "type": "text",
339 "selector": {
340 "primary": "#nom",
341 "alternative": "input[placeholder='Ex : Durand']",
342 "stability": "STABLE"
343 },
344 "validation": {
345 "required": true,
346 "pattern": "^[a-zA-Z-' ]+$"
347 }
348 }
349 ]
350 }
351 ```
352
353 COMMIT : `feat({platform}/{product}): add form cartography`
354
355---
356
357### Phase 2 : Scaffolding
358
359Creer l'arborescence complete :
360
361```
362src/main/flows/
363├── config/products/{platform}-{product}.ts # ProductConfiguration
364└── platforms/{platform}/products/{product}/
365 ├── steps/
366 │ ├── form-fill/
367 │ │ ├── FormFillOrchestrator.ts
368 │ │ ├── index.ts
369 │ │ ├── selectors/
370 │ │ │ ├── section1.ts
371 │ │ │ ├── section2.ts
372 │ │ │ ├── common.ts
373 │ │ │ └── index.ts
374 │ │ ├── sections/
375 │ │ │ ├── Section1Fill.ts
376 │ │ │ └── Section2Fill.ts
377 │ │ └── operations/
378 │ │ ├── DateOperations.ts
379 │ │ ├── DropdownOperations.ts
380 │ │ ├── RadioOperations.ts
381 │ │ ├── ToggleOperations.ts
382 │ │ └── index.ts
383 │ └── navigation/
384 │ └── index.ts
385 └── transformers/
386 ├── LeadTransformer.ts
387 ├── types.ts
388 ├── mappers/
389 │ ├── civilite-mapper.ts
390 │ ├── profession-mapper.ts
391 │ └── regime-mapper.ts
392 └── validators/
393 ├── lead-validator.ts
394 └── eligibility-validator.ts
395
396e2e/{platform}/{product}/
397├── fixtures.ts
398├── single-lead-journey.spec.ts
399├── bulk-validation.spec.ts
400└── .detailed/
401 ├── explore-selectors.spec.ts
402 ├── form-fill.section1.spec.ts
403 ├── form-fill.section2.spec.ts
404 └── transformer.spec.ts
405```
406
407**Fichiers de reference a copier/adapter :**
408
409| Type | Fichier de reference |
410|------|---------------------|
411| ProductConfiguration | `src/main/flows/config/products/alptis-sante-pro-plus.ts` |
412| FormFillOrchestrator | `src/main/flows/platforms/alptis/products/sante-pro-plus/steps/form-fill/FormFillOrchestrator.ts` |
413| Selectors | `src/main/flows/platforms/alptis/products/sante-pro-plus/steps/form-fill/selectors/section2.ts` |
414| Operations | `src/main/flows/platforms/alptis/products/sante-pro-plus/steps/form-fill/operations/` |
415| LeadTransformer | `src/main/flows/platforms/alptis/products/sante-pro-plus/transformers/LeadTransformer.ts` |
416| Mappers | `src/main/flows/platforms/alptis/products/sante-pro-plus/transformers/mappers/` |
417| Fixtures e2e | `e2e/alptis/fixtures.ts` |
418| Single lead test | `e2e/alptis/sante-pro-plus/single-lead-journey.spec.ts` |
419
420COMMIT : `feat({platform}/{product}): scaffold flow structure`
421
422---
423
424### Phase 3 : Implementation section par section
425
426Pour chaque section du formulaire (en ordre) :
427
4281. **Types** : Definir `{Product}FormData` base sur la cartographie
429 ```typescript
430 export type {Product}FormData = {
431 mise_en_place: {
432 remplacement_contrat: boolean;
433 date_effet: string;
434 };
435 adherent: {
436 civilite: 'M.' | 'Mme';
437 nom: string;
438 prenom: string;
439 date_naissance: string;
440 // ... autres champs
441 };
442 conjoint?: { ... };
443 enfants?: Array<{ ... }>;
444 };
445 ```
446
4472. **Mappers** : Creer un mapper pour chaque enum
448 ```typescript
449 // mappers/profession-mapper.ts
450 const PROFESSION_MAPPING: Record<string, string> = {
451 'profession liberale': 'PROFESSIONS_LIBERALES',
452 "chef d'entreprise": 'CHEFS_D_ENTREPRISE',
453 // ... base sur la cartographie
454 };
455
456 export function mapProfession(value: string | undefined): string {
457 if (!value) return 'AUTRES';
458 return PROFESSION_MAPPING[value.toLowerCase().trim()] ?? 'AUTRES';
459 }
460 ```
461
4623. **Selectors** : Definir avec stabilite
463 ```typescript
464 // selectors/section2.ts
465 export const SECTION_2_SELECTORS = {
466 nom: {
467 primary: '#nom',
468 stability: 'STABLE',
469 },
470 civilite: {
471 primary: "input[name*='form-radio']",
472 byValue: (v: 'monsieur' | 'madame') => `input[value='${v}']`,
473 stability: 'UNSTABLE',
474 },
475 date_naissance: {
476 primary: "input[placeholder='Ex : 01/01/2020']",
477 note: "Use .nth(1) - first date field is date_effet",
478 stability: 'MODERATE',
479 },
480 } as const;
481 ```
482
4834. **SectionFill** : Implementer le remplissage
484 ```typescript
485 // sections/Section2Fill.ts
486 export class Section2Fill {
487 async fill(page: Page, data: FormData, logger?: FlowLogger): Promise<void> {
488 // Civilite
489 const civiliteSelector = SELECTORS.civilite.byValue(
490 data.adherent.civilite === 'M.' ? 'monsieur' : 'madame'
491 );
492 await page.locator(civiliteSelector).click({ force: true });
493
494 // Nom
495 await page.locator(SELECTORS.nom.primary).fill(data.adherent.nom);
496
497 // ... etc
498 }
499 }
500 ```
501
5025. **Test detaille** : Tester la section isolement (headless)
503 ```bash
504 npx playwright test e2e/{platform}/{product}/.detailed/form-fill.section{n}.spec.ts
505 ```
506
507COMMIT apres chaque section : `feat({platform}/{product}): implement section {n} - {name}`
508
509---
510
511### Phase 4 : Integration
512
5131. **Implementer le FormFillOrchestrator**
514 ```typescript
515 export class FormFillOrchestrator {
516 private section1 = new Section1Fill();
517 private section2 = new Section2Fill();
518
519 async fillMiseEnPlace(page: Page, data: FormData, logger?: FlowLogger) {
520 await this.section1.fill(page, data, logger);
521 }
522
523 async fillAdherent(page: Page, data: FormData, logger?: FlowLogger) {
524 await this.section2.fill(page, data, logger);
525 }
526 // ...
527 }
528 ```
529
5302. **Enregistrer dans PRODUCT_CONFIGS**
531
532 Editer `src/main/flows/config/products/index.ts` :
533 ```typescript
534 import { {PLATFORM}_{PRODUCT} } from "./{platform}-{product}";
535
536 export const PRODUCT_CONFIGS: Record<string, ProductConfiguration> = {
537 // ... existing
538 [{PLATFORM}_{PRODUCT}.flowKey]: {PLATFORM}_{PRODUCT},
539 };
540 ```
541
5423. **Creer ServiceFactory** si nouvelle plateforme
543
5444. **Tester single lead** (headless)
545 ```bash
546 LEAD_INDEX=0 npx playwright test e2e/{platform}/{product}/single-lead-journey.spec.ts
547 ```
548
549COMMIT : `feat({platform}/{product}): integrate flow with FlowEngine`
550
551---
552
553### Phase 5 : Tests bulk et generation de leads
554
5551. **Tester sur tous les leads existants** (headless)
556 ```bash
557 npx playwright test e2e/{platform}/{product}/bulk-validation.spec.ts
558 ```
559
5602. **Si aucun lead compatible** : Generer des fixtures JSON programmatiquement
561
562 Creer dans `src/main/__tests__/fixtures/emails/` :
563 - `email-{next}-solo.json` : Lead sans conjoint ni enfants
564 - `email-{next}-conjoint.json` : Lead avec conjoint
565 - `email-{next}-enfants.json` : Lead avec enfants
566 - `email-{next}-both.json` : Lead avec conjoint ET enfants
567
568 Format :
569 ```json
570 {
571 "id": "fixture-{product}-solo",
572 "subject": "Nouveau lead - {Product} Solo",
573 "from": "test@fixture.com",
574 "date": 1700000000000,
575 "text": "Civilite: M.\nNom: DUPONT\nPrenom: Jean\n..."
576 }
577 ```
578
5793. **Iterer jusqu'a 100% de succes**
580 - Si un test echoue : identifier le probleme, corriger, re-tester
581 - Repeter jusqu'a ce que bulk-validation passe a 100%
582
583COMMIT : `test({platform}/{product}): add test fixtures and bulk validation`
584
585---
586
587### Phase 6 : Validation utilisateur
588
589Quand tous les tests passent OU si bloque :
590
591```
592Flow {platform}_{product} pret pour review.
593
594Status:
595- Sections implementees: {n}/{total}
596- Tests bulk: {passed}/{total} leads
597- Coverage: {percentage}%
598
599Prochaines etapes:
6001. Review du code
6012. Merge de la branche
6023. Test manuel si necessaire
603```
604
605Demander a l'utilisateur s'il veut :
6061. Merger la branche
6072. Faire des ajustements
6083. Voir les details d'un probleme
609
610---
611
612## Conventions
613
614### Nommage
615| Element | Pattern | Exemple |
616|---------|---------|---------|
617| flowKey | `{platform}_{product}` | `alptis_sante_select` |
618| Branche | `flow/{platform}-{product}` | `flow/alptis-prevoyance-tns` |
619| Config file | `{platform}-{product}.ts` | `alptis-prevoyance-tns.ts` |
620
621### Pattern de selectors
622```typescript
623{
624 primary: "#semantic-id", // Le plus stable
625 alternative: ".class-selector", // Fallback
626 byValue: (v) => `[value='${v}']`, // Pour radios/options
627 byRole: "combobox", // Pour Playwright roles
628 byPosition: ".item:nth(0)", // Si necessaire
629 fallback: "label:has-text('...')", // Dernier recours
630 stability: 'STABLE' | 'MODERATE' | 'UNSTABLE',
631}
632```
633
634### Format commits
635```
636{type}({platform}/{product}): {description}
637
638- Detail 1
639- Detail 2
640
641Generated with Claude Code
642
643Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
644```
645
646Types : `feat`, `fix`, `test`, `chore`, `docs`
647
648---
649
650## Checklist
651
652- [ ] Branche `flow/{platform}-{product}` creee
653- [ ] Credentials disponibles dans .env
654- [ ] Exploration terminee
655- [ ] Cartographie JSON generee
656- [ ] ProductConfiguration creee et enregistree
657- [ ] Types FormData definis
658- [ ] Tous les mappers implementes
659- [ ] Tous les validators implementes
660- [ ] LeadTransformer fonctionnel
661- [ ] Tous les selectors definis avec stabilite
662- [ ] Toutes les operations implementees
663- [ ] FormFillOrchestrator complet
664- [ ] Fixtures de test creees
665- [ ] Tests single-lead passent (headless)
666- [ ] Tests bulk-validation passent 100% (headless)
667- [ ] Commits apres chaque etape majeure