Squash merge develop → master. - Fiche parent éditable (co-parent, PATCH fiche, GET /parents) - Fiche AM 3 onglets (PATCH fiche, rattacher/détacher enfants) - Table enfants_assistantes_maternelles + enum garde/sans_garde - Migration SQL + BDD.sql canonique - Correctifs recette : @Get() parents, DTO fiche AM, fix NIR Co-authored-by: Cursor <cursoragent@cursor.com>
245 lines
8.0 KiB
Markdown
245 lines
8.0 KiB
Markdown
# #112 — Alignement front après évolution back (reprise dossier complet)
|
||
|
||
**Branche déployée :** `feature/112-reprise-apres-refus-front`
|
||
**Commit back :** `d70577b1` — `feat(#112): reprise après refus — dossier complet GET/PATCH`
|
||
**Date :** 2026-06-16
|
||
|
||
Ce document décrit le **contrat API réel** après extension du back, et ce que le front doit encore brancher pour exploiter le dossier complet (au-delà de l’identité seule).
|
||
|
||
---
|
||
|
||
## 1. Endpoints (inchangés côté URL)
|
||
|
||
| Méthode | Route | Auth |
|
||
|---------|-------|------|
|
||
| `GET` | `/api/v1/auth/reprise-dossier?token={uuid}` | Public |
|
||
| `PATCH` | `/api/v1/auth/reprise-resoumettre` | Public |
|
||
| `POST` | `/api/v1/auth/reprise-identify` | Public (inchangé) |
|
||
|
||
> **Note :** le ticket #111 parlait de `PUT` ; l’implémentation reste en **`PATCH`** (comme avant).
|
||
|
||
---
|
||
|
||
## 2. `GET /auth/reprise-dossier` — réponse enrichie
|
||
|
||
### Champs communs (toujours présents)
|
||
|
||
Identiques à avant : `id`, `email`, `prenom`, `nom`, `telephone`, `adresse`, `ville`, `code_postal`, `numero_dossier`, `role`, `photo_url`, `genre`, `situation_familiale`.
|
||
|
||
### Rôle `parent` (+ champs #119)
|
||
|
||
Alignés sur `DossierFamilleCompletDto` :
|
||
|
||
```json
|
||
{
|
||
"parents": [
|
||
{
|
||
"user_id": "uuid",
|
||
"email": "…",
|
||
"prenom": "…",
|
||
"nom": "…",
|
||
"telephone": "…",
|
||
"adresse": "…",
|
||
"ville": "…",
|
||
"code_postal": "…",
|
||
"statut": "refuse",
|
||
"co_parent_id": "uuid-parent-entity"
|
||
}
|
||
],
|
||
"enfants": [
|
||
{
|
||
"id": "uuid-enfant",
|
||
"first_name": "Emma",
|
||
"last_name": "MARTIN",
|
||
"genre": "F",
|
||
"status": "actif",
|
||
"birth_date": "2023-02-15T00:00:00.000Z",
|
||
"due_date": null,
|
||
"photo_url": "/uploads/photos/…",
|
||
"consent_photo": true,
|
||
"est_multiple": false
|
||
}
|
||
],
|
||
"texte_motivation": "Nous recherchons…"
|
||
}
|
||
```
|
||
|
||
**Mapping front suggéré :**
|
||
|
||
| JSON back | Modèle / wizard parent |
|
||
|-----------|-------------------------|
|
||
| `parents[]` | `UserRegistrationData.parent1` + `parent2` (matcher par `email` ou ordre : titulaire = `id` du GET racine) |
|
||
| `enfants[].first_name` / `last_name` | `ChildData.firstName` / `lastName` |
|
||
| `enfants[].birth_date` | `ChildData.birthDate` (ISO → `DateTime`) |
|
||
| `enfants[].due_date` | `ChildData.dueDate` (enfant `a_naitre`) |
|
||
| `enfants[].status` | `actif` = né, `a_naitre` = à naître |
|
||
| `enfants[].photo_url` | `ApiConfig.absoluteMediaUrl()` + conserver pour reprise sans re-upload |
|
||
| `enfants[].id` | **Obligatoire** pour le PATCH (update par id) |
|
||
| `enfants[].est_multiple` | `grossesse_multiple` si utilisé |
|
||
| `texte_motivation` | étape présentation / motivation |
|
||
|
||
Si `numero_dossier` absent : pas de `parents[]` / `enfants[]` / `texte_motivation` (identité seule).
|
||
|
||
### Rôle `assistante_maternelle`
|
||
|
||
Champs racine + fiche pro (structure **aplatie**, pas de sous-objet `user`) :
|
||
|
||
```json
|
||
{
|
||
"consentement_photo": true,
|
||
"date_naissance": "1985-03-12T00:00:00.000Z",
|
||
"lieu_naissance_ville": "Paris",
|
||
"lieu_naissance_pays": "France",
|
||
"numero_agrement": "AGR-2024-12345",
|
||
"nir": "123456789012345",
|
||
"date_agrement": "2024-06-01T00:00:00.000Z",
|
||
"nb_max_enfants": 4,
|
||
"place_disponible": 2,
|
||
"biographie": "…"
|
||
}
|
||
```
|
||
|
||
**Mapping `AmRegistrationData` :**
|
||
|
||
| JSON back | Champ front |
|
||
|-----------|-------------|
|
||
| `nb_max_enfants` | `capaciteAccueil` |
|
||
| `place_disponible` | `placesDisponibles` |
|
||
| `numero_agrement` | `numeroAgrement` |
|
||
| `biographie` | `biographie` / présentation |
|
||
| `photo_url` | déjà géré via `RepriseSession.photoUrl` |
|
||
|
||
---
|
||
|
||
## 3. `PATCH /auth/reprise-resoumettre` — body étendu
|
||
|
||
### Commun
|
||
|
||
```json
|
||
{ "token": "uuid-reprise" }
|
||
```
|
||
|
||
### Parent — champs à envoyer depuis le wizard
|
||
|
||
| Champ PATCH | Source wizard | Notes |
|
||
|-------------|---------------|-------|
|
||
| `prenom`, `nom`, `telephone`, `adresse`, `ville`, `code_postal` | Parent 1 (titulaire token) | Champs racine |
|
||
| `co_parent_prenom`, `co_parent_nom`, `co_parent_telephone` | Parent 2 | |
|
||
| `co_parent_meme_adresse`, `co_parent_adresse`, `co_parent_code_postal`, `co_parent_ville` | Parent 2 adresse | |
|
||
| `texte_motivation` **ou** `presentation_dossier` | Étape motivation | Les deux alias acceptés |
|
||
| `enfants[]` | Liste enfants | Voir ci-dessous |
|
||
|
||
**Structure `enfants[]` (miroir inscription + `id` obligatoire) :**
|
||
|
||
```json
|
||
{
|
||
"id": "uuid-enfant-existant",
|
||
"prenom": "Emma",
|
||
"nom": "MARTIN",
|
||
"date_naissance": "2023-02-15",
|
||
"date_previsionnelle_naissance": null,
|
||
"genre": "F",
|
||
"photo_base64": "data:image/jpeg;base64,…",
|
||
"photo_filename": "emma.jpg",
|
||
"grossesse_multiple": false
|
||
}
|
||
```
|
||
|
||
- **v1 back :** update par `id` uniquement — pas de création/suppression d’enfant.
|
||
- Si `id` inconnu pour ce dossier → **400** `Enfant inconnu pour ce dossier : {id}`.
|
||
- Sans nouvelle photo : ne pas envoyer `photo_base64` (l’existant est conservé).
|
||
|
||
### AM — champs à envoyer
|
||
|
||
| Champ PATCH | Source |
|
||
|-------------|--------|
|
||
| Identité + `photo_url` ou `photo_base64` + `photo_filename` | Étapes 1–2 |
|
||
| `consentement_photo`, `date_naissance`, `lieu_naissance_ville`, `lieu_naissance_pays` | Identité |
|
||
| `numero_agrement`, `nir`, `date_agrement` | Pro |
|
||
| `capacite_accueil`, `places_disponibles` | Pro |
|
||
| `biographie` | Présentation |
|
||
|
||
Validation NIR identique à l’inscription si `nir` fourni.
|
||
|
||
### Réponse succès (nouveau format)
|
||
|
||
```json
|
||
{
|
||
"message": "Dossier resoumis avec succès. Il est de nouveau en attente de validation.",
|
||
"statut": "en_attente",
|
||
"user_id": "uuid",
|
||
"numero_dossier": "2026-000021"
|
||
}
|
||
```
|
||
|
||
Code HTTP : **200** (pas de corps `Users` brut comme l’ancien back).
|
||
|
||
### Effet métier
|
||
|
||
- **Parent :** tous les users `role=parent` avec le même `numero_dossier` passent en `en_attente` ; `token_reprise` invalidé sur **tous** (symétrique refus #110).
|
||
- **AM :** un seul user.
|
||
|
||
### E-mail accusé resoumission (parent)
|
||
|
||
Après `PATCH` réussi, un e-mail est envoyé à **chaque parent** du dossier (`sendResoumissionPendingEmail`) :
|
||
- confirmation de resoumission ;
|
||
- rappel du **numéro de dossier** ;
|
||
- mention « en attente de validation ».
|
||
|
||
Échec SMTP : logué, **ne bloque pas** la resoumission (même règle que l'inscription initiale).
|
||
|
||
---
|
||
|
||
## 4. Fichiers front à modifier (checklist)
|
||
|
||
### Modèles
|
||
|
||
- [ ] `lib/models/reprise_dossier.dart` — parser `parents[]`, `enfants[]`, `texte_motivation`, champs AM
|
||
- [ ] Réutiliser ou mapper vers `DossierFamilleEnfant` / structures existantes (#119 admin) si possible
|
||
|
||
### Session / préremplissage
|
||
|
||
- [ ] `lib/services/reprise_session.dart`
|
||
- `applyToParent` : remplir parent1/parent2 depuis `parents[]`, enfants, motivation
|
||
- `applyToAm` : remplir tous les champs AM
|
||
|
||
### API
|
||
|
||
- [ ] `lib/services/auth_service.dart` — `resoumettreReprise()` : accepter body complet (parent + AM), pas seulement identité
|
||
- [ ] Étendre `UserRegistrationData` / `AmRegistrationData` helpers `toReprisePatchBody()` si utile
|
||
|
||
### Écrans fin de parcours
|
||
|
||
- [ ] `parent_register_step5_screen.dart` — PATCH avec co-parent, enfants, motivation
|
||
- [ ] `am_register_step4_screen.dart` — PATCH avec fiche AM complète
|
||
|
||
### Hors scope back (inchangé)
|
||
|
||
RIB / IBAN / attestation CAF (étape 5 wizard parent) : **non persistés** — rien à envoyer en reprise.
|
||
|
||
### Non implémenté front (ticket #112 initial)
|
||
|
||
- [ ] Modale login « J’ai un numéro de dossier » → `POST /auth/reprise-identify` (back prêt, front absent)
|
||
|
||
---
|
||
|
||
## 5. Tests manuels suggérés
|
||
|
||
1. Refuser un dossier parent complet (≥1 enfant + co-parent + motivation).
|
||
2. Ouvrir le lien mail `/reprise?token=…`.
|
||
3. Vérifier dans DevTools que le GET contient `enfants[]` et `texte_motivation`.
|
||
4. Après branchement front : wizard prérempli sur toutes les étapes.
|
||
5. Resoumettre → statut `en_attente` pour les deux parents ; dossier visible file validation admin (#119).
|
||
|
||
---
|
||
|
||
## 6. Références code back
|
||
|
||
```
|
||
backend/src/routes/auth/dto/reprise-dossier.dto.ts
|
||
backend/src/routes/auth/dto/resoumettre-reprise.dto.ts
|
||
backend/src/routes/auth/dto/enfant-reprise.dto.ts
|
||
backend/src/routes/auth/auth.service.ts → getRepriseDossier, resoumettreReprise
|
||
backend/src/routes/parents/dto/dossier-famille-complet.dto.ts
|
||
```
|