# Extraction documentaire — LA PARCELLE

**SUIVI #1565** — extraction factuelle pour notice utilisateur Centre d’aide.  
**Aucun comportement modifié.** Constat de code uniquement.  
Date d’extraction : 2026-09-16.

Fiches `docs/suivi/` lues (section LEÇON) avant extraction : `SUIVI_1564` (état obligatoire des filles de division ; réunion reste sur défaut `reperee`), `SUIVI_1562` (totaux de surface = actives seulement ; remplacées visibles via filtre), `SUIVI_1563` (colonne Occup. à trois valeurs), `SUIVI_1533` (totaux SQL, pas reduce JS), `SUIVI_1510` (création unitaire + acte), `SUIVI_1452` (grille dossier / carte), `SUIVI_1466` (menu Prospection renommé Parcelles). Autres fiches croisées : `SUIVI_1109` (IGN), `SUIVI_1225` (promesse → sous compromis).

Convention de citation : `chemin/fichier.ext:ligne`.  
Si un point n’est pas établi par le code : **NON DÉTERMINÉ**.

---

## 1. MODÈLE DE DONNÉES

### 1.1 Table `parcelles`

Création : `database/migrations/2026_07_30_140100_create_parcelles_table.php:16-47`.  
Unicité métier initiale : `(code_insee_commune, section_cadastrale, numero)` (`140100:9-10`, unique `parcelles_commune_section_numero_uq`). Remplacée ensuite par l’unicité **vivante** (voir 1.8).

| Colonne | Type (migrations) | Nullable | Défaut | Index / FK |
|---|---|---|---|---|
| `id` | bigint PK | non | auto | PK |
| `section_cadastrale` | string(16) | non | — | partie unique vivante |
| `numero` | string(32) | non | — | partie unique vivante |
| `code_insee_commune` | string(5) | non | — | FK `communes.code_insee` **restrictOnDelete** `parcelles_commune_fk` (`140100:34-37`) ; index `parcelles_code_insee_commune_idx` (`2026_08_07_170000:57-60`) |
| `surface_cadastrale_m2` | decimal(14,2) | oui | NULL | — |
| `surface_arpentee_m2` | decimal(14,2) | oui | NULL | — |
| `date_arpentage` | date | oui | NULL | — |
| `bornage` | string(32) | oui | NULL | `#1446` `2026_09_04_144600:17-20` |
| `date_bornage_effective` | date | oui | NULL | `144600:22-25` |
| `centroide_lat` | decimal(10,7) | oui | NULL | — |
| `centroide_lng` | decimal(10,7) | oui | NULL | — |
| `zonage_plu` | string | oui | NULL | — |
| `lieu_dit` | string(255) | oui | NULL | `2026_07_30_160000` |
| `constructible` | **VARCHAR(32)** (était boolean) | oui | NULL | index `parcelles_constructible_idx` ; conversion `#1242/#1247` `2026_08_07_151000:37-52` |
| `risque_inondable` | boolean | non | `false` | index `parcelles_inondable_idx` |
| `risque_feu_foret` | boolean | non | `false` | `144600:27-30` |
| `bati_present` | boolean | oui | NULL | `144600:32-35` |
| `etat_foncier` | string(32) | non | `'reperee'` | index `parcelles_etat_idx` |
| `type_foncier` | string(32) | oui | NULL | index `parcelles_type_foncier_idx` (`151000:25-34`) |
| `societe_detentrice_id` | unsignedBigInteger | oui | NULL | FK `entites.id` **nullOnDelete** `parcelles_societe_detentrice_fk` (`2026_08_07_161000`) |
| `statut_cadastral` | string(16) | non | `'active'` | index `parcelles_statut_cad_idx` |
| `commentaire` | text | oui | NULL | — |
| `occupation_absente_at` | timestamp | oui | NULL | `#1563` `2026_09_15_161000` |
| `occupation_absente_par_id` | unsignedBigInteger | oui | NULL | FK `users.id` **nullOnDelete** |
| `createur_id` | foreignId | oui | NULL | FK `users` **nullOnDelete** (`2026_07_31_100200`) |
| `created_at` / `updated_at` | timestamps | oui | NULL | — |
| `deleted_at` | softDeletes | oui | NULL | index `parcelles_deleted_at_idx` |
| `deleted_by` | foreignId | oui | NULL | FK `users` **nullOnDelete** |
| `parcelle_vivante` | tinyint **STORED** | oui | `CASE WHEN deleted_at IS NULL THEN 1 ELSE NULL END` | UNIQUE `(code_insee_commune, section_cadastrale, numero, parcelle_vivante)` `parcelles_commune_section_numero_vivante_uq` (`2026_08_07_170000:69-84`) |

**onUpdate des FK :** jamais déclaré dans les migrations lues → **NON DÉTERMINÉ** (comportement MySQL / Laravel par défaut).

Casts modèle : `app/Models/Parcelle.php:127-141` (`decimal:2` surfaces, `decimal:7` centroïdes, dates, booléens, `occupation_absente_at` datetime).

`$fillable` : `Parcelle.php:99-122`. Les colonnes `occupation_absente_at` / `occupation_absente_par_id` sont **hors fillable** ; écriture via `forceFill` (`Parcelle.php:314-330`).

### 1.2 Tables liées

#### `parcelle_geometries` — `2026_07_30_140200:33-47` (MySQL)

| Colonne | Type | Null | Défaut | Contraintes |
|---|---|---|---|---|
| `id` | BIGINT UNSIGNED AI | non | — | PK |
| `parcelle_id` | BIGINT UNSIGNED | non | — | UNIQUE ; FK `parcelles(id)` **ON DELETE CASCADE** |
| `geom` | GEOMETRY NOT NULL SRID 4326 | non | — | SPATIAL INDEX |
| `source` | VARCHAR(32) | non | `'manuel'` | — |
| `date_maj` | TIMESTAMP | oui | NULL | — |
| timestamps | TIMESTAMP | oui | NULL | — |

SQLite tests : `geom` = `text` (`140200:20-28`). Cardinalité : **1 parcelle → 0..1 géométrie** (`Parcelle::geometrie` HasOne, `Parcelle.php:237-239`).

#### `parcelle_proprietaire` (détentions)

CREATE `2026_07_30_140300` ; étendue `2026_07_30_170000` ; unique courante `2026_07_30_170400` ; FK acte `2026_07_30_170200`.

| Colonne | Type | Null | Contraintes |
|---|---|---|---|
| `parcelle_id` | FK | non | cascadeOnDelete |
| `proprietaire_id` | FK | non | cascadeOnDelete |
| `quote_part` | decimal(8,4) | oui | — |
| `date_debut_detention` | date | oui | — |
| `date_fin_detention` | date | oui | index fin |
| `detention_courante` | tinyint STORED | oui | UNIQUE `(parcelle_id, proprietaire_id, detention_courante)` |
| `acte_foncier_id` | unsignedBigInteger | oui | FK `actes_fonciers` **nullOnDelete** |

Cardinalité : parcelle **N⇄N** propriétaires, avec historique (plusieurs lignes ; courante = `date_fin_detention` NULL). Modèle : `ParcelleDetention`. Écart : cast modèle `decimal:6` vs migration `decimal(8,4)` — **constat** (voir §10).

#### `parcelle_occupations` — `2026_07_31_130000` + `144600`

| Colonne | Type | Null | Défaut | FK |
|---|---|---|---|---|
| `parcelle_id` | FK | non | — | cascadeOnDelete |
| `statut_occupation` | string(40) | non | — | — |
| `occupant_nom` | string(255) | oui | — | — |
| `part_pct` | decimal(5,2) | oui | — | — |
| `date_fin_bail` | date | oui | — | — |
| `date_echeance` | date | oui | — | `#1446` |
| `preavis_mois` | unsignedSmallInteger | oui | — | — |
| `indemnite_eviction_estimee` / `_reelle` | decimal(14,2) | oui | — | — |
| `statut` | string(20) | non | `'a_traiter'` | suivi |
| `commentaire` | text | oui | — | — |
| `createur_id` | FK users | oui | — | nullOnDelete |
| `tache_suivi_id` | FK `taches_suivi` | oui | — | nullOnDelete |

Cardinalité : **1 parcelle → N occupations**. Pas d’unicité sur `parcelle_id`.

#### `parcelle_batis` — `2026_08_07_151000:56-67` + `144600:39-49`

| Colonne | Type | Null | FK |
|---|---|---|---|
| `parcelle_id` | FK | non | cascadeOnDelete |
| `etat` | string(32) | non | — |
| `surface_m2` | decimal(14,2) | oui | `#1446` |
| `annee_construction` | unsignedSmallInteger | oui | `#1446` |
| `commentaire` | text | oui | — |

Cardinalité : **1 parcelle → N bâtis** (`Parcelle.php:342-348`).

#### `parcelle_filiations` — `2026_07_31_190000:28-36`

Arcs **source → issue**. JAMAIS de `mere_id` sur `parcelles` (commentaire migration `:9`).

| Colonne | Type | Null | FK / index |
|---|---|---|---|
| `parcelle_source_id` | FK | non | restrictOnDelete |
| `parcelle_issue_id` | FK | non | restrictOnDelete |
| `type` | string(40) | non | — |
| `date_operation` | date | oui | — |
| `reference_da` | string(120) | oui | — |
| `geometre_fournisseur_id` | unsignedBigInteger | oui | FK fournisseurs nullOnDelete (si table) |
| `commentaire` | text | oui | — |
| `createur_id` | FK users | oui | nullOnDelete |
| UNIQUE | `(parcelle_source_id, parcelle_issue_id)` | | |

Cardinalité : parcelle **N arcs** comme source et **N arcs** comme issue (`Parcelle.php:390-403`).

#### `parcelle_valorisations` — `2026_07_31_180000`

`parcelle_id` cascadeOnDelete ; `date_valorisation` date NOT NULL ; `valeur` decimal(15,2) NOT NULL ; `methode` string(40) NOT NULL ; `auteur_id` users nullOnDelete.

#### Pivots

| Table | Migration | Cardinalité | onDelete |
|---|---|---|---|
| `acte_parcelle` | `2026_07_30_170300` + `surface_acquise_m2` via `2026_07_31_150000` | N⇄N acte ↔ parcelle ; UNIQUE `(acte, parcelle)` | acte cascade ; parcelle **restrict** |
| `promesse_parcelle` | `2026_07_30_180100` | N⇄N ; pivot `surface_promise_m2` | promesse cascade ; parcelle restrict |
| `offre_parcelle` | `2026_07_30_230000` | N⇄N ; `surface_souhaitee_m2` | offre cascade ; parcelle restrict |
| `dossier_foncier_parcelle` | `2026_07_30_150300` + `origine` `2026_08_12_150000` default `'detention'` | N⇄N ; UNIQUE dossier+parcelle | dossier cascade ; parcelle restrict |
| `scenario_parcelle` | `2026_07_31_230100` | N⇄N ; `surface_retenue_m2`, `hypothetique` | scenario cascade ; parcelle restrict |

#### `charges_portage` — `2026_07_31_170000`

`parcelle_id` **nullable**, **nullOnDelete**. UI fiche parcelle **masquée** (`AFFICHER_CHARGES_PORTAGE = false`, `Show.vue` — voir §2).

### 1.3 Colonnes JSON

**Aucune colonne MySQL JSON** sur `parcelles` ni sur les tables listées ci-dessus.

`parcelle_geometries.geom` = **GEOMETRY** (MySQL) ou texte GeoJSON (sqlite). Usage : `ST_GeomFromGeoJSON` / `ST_AsGeoJSON` via `ParcelleGeometrie::upsertFromGeoJson`. Structure attendue : objet GeoJSON avec `type` + `coordinates` (`IgnCadastreParcelleService.php:179-191`). Exemple réel de contenu en base : **NON DÉTERMINÉ** (pas lu en production).

### 1.4 Accessors, scopes, méthodes calculées (`Parcelle`)

| Kind | Nom | Citation |
|---|---|---|
| Scope | `scopeActivesCadastre` — `statut_cadastral = active` | `Parcelle.php:366-371` |
| Méthode | `estRemplacee()` | `Parcelle.php:374-377` |
| Méthode | `statutCadastralLibelle()`, `etatLibelle()`, `constructibleLibelle()`, `typeFoncierLibelle()`, `referenceCadastrale()` | `Parcelle.php:379-428` |
| Méthode | `aMarqueurPasOccupation()`, `occupationEtatListe()`, `poserMarqueurPasOccupation()`, `leverMarqueurPasOccupation()` | `Parcelle.php:284-331` |
| Scope global | `HasFoncierParcelleVisibilite` → `FoncierParcelleVisibiliteScope` | trait + `Parcelle.php:21` |

Pas d’`Attribute::` / `getXxxAttribute` sur `Parcelle`. Pas de `bornageLibelle()` sur le modèle.

### 1.5 Soft delete, historisation, traçabilité

| Mécanisme | Fait | Citation |
|---|---|---|
| SoftDeletes | Oui, modèle `Parcelle` uniquement parmi les modèles parcelle listés | `Parcelle.php:22` |
| `deleted_by` | Oui | `Parcelle.php:157-159` |
| `parcelle_vivante` | Colonne générée pour unicité cadastrale | `2026_08_07_170000:69-84` |
| Audit champs | Trait `AuditsFieldChanges` ; liste exclusive `auditedFields()` | `Parcelle.php:19`, `31-54` |
| Champs sensibles audit | Aucun sur parcelle (`sensitiveAuditedFields` vide) | `Parcelle.php:62-65` |
| `createur_id` | Oui | fillable + relation |
| `created_by` / `updated_by` | **Absents** de `parcelles` | fillable `99-122` |
| Journal utilisateur (`journal_mises_a_jour`) | Pas de colonne sur parcelle | — |
| Commentaires entité | Trait `HasEntiteCommentaires` | `Parcelle.php:20` |

---

## 2. CARTOGRAPHIE DES ÉCRANS

Préfixe routes : `/foncier` · nom `foncier.*` · middleware `feature.permission:foncier.lecture` + `foncier.module` (`routes/web.php:783-786`).

### Accès menu

Chemin : header → bouton **Foncier** → **Parcelles** (`AppShell.vue:1176`, `1192-1201`).  
URL : `/foncier/prospection` (constante `FONCIER_NAV_PROSPECTION`).  
Autres items du sous-menu Foncier : **Dossiers**, **Actes**, **Secteurs**, **Groupe de travail**, **Corbeille** (si `userCan('foncier.corbeille')`, `AppShell.vue:1247-1258`).

### 2.1 Liste principale « Parcelles »

| | |
|---|---|
| Nom affiché | `Parcelles` (h1 uppercase) `Prospection/Index.vue:580` |
| URL / route | `GET /foncier/prospection` · `foncier.prospection.index` |
| Vue | `resources/js/Pages/Foncier/Prospection/Index.vue` |
| Controller | `ProspectionController@index` |
| Accès | Foncier → **Parcelles** |

Sous-titre : « Parcelles et propriétaires — un seul référentiel, trois lectures. » (`:581-582`).

Mode d’affichage (select **Mode d’affichage**) — `ProspectionController.php:50-54` : `Par parcelle` (`parcelle`) / `Par propriétaire` (`proprietaire`) / `Par commune` (`commune`).

**CTA (si `peut_gestion` et mode parcelle)**  
- **Ajouter multiparcelle** (`:597-602`)  
- **Nouvelle parcelle** (`:604-613`) → `/foncier/parcelles/create`

**Filtres visibles** : Recherche (placeholder « Section, numéro, commune, propriétaire… ») ; **Commune** ; **Constructible** ; **Type foncier** ; **Filtrer** ; **Filtres (N)** ; case **Afficher les parcelles remplacées** (`:723`).

**Filtres avancés** : **Département**, **Inondable**, **Occupation** (`Tous` / `Occupée` / `Pas d’occupation` / `Non vérifié`), **Mon secteur**, **Grouper par secteur**, **Détenue par le groupe**, **Appliquer les filtres** (`:739-787`).

**Colonnes grille (11)** (`:855-896`) : Commune · Référence · Propriétaire(s) · Surface · État · Zonage · Constr. · Occup. · Acte · Valorisation · Référent.

Occup. affiche `Oui` / `Non` / `—` (`occupationListeLabel`, `:104-107`).

**Pied** : « N parcelle(s) · M remplacée(s) · dont K détenue(s) » + surface + note « Surface et détenues : parcelles actives au cadastre… » (`:1115-1128`).

**Action ligne** : clic référence → fiche `/foncier/parcelles/{id}`.

Section **Propriétaires sans parcelle** (repliable) (`:1154-1168`).

### 2.2 `Parcelles/Index.vue` — non rendu en navigation normale

`GET /foncier/parcelles` · `foncier.parcelles.index` · `ParcelleController@index` **redirige** vers `foncier.prospection.index` + `mode=parcelle` (`ParcelleController.php:84-89`).  
Le composant `resources/js/Pages/Foncier/Parcelles/Index.vue` n’est pas `Inertia::render` par cette action.

### 2.3 Création unitaire

| | |
|---|---|
| Nom | `Nouvelle parcelle` `Create.vue:265` |
| URL | `GET /foncier/parcelles/create` · `foncier.parcelles.create` |
| POST | `foncier.parcelles.store-unitaire` `/parcelles/saisie-complete` |
| Vue | `Foncier/Parcelles/Create.vue` |
| Controller | `ParcelleController@create` / `@storeUnitaire` |
| Accès | Liste → **Nouvelle parcelle** |

Retour : `← Parcelles` → `/foncier/parcelles` (donc redirect prospection) (`Create.vue:264`).

Blocs : **Identification** ; **Infos avancées** (Déplier / Replier) ; **Propriété** (boutons **Détenue par le groupe** / **Propriétaire externe**) ; **Acte de vente** (radio **Non** / **Rattacher à un acte existant** / **Créer un nouvel acte**).

Actions : **Enregistrer** · **Annuler**. Flash succès : `Parcelle créée.` (`ParcelleController.php:183`).

### 2.4 Import batch (multiparcelle)

| | |
|---|---|
| Nom | Dialog `Ajouter multiparcelle` |
| Composant | `Components/Foncier/Prospection/ProspectionSaisieDialog.vue` |
| Endpoint | `POST /foncier/parcelles/batch` · `foncier.parcelles.store-batch` · `ParcelleController@storeBatch` |
| Accès | Liste (mode parcelle) → **Ajouter multiparcelle** |

Colonnes grille : Section* · Numéro* · Commune* · Surface cad. · État foncier* · Société détentrice (si droit).  
Actions : **Ajouter une ligne** · **Annuler** · **Enregistrer**.  
Confirm fermeture sale : « Des valeurs ont été saisies. Fermer sans enregistrer ? »

### 2.5 Fiche parcelle

| | |
|---|---|
| Nom | h1 = `lieu_dit` ou `Sans lieu-dit` + badge état `Show.vue:750-754` |
| URL | `GET /foncier/parcelles/{id}` · `foncier.parcelles.show` |
| Vue | `Foncier/Parcelles/Show.vue` |
| Controller | `ParcelleController@show` |
| Accès | Liste → clic référence ; dossier ; propriétaire ; acte ; nav fiche |

Retour : `← Parcelles` → `/foncier/prospection?mode=parcelle` (`:745`).

Hint : « Pour modifier, cliquez sur une valeur » (`:1205`) — édition **inline**.

**Actions header (`peut_gestion`)**

| Libellé exact | Condition | Citation |
|---|---|---|
| **Diviser** | `operation_cadastrale.peut_operer` | `:794-800` |
| **Réunir** | idem | `:802-808` |
| **Déclarer une acquisition** | | `:810-811` → `/foncier/actes-fonciers/create?parcelle_id=` |
| **Mettre en corbeille** | | `:813-821` |
| aria **Historique de la parcelle** | | `:823-828` |

`peut_operer` = `peutGestion && ! $parcelle->estRemplacee()` (`ParcelleController.php:434-435`).

**Blocs** : Actes d’acquisition ; Filiation cadastrale (Issue de / A donné / Ascendance / Descendance) ; Identification ; Surfaces & bornage ; Urbanisme ; Bâti ; Commentaire ; Occupation du terrain ; Valorisations ; Propriétaire(s) actuel(s) + Anciens ; Plan cadastral ; navigation gauche `ParcelleFicheNavigation`.

**Charges de portage** : UI présente mais `AFFICHER_CHARGES_PORTAGE = false` — **non visible**.

Bandeau remplacée : « **Parcelle remplacée au cadastre** — elle n’apparaît dans la liste que si « Afficher les parcelles remplacées » est coché. » (`:769-770`).

### 2.6 Overlay division

Titre : `Diviser {reference}` (`Show.vue:1020`).  
Accès : fiche → **Diviser**.  
Actions : **Ajouter une fille** · **Annuler** · **Enregistrer la division**.  
**Pas de `confirm()`** avant submit (`:1112-1113`).  
POST `foncier.parcelles.diviser`.

Texte d’aide : « Crée N parcelles filles (actives), passe cette parcelle en remplacée. […] Chaque fille doit avoir un état foncier (vide par défaut — à choisir). » (`:1021-1025`).

### 2.7 Overlay réunion

Titre : `Réunir avec {reference}` (`:1125`).  
Accès : fiche → **Réunir**.  
Actions : **Annuler** · **Enregistrer la réunion**.  
**Pas de `confirm()`**.  
POST `foncier.parcelles.reunir`.

### 2.8 Dialogs fiche (bâti, occupation, valorisation, historique)

| Header | Actions | Endpoint |
|---|---|---|
| `Ajouter un bâti` | **Annuler** · **Enregistrer le bâti** | `foncier.parcelles.batis.store` |
| `Ajouter une occupation` | **Annuler** · **Enregistrer l’occupation** | `foncier.parcelles.occupations.store` |
| `Ajouter une valorisation` | **Annuler** · **Enregistrer la valorisation** | `foncier.parcelles.valorisations.store` |
| `Historique de la parcelle` | lecture | FieldAudit |

Occupation : boutons **Libérer**, **Pas d’occupation**, **Retirer le constat**.

### 2.9 Plan cadastral (bloc fiche)

Titre **Plan cadastral** (`:2486`).  
Bouton **Récupérer le contour cadastral** (`:2501`).  
Label GeoJSON : `GeoJSON polygone (saisie manuelle — repli)` + **Enregistrer la géométrie** (`:2521-2523`).  
Carte : `ParcelleMap.vue`.  
Vide : « Pas de carte à afficher : cette parcelle n’a pas encore de géométrie. » (`:2517`).  
Contour absent : « Aucun contour en base — récupérez le cadastre IGN ou saisissez un GeoJSON. » (`:2495`).

**Il n’existe pas d’écran « recherche cadastrale IGN » pour créer une parcelle.** La commune se cherche via `CommuneSelect` (`foncier.communes.search`). Le contour IGN s’importe **après** existence de la parcelle.

### 2.10 Page Form (édition URL directe)

| | |
|---|---|
| Nom | `Modifier la parcelle` (`Form.vue`) |
| URL | `GET /foncier/parcelles/{id}/edit` · `foncier.parcelles.edit` |
| Vue | `Foncier/Parcelles/Form.vue` `mode: 'edit'` |
| Accès UI | **Aucun lien trouvé** depuis Show / liste — URL directe seulement |

Actions : **Annuler** · **Enregistrer**. Branche create de `Form.vue` : **non utilisée** par `create()` (qui rend `Create.vue`).

### 2.11 Corbeille

| | |
|---|---|
| Nom | `Corbeille des parcelles` `Corbeille.vue:38` |
| URL | `GET /foncier/parcelles/corbeille` · `foncier.parcelles.corbeille.index` |
| Accès | Foncier → **Corbeille** (permission `foncier.corbeille`) |

Colonnes DataTable (`Corbeille.vue:55-99`) : **Référence** · **Commune** · **État foncier** (`etat_libelle`) · **Rattachements** · **Supprimée le** · **Supprimée par** · **Actions**. Vide : « Aucune parcelle en corbeille. » (`:102-103`).  
Action : **Restaurer** — confirm `Restaurer la parcelle {reference} ?` (`Corbeille.vue:24`).  
Texte : « Parcelles soft-supprimées — restauration possible. Aucune suppression définitive ici. » (`:41`).

### 2.12 Navigation fiche

`ParcelleFicheNavigation.vue` · `GET /foncier/parcelles/{id}/navigation` · `foncier.parcelles.navigation`.  
Labels : aria `Parcelles voisines` ; panel **Parcelles** ; placeholder « Section, numéro ou lieu-dit » ; sections **Dossiers**, **Dossier (N)**, `{commune} (N)`, **Autres communes**.

### 2.13 Dossier — onglet Synthèse (emprise)

Onglet **Synthèse** (`Dossiers/Show.vue`). Composant `DossierSyntheseTab.vue`.  
Blocs parcelle : **Parcelles et propriétaires** (`:395`) · **Emprise du dossier** (`:444`).  
Lien **Voir le foncier →**.  
IGN : **Récupérer le contour** / **Récupérer les contours manquants** (`:508`). Sous-titre : `{tracées}/{total} tracée(s)` (`:110-113`).  
Badge liste aperçu : `Acheté le {date}` ou `Acheté` (`:243-248`). Badge carte polygone : `ACHETÉ` (`ParcelleMap.vue:93`).

### 2.14 Dossier — onglet FONCIER

Titre **Foncier — matière première**.  
Actions : **Choisir des parcelles** (dialog `Choisir des parcelles — {label}` · **Rattacher (détention)**) ; **Ajouter des parcelles** (dialog `Ajouter des parcelles — {label}` · **Enregistrer**) ; **Retirer du dossier**.

Hors périmètre notice : création de dossier, phases, autres onglets.

### 2.15 Acte rattaché à une parcelle

Depuis fiche : **Déclarer une acquisition** → `GET /foncier/actes-fonciers/create?parcelle_id=`.  
Depuis création unitaire : bloc **Acte de vente**.  
Liste des actes sur la fiche : bloc **Actes d’acquisition**.

### 2.16 Composants orphelins / legacy

| Fichier | Statut constaté |
|---|---|
| `ParcellePanel.vue` | Aucun import trouvé dans `resources/js` |
| `Parcelles/Index.vue` | Redirect ; non rendu Inertia |
| Charges portage Show | Flag `false` |

---

## 3. CHAMPS DE SAISIE — TABLEAU EXHAUSTIF

### 3.1 Mappings de choix (référentiel unique)

Source : `app/Support/Foncier/FoncierReferentiels.php` — « source unique front + back » (`:5-7`).

#### État foncier — `ETATS_FONCIERS` (`:31-46`)

| Libellé affiché | Valeur postée / DB | Libellé back |
|---|---|---|
| Repérée | `reperee` | Repérée |
| En négociation | `en_negociation` | En négociation |
| Sous compromis | `sous_compromis` | Sous compromis |
| Acquise | `acquise` | Acquise |
| Affectée | `affectee` | Affectée |
| Pas d'action | `pas_d_action` | Pas d'action |
| Projet abandonné | `projet_abandonne` | Projet abandonné |
| Réserve foncière | `reserve_fonciere` | Réserve foncière |
| Opportunité | `opportunite` | Opportunité |
| Bouchon | `bouchon` | Bouchon |
| Vendue client | `vendue_client` | Vendue client |
| Cession | `cession` | Cession |
| Rétrocession | `retrocession` | Rétrocession |
| Autre | `autre` | Autre |

Front : placeholder « Choisir… » / `null` (création, batch, filles division) — **pas** dans le référentiel.

#### Constructibilité — `CONSTRUCTIBILITES` (`:196-202`)

| Affiché | Valeur | Back |
|---|---|---|
| Non renseigné *(front only)* | `null` | non renseigné (`libelleConstructible`) |
| Oui | `oui` | Oui |
| Pour partie | `pour_partie` | Pour partie |
| Potentiel | `potentiel` | Potentiel |
| À devenir | `a_devenir` | À devenir |
| Jamais | `jamais` | Jamais |

BC normalize (`ParcelleCreationService`) : `true/1/'true'` → `oui` ; `false/0/'false'` → `jamais`.

#### Bornage — `BORNAGES` (`:177-181`)

Oui=`oui` · Non=`non` · En cours=`en_cours` · NULL = non renseigné (commentaire `:168`).

#### Type foncier — `TYPES_FONCIER` (`:160-166`)

Réserve foncière=`reserve_fonciere` · Opportunité=`opportunite` · Bouchon=`bouchon` · Cession=`cession` · Rétrocession=`retrocession`.

**Ces 5 codes sont aussi des valeurs de `etat_foncier`** (`ETATS_FONCIERS` `:39-44`). Colonne `type_foncier` existe toujours (`Parcelle.php:113`).

#### Statut cadastral — `STATUTS_CADASTRAL` (`:142-145`)

Active=`active` · Remplacée=`remplacee`.

#### Occupation terrain — `STATUTS_OCCUPATION_TERRAIN` (`:90-97`)

Propriétaire occupant=`proprietaire_occupant` · Bail rural / fermage=`bail_rural_fermage` · Bail commercial=`bail_commercial` · Convention précaire=`convention_precaire` · Occupant sans titre=`occupant_sans_titre` · Libre=`libre`.

#### Suivi occupation — `STATUTS_SUIVI_OCCUPATION` (`:106-110`)

À traiter=`a_traiter` · Négocié=`negocie` · Libéré=`libere`.

#### État bâti — `ETATS_BATI` (`:213-217`)

Neuf=`neuf` · À rénover=`a_renover` · À détruire=`a_detruire`.

#### Types propriétaire — `TYPES_PROPRIETAIRE` (`:128-135`)

Personne physique=`physique` · Personne morale=`morale` · Indivision=`indivision` · SCI=`sci` · Collectivité=`collectivite` · Société du groupe=`societe_groupe`.

#### Propriété / acte (création unitaire)

| Affiché (`Create.vue`) | Valeur | Back |
|---|---|---|
| Détenue par le groupe | `groupe` | groupe |
| Propriétaire externe | `externe` | externe |
| Non | `non` | non |
| Rattacher à un acte existant | `rattacher` | rattacher |
| Créer un nouvel acte | `creer` | creer |

#### Bâti présent (création) — `Create.vue:85-89`

Non renseigné=`null` · Oui=`true` · Non=`false`.

#### Filtre occupation liste (`Index.vue:761-765`)

Occupée=`oui` · Pas d’occupation=`non` · Non vérifié=`indetermine`.

#### Filiation — `TYPES_FILIATION` (`:229-234`)

Division=`division` · Réunion=`reunion` · Remembrement=`remembrement` · Alignement=`alignement`.  
**UI actuelle** : division et réunion seulement (`ParcelleOperationCadastraleService`). Remembrement / alignement : pas d’écran trouvé.

#### Géométrie `source`

manuel / ign / cadastre_gouv (`FoncierReferentiels.php:249-253`). UI manuelle poste `manuel`. IGN poste via service `'ign'`.

#### Méthodes valorisation — `METHODES_VALORISATION` (`:528+`)

Expertise=`expertise` · Comparaison=`comparaison` · Charge foncière=`charge_fonciere` · Interne=`interne` · Autre=`autre`.

### 3.2 Whitelist `updateChamp` parcelle

`ParcelleController::champsInlineAutorises()` `ParcelleController.php:59-79` :

`section_cadastrale`, `numero`, `surface_cadastrale_m2`, `surface_arpentee_m2`, `date_arpentage`, `bornage`, `date_bornage_effective`, `zonage_plu`, `constructible`, `type_foncier`, `societe_detentrice_id`, `risque_inondable`, `risque_feu_foret`, `bati_present`, `lieu_dit`, `commentaire`, `etat_foncier`.

Payload `{ champ, valeur }`. **Hors whitelist** : `code_insee_commune`, `statut_cadastral`, `centroide_*`.

Occupation whitelist : `ParcelleOccupationController.php:33-46`.  
Bâti whitelist : `ParcelleBatiController.php:32-35` (`etat`, `commentaire`, `surface_m2`, `annee_construction`).

### 3.3 Tableau des champs

Règles : `parcelleFieldRules` `ParcelleController.php:924-948` ; unitaire `ParcelleCreationUnitaireService.php:132-210` ; batch `ParcelleCreationService::rulesCreateBatch`.

| Écran | Libellé affiché | Type | Obligatoire ? | Valeur postée | Libellé back | Règle de validation | Défaut | Format |
|---|---|---|---|---|---|---|---|---|
| Prospection Index | Recherche | input | non | `q` | — | trim | `''` | texte |
| Prospection Index | Commune | select | non | `code_insee` | — | code INSEE | Toutes | string 5 |
| Prospection Index | Constructible | select | non | `constructible` | Constructible | ∈ CONSTRUCTIBILITES sinon ignoré | Tous | code |
| Prospection Index | Type foncier | select | non | `type_foncier` | Type foncier | ∈ TYPES_FONCIER | Tous | code |
| Prospection Index | Afficher les parcelles remplacées | checkbox | non | `inclure_remplacees` | — | truthy → 1 | off | `1` |
| Prospection Index | Département | select | non | `departement` | — | string | Tous | string |
| Prospection Index | Inondable | select | non | `risque_inondable` | Risque inondable | `1`/`0` | Tous | 0\|1 |
| Prospection Index | Occupation | select | non | `occupee` | — | oui\|non\|indetermine | Tous | string |
| Prospection Index | (pastilles) État | boutons multi | non | `etats[]` | État foncier | codes ETATS | [] | array |
| Prospection Index | Mon secteur | checkbox | non | `mon_secteur` | — | 0\|1 ; défaut serveur ON | ON | 0\|1 |
| Prospection Index | Grouper par secteur | checkbox | non | `grouper_par_charge` | — | 0\|1 | off | 0\|1 |
| Prospection Index | Détenue par le groupe | checkbox | non | `detenue_par_le_groupe` | — | truthy | off | 1 |
| Create | Section* | input | oui | `section_cadastrale` | Section cadastrale | required max:16 + normalize IGN | `''` | string |
| Create | Numéro* | input | oui | `numero` | Numéro | required max:32 | `''` | string |
| Create | Commune* | CommuneSelect | oui | `code_insee_commune` | Commune | required size:5 exists:communes | query | INSEE |
| Create | Surface cad. m² | InputNumber | non | `surface_cadastrale_m2` | Surface cadastrale | nullable numeric min:0 | null | decimal |
| Create | État foncier* | select | oui | `etat_foncier` | État foncier | required in ETATS | null | code |
| Create | Surface arpentée m² | InputNumber | non | `surface_arpentee_m2` | Surface arpentée | nullable min:0 | null | decimal |
| Create | Date d’arpentage | date | non | `date_arpentage` | Date d’arpentage | nullable date | null | Y-m-d |
| Create | Bornage | select | non | `bornage` | Bornage | nullable in BORNAGES | null | code |
| Create | Date de bornage effective | date | non | `date_bornage_effective` | Date de bornage effective | nullable date | null | Y-m-d |
| Create | Zonage PLU | input | non | `zonage_plu` | Zonage PLU | nullable max:255 | `''` | string |
| Create | Constructible | select | non | `constructible` | Constructible | nullable in CONSTRUCTIBILITES | null | code |
| Create | Risque inondable | checkbox | non | `risque_inondable` | Risque inondable | bool | false | 0\|1 |
| Create | Risque feu de forêt | checkbox | non | `risque_feu_foret` | Risque feu de forêt | bool | false | 0\|1 |
| Create | Bâti présent | select | non | `bati_present` | Bâti présent | nullable bool | null | true\|false\|null |
| Create | Lieu-dit | input | non | `lieu_dit` | Lieu-dit | nullable max:255 | `''` | string |
| Create | Type foncier | select | non | `type_foncier` | Type foncier | nullable in TYPES | null | code |
| Create | Commentaire | textarea | non | `commentaire` | Commentaire | nullable max:65535 | `''` | string |
| Create | Propriété (boutons) | segmented | oui | `propriete_mode` | Propriété | required groupe\|externe | null | string |
| Create | Société détentrice* | select | si groupe | `societe_detentrice_id` | Société détentrice | requiredIf groupe, exists:entites | null | int |
| Create | Propriétaire | select | non | `proprietaire_id` | Propriétaire | nullable exists:proprietaires | null | int |
| Create | Acte de vente | radio | oui | `acte_mode` | Acte de vente | required non\|rattacher\|creer | `non` | string |
| Create | Acte existant* | AutoComplete | si rattacher | `acte_id` | Acte existant | requiredIf rattacher | null | int |
| Create | Société acquéreuse* | select | si creer | `acte_societe_acquereur_id` | Société acquéreuse | requiredIf creer | null | int |
| Create | Date de l’acte* | date | si creer | `acte_date_acte` | Date de l’acte | requiredIf creer | today | Y-m-d |
| Create | Prix d’achat* | InputNumber | si creer | `acte_prix_numeraire` | Prix d’achat | requiredIf creer min:0 | null | decimal |
| Create | Référence de l’acte | input | non | `acte_reference_acte` | — | nullable max:255 | `''` | string |
| Create | Promesse (optionnel) | AutoComplete | non | `acte_promesse_id` | — | nullable exists:promesses | null | int |
| Create | Notaire (fournisseur Intacct) | AutoComplete | non | `acte_notaire_fournisseur_id` | — | nullable exists:fournisseurs | null | int |
| Create | *(pas d’UI)* | — | non | `surface_acquise_m2` | — | nullable min:0 | toujours null posté | decimal |
| Batch | Section* | input | oui si ligne non vide | `lignes[].section_cadastrale` | Section cadastrale | rulesCreate | `''` | string |
| Batch | Numéro* | input | oui | `lignes[].numero` | Numéro | required | `''` | string |
| Batch | Commune* | CommuneSelect | oui | `lignes[].code_insee_commune` | — | size:5 exists | `''` | INSEE |
| Batch | Surface cad. | InputNumber | non | `lignes[].surface_cadastrale_m2` | Surface cadastrale | nullable min:0 | null | decimal |
| Batch | État foncier* | select | oui | `lignes[].etat_foncier` | État foncier | required in ETATS | null | code |
| Batch | Société détentrice | select | non | `lignes[].societe_detentrice_id` | Société détentrice | nullable exists ; ACL groupe | null | int |
| Show inline | Section | text | oui si patché | `section_cadastrale` | Section cadastrale | required max:16 + doublon | — | string |
| Show inline | Numéro | text | oui si patché | `numero` | Numéro | required max:32 + doublon | — | string |
| Show inline | État foncier | select | oui si patché | `etat_foncier` | État foncier | required in ETATS | — | code |
| Show | Statut cadastral | lecture | — | — | Statut cadastral | non editable inline | — | **code brut** `parcelle.statut_cadastral` (`Show.vue:1254`) |
| Show inline | Société détentrice | select | non | `societe_detentrice_id` | Société détentrice | nullable exists ; ACL ; verrou acte | — | int\|null |
| Show inline | Lieu-dit | text | non | `lieu_dit` | Lieu-dit | nullable max:255 | — | string |
| Show inline | Cadastrale | number | non | `surface_cadastrale_m2` | Surface cadastrale | nullable min:0 | — | decimal |
| Show inline | Arpentée | number | non | `surface_arpentee_m2` | Surface arpentée | nullable min:0 | — | decimal |
| Show inline | Date arpentage | date | non | `date_arpentage` | Date d’arpentage | nullable date | — | Y-m-d |
| Show inline | Bornage | select | non | `bornage` | Bornage | in BORNAGES | — | code\|null |
| Show inline | Date de bornage effective | date | non | `date_bornage_effective` | Date de bornage effective | nullable date | — | Y-m-d |
| Show inline | Zonage PLU | text | non | `zonage_plu` | Zonage PLU | nullable max:255 | — | string |
| Show inline | Constructible | tri_etat | non | `constructible` | Constructible | normalize | — | code\|null |
| Show inline | Risque inondable | boolean | non | `risque_inondable` | Risque inondable | boolean | — | bool |
| Show inline | Risque feu de forêt | boolean | non | `risque_feu_foret` | Risque feu de forêt | boolean | — | bool |
| Show inline | Bâti présent | boolean | non | `bati_present` | Bâti présent | nullable boolean | — | bool\|null |
| Show inline | Commentaire | textarea | non | `commentaire` | Commentaire | nullable | — | string |
| Show | Type foncier | **pas d’UI** | — | `type_foncier` *(whitelist)* | Type foncier | normalize | — | NON DÉTERMINÉ usage fiche |
| Form edit | Section * | input | oui | `section_cadastrale` | Section cadastrale | required | parcelle | string |
| Form edit | Numéro * | input | oui | `numero` | Numéro | required | parcelle | string |
| Form edit | Commune * | CommuneSelect | oui | `code_insee_commune` | — | required size:5 | parcelle | INSEE |
| Form edit | Surface cadastrale (m²) | InputNumber | non | `surface_cadastrale_m2` | Surface cadastrale | nullable min:0 | parcelle | decimal |
| Form edit | Surface arpentée (m²) | InputNumber | non | `surface_arpentee_m2` | Surface arpentée | nullable min:0 | parcelle | decimal |
| Form edit | Date d’arpentage | date | non | `date_arpentage` | Date d’arpentage | nullable date | parcelle | Y-m-d |
| Form edit | Zonage PLU (texte libre) | input | non | `zonage_plu` | Zonage PLU | nullable max:255 | parcelle | string |
| Form edit | Constructible | select | non | `constructible` | Constructible | normalize | parcelle | code |
| Form edit | Lieu-dit | input | non | `lieu_dit` | Lieu-dit | nullable | parcelle | string |
| Form edit | État foncier * | select | oui | `etat_foncier` | État foncier | required in ETATS | `reperee` | code |
| Form edit | Statut cadastral * | select | oui | `statut_cadastral` | Statut cadastral | required in STATUTS | `active` | code |
| Form edit | Risque inondable | checkbox | non | `risque_inondable` | Risque inondable | boolean | parcelle | bool |
| Form edit | Commentaire | textarea | non | `commentaire` | Commentaire | nullable | parcelle | string |
| Division | Date d’opération | date | non | `date_operation` | — | nullable date | `''` | Y-m-d |
| Division | Référence DA (recommandée) | input | non | `reference_da` | — | nullable max:120 | `''` | string |
| Division | Géomètre | select | non | `geometre_fournisseur_id` | — | nullable exists:fournisseurs | null | int |
| Division | Commentaire | input | non | `commentaire` | — | nullable max:5000 | `''` | string |
| Division | Section (fille) | input | oui | `filles.*.section_cadastrale` | Section cadastrale | required max:16 | `''` | string |
| Division | Numéro | input | oui | `filles.*.numero` | Numéro | required max:32 | `''` | string |
| Division | Surface m² | InputNumber | non | `filles.*.surface_cadastrale_m2` | Surface cadastrale | nullable min:0 | null | decimal |
| Division | État foncier* | select | oui | `filles.*.etat_foncier` | État foncier | required in ETATS | null | code |
| Réunion | Autres sources | checkbox multi | oui | `sources_ids` | — | required array min:1 exists vivantes | [] | int[] |
| Réunion | Section issue | input | oui | `issue.section_cadastrale` | Section cadastrale | required max:16 | `''` | string |
| Réunion | Numéro issue | input | oui | `issue.numero` | Numéro | required max:32 | `''` | string |
| Réunion | Surface cadastrale m² | InputNumber | non | `issue.surface_cadastrale_m2` | Surface cadastrale | nullable min:0 | null | decimal |
| Occupation create | Type d’occupation | select | oui | `statut_occupation` | Statut d’occupation | required in STATUTS_OCCUPATION | `bail_rural_fermage` | code |
| Occupation create | (select suivi, sans label) | select | non | `statut` | Suivi occupation | nullable in SUIVI ; défaut `a_traiter` | `a_traiter` | code |
| Occupation create | Nom de l’occupant | input | non | `occupant_nom` | Occupant | nullable max:255 | `''` | string |
| Occupation create | Date de signature | date | non | `date_fin_bail` | Date de signature *(audit : Date de signature côté occupation)* | nullable date | `''` | Y-m-d |
| Occupation create | Date d’échéance | date | non | `date_echeance` | Date d’échéance | nullable date | `''` | Y-m-d |
| Occupation create | Préavis (mois) | number | non | `preavis_mois` | Préavis (mois) | nullable int 0–120 | null | int |
| Occupation create | Part % | number | non | `part_pct` | Part d’occupation (%) | nullable 0–100 | null | decimal |
| Occupation create | Indemnité estimée (€) | input | si prix | `indemnite_eviction_estimee` | Indemnité d’éviction estimée | nullable min:0 ; ACL `foncier.prix` | null | decimal |
| Occupation create | Indemnité réelle (€) | input | si prix | `indemnite_eviction_reelle` | Indemnité d’éviction réelle | idem | null | decimal |
| Occupation create | Commentaire | textarea | non | `commentaire` | Commentaire occupation | nullable max:5000 | `''` | string |
| Bâti create | État | select | oui | `etat` | État du bâti | required in ETATS_BATI | `neuf` | code |
| Bâti create | Commentaire | textarea | non | `commentaire` | Commentaire bâti | nullable | `''` | string |
| Bâti create | Surface m² | InputNumber | non | `surface_m2` | Surface du bâti | nullable min:0 | null | decimal |
| Bâti create | Année de construction | InputNumber | non | `annee_construction` | Année de construction | nullable int 1000–2100 | null | int |
| Show géométrie | GeoJSON polygone (saisie manuelle — repli) | textarea | oui | `geojson` | — | required string | `''` | GeoJSON |
| Show géométrie | *(source cachée)* | — | non | `source` | — | manuel\|ign\|cadastre_gouv | `manuel` | string |
| Show proprio | Choisir… | select | oui | `proprietaire_id` | — | required exists:proprietaires | null | int |
| Show détention | Quote-part (0–1) | InputNumber | non | `quote_part` | — | nullable 0–1 | null | decimal |
| Show détention | date début / fin | date | non | `date_debut_detention` / `date_fin_detention` | — | nullable date | — | Y-m-d |
| Dossier choisir | Section, numéro, commune… | input recherche | — | search only | — | min 2 car. client | `''` | string |
| Dossier choisir | QP | InputNumber | non | `parcelles[].quote_part` | — | nullable 0–1 | null | decimal |
| Dossier ajouter | Code INSEE commune | input | oui | `code_insee_commune` | — | required size:5 exists | dossier | INSEE |
| Dossier ajouter | Section / Numéro | input | oui | `lignes[].section_cadastrale` / `numero` | Section / Numéro | required | `''` | string |
| Dossier ajouter | Surface cad. m² | InputNumber | non | `lignes[].surface_cadastrale_m2` | Surface cadastrale | nullable min:0 | null | decimal |
| Dossier ajouter | Quote-part | InputNumber | non | `lignes[].quote_part` | — | nullable 0–1 | null | decimal |
| Dossier ajouter | Si le triplet existe déjà : rattacher… | checkbox | non | `confirm_rattacher` | — | boolean ; sinon 422 si doublon | false | bool |

Serveur force `statut_cadastral=active` à la création (`ParcelleCreationService` `applyServerDefaults`). Envelope batch : `lignes` required array min:1 max:50 (`ParcelleController.php:244-247`). `filles` division : required array min:2.

---

## 4. RÉFÉRENTIELS

### 4.1 Enums PHP (pas de table)

Tous les listes d’état / occupation / bâti / bornage / constructibilité / type foncier / filiation / valorisation / charges sont des **constantes PHP** dans `FoncierReferentiels.php`. **Aucun écran d’administration** pour les modifier. Qui peut les changer : un développeur (commit). Valeurs actuellement en base : **NON DÉTERMINÉ** (requête à exécuter en prod) :

```sql
SELECT DISTINCT etat_foncier FROM parcelles WHERE deleted_at IS NULL;
SELECT DISTINCT statut_cadastral FROM parcelles WHERE deleted_at IS NULL;
SELECT DISTINCT type_foncier FROM parcelles WHERE deleted_at IS NULL;
SELECT DISTINCT bornage FROM parcelles WHERE deleted_at IS NULL;
SELECT DISTINCT constructible FROM parcelles WHERE deleted_at IS NULL;
SELECT DISTINCT statut_occupation FROM parcelle_occupations;
SELECT DISTINCT etat FROM parcelle_batis;
```

### 4.2 Tables alimentant des champs parcelle

| Référentiel | Table | Champ parcelle | Qui peut modifier | Écran admin |
|---|---|---|---|---|
| Communes | `communes` | `code_insee_commune` | `foncier.referentiels` | Admin communes (`ReferentielCommunesController.php:18-22`) |
| Entités / sociétés | `entites` | `societe_detentrice_id`, acte acquéreur | Admin entités + sync Intacct | Admin entités — **hors notice parcelle** |
| Propriétaires | `proprietaires` | pivot détention | `foncier.gestion` | fiches propriétaires |
| Fournisseurs | `fournisseurs` | géomètre, notaire | référentiel fournisseurs | — |
| Utilisateurs | `users` | `createur_id`, `deleted_by`, chargé, auteur constat | — | — |

SQL communes / entités :

```sql
SELECT code_insee, nom, departement, code_postal FROM communes ORDER BY nom;
SELECT id, nom, siret FROM entites ORDER BY nom;
```

Valeurs actuelles : **NON DÉTERMINÉ**.

### 4.3 Permissions catalogue

`config/feature_permissions.php:145-151` : `foncier.lecture`, `foncier.gestion`, `foncier.prix`, `foncier.referentiels`, `foncier.secteurs`, `foncier.deverrouillage`, `foncier.corbeille`.

Mapping **intent** `default_mappings` (`:185-315`) :

| Groupe M365 (brut) | Clés foncier (config) |
|---|---|
| `GS_DSI` | `['*']` |
| `GS_ADMIN_ERP` | `['*', '!admin.systeme', '!admin.maintenance']` |
| `GS_DIRECTION_GENERALE` | `!foncier.*` |
| `GS_ENVOL` | `!foncier.*` |
| `GS_HECTARE` | `lecture`, `gestion`, `prix` seulement (`:298-303`) |
| `GS_GEMME_PDG` | `lecture`, `prix`, `deverrouillage` — **pas** `gestion` (`:308-315`) |

**Vérité runtime** = table `feature_permission_groups` (sauf GS_DSI / GS_ADMIN_ERP gérés dans `PermissionService.php:45-54` via `m365GroupNames()` brut). Query :

```sql
SELECT fp.feature_key, fpg.groupe_m365
FROM features_permissions fp
JOIN feature_permission_groups fpg ON fpg.feature_permission_id = fp.id
WHERE fp.feature_key LIKE 'foncier.%'
ORDER BY 1, 2;
```

Seed `foncier.corbeille` : groupes **GS_DSI**, **GS_ADMIN_ERP** uniquement (`2026_08_07_170100:18`). État actuel prod : **NON DÉTERMINÉ**.

`PermissionService` cache 300 s (`:20`).

---

## 5. RÈGLES MÉTIER ET ARBITRAGES

### 5.1 États fonciers

Valeurs / libellés : `ETATS_FONCIERS` (`FoncierReferentiels.php:31-46`).

Axe d’avancement (`ParcelleEtatAvancement.php:15-21`) :  
`reperee`(10) < `en_negociation`(20) < `sous_compromis`(30) < `acquise`(40) < `affectee`(50).

Hors axe (`:24-34`) : `pas_d_action`, `projet_abandonne`, types fonciers (`reserve_fonciere`, `opportunite`, `bouchon`, `cession`, `retrocession`), `vendue_client`, `autre`.

**Saisie manuelle** : toute valeur de `ETATS_FONCIERS` est acceptée par `Rule::in` — **pas de CHECK SQL** trouvé. Les transitions « en avant seulement » ne s’appliquent **pas** à l’édition inline de l’état.

**Promesse → sous_compromis** (`ParcelleEtatTransitionService.php:38-88`) : si statut promesse ∈ `{signe, en_cours}` (`:25-31`) et `peutAvancerVersSousCompromis` (`ParcelleEtatAvancement.php:50-67`) : hors-axe → oui ; déjà ≥ sous_compromis → non ; axe seulement si rang < 30. **Pas de régression auto** si la promesse devient caduque (`:116-120`).

Messages bandeau fiche (`:110-119`) :  
- `Cette parcelle est rattachée à une promesse signée mais n’est pas encore « Sous compromis ».`  
- `Parcelle « Sous compromis » sans promesse signée vivante (compromis caduc ou abandonné — arbitrage humain, pas de régression auto).`

**Acte d’acquisition** : **n’écrit pas** `etat_foncier = acquise` (`ActeAcquisitionService.php:15`, `:137-140`). Pose `societe_detentrice_id` + clôture des détentions externes (`:145-179`).

### 5.2 Surfaces

| Champ | Rôle | Citation |
|---|---|---|
| `surface_cadastrale_m2` | Surface principale ; totaux liste et emprise | `Parcelle.php:103` ; `ParcelleProspectionQuery.php:387` |
| `surface_arpentee_m2` | Arpentage ; **vidée** sur les filles de division | `ParcelleOperationCadastraleService.php:403-405` (« D69 : arpentée vide jusqu’au géomètre ») |
| Surface « cessible » sur parcelle | **Absente** du fillable | — |
| `surface_acquise_m2` | Pivot `acte_parcelle` | migration `150000` ; Create poste toujours `null` |
| `surface_promise_m2` | Pivot promesse | `promesse_parcelle` |

**Quelle surface fait foi pour les totaux liste** : `SUM(surface_cadastrale_m2)` **uniquement si** `statut_cadastral = active` (`ParcelleProspectionQuery.php:376-388`). Les remplacées sont **dénombrées** (si filtre coché) mais **pas additionnées**. Note UI : `Index.vue:1127`.

Emprise dossier : surfaces = **cadastrales** ; commentaire contrôleur : « ST_Area 4326 n’est pas en m² » (`DossierFoncierController.php:1670`). Remplacées **exclues** de la boucle (`:1698-1701`).

Écart division / réunion : calculé, **jamais bloquant** ; alerte visuelle si \|%\| ≥ 10 (`ParcelleOperationCadastraleService.php:21-22`, `:495`).

### 5.3 Division

Service : `ParcelleOperationCadastraleService::diviser` (`:47-120`).

| Règle | Fait | Citation |
|---|---|---|
| Mère | `statut_cadastral = remplacee` ; détentions courantes **clôturées** ; **`etat_foncier` inchangé** | `:99-102` |
| Filles | ≥ 2 ; créées via `createPrepared` ; détentions propagées | `:52-97` |
| Somme surfaces | écart informatif, non bloquant | `:104`, `:438-451` |
| État fille | **obligatoire**, `Rule::in` ETATS, **pas** de repli `reperee` | `preparerFille(..., true)` `:348-414` ; `ParcelleController` validate division |
| Numérotation | saisie utilisateur section+numéro ; doublon cadastral refusé | `:350-396` |
| Géométrie | **non** créée sur les filles | commentaire service `:17` ; UI `:1024` |
| Actes | liens via `acte_foncier_id` des détentions propagées ; mère reste remplacée | `ParcelleDetentionPropagationService` |
| Réversibilité | **pas** d’annulation ; réunion = opération distincte N→1 | `reunir` `:140-245` |
| Confirmation UI | **absente** | `Show.vue:1113` |

Messages :  
- `Une division exige au moins 2 parcelles issues.` (`:54`)  
- `L’état foncier est obligatoire.` / `État foncier invalide.` (`:375-381`)  
- `Section et numéro obligatoires.` (`:354`)  
- `La parcelle … existe déjà en base — doublon cadastral refusé.` (`:393-394`)  
- `Deux lignes portent la même référence cadastrale dans l’opération.` (`:427`)  
- `La parcelle … est déjà remplacée au cadastre — elle ne peut plus être source d’une opération.` (`:294-295`)  
- `Échec de la division : {exception} — aucune modification conservée.` (`:117`)

### 5.4 Réunion

| Règle | Fait | Citation |
|---|---|---|
| Sources | ≥ 2 actives, **même commune** | `:150-181` |
| Issue | 1 parcelle créée ; sources → remplacées | `:210-226` |
| État de l’issue | `preparerFille` **sans** 4e arg → `applyServerDefaults` → **`reperee`** | `:184` ; LEÇON `#1564` |
| Détenteurs | doivent être **identiques** (propriétaires + quotes-parts) sinon refus | `ParcelleDetentionPropagationService.php:90-96` |
| Géométrie | non créée | UI `:1129` |

Message refus détenteurs : `Réunion refusée : les sources n’ont pas exactement les mêmes détenteurs courants (propriétaires et quotes-parts). …` (`:91-95`).

### 5.5 Parcelles remplacées

Définition : `statut_cadastral === remplacee` (`Parcelle.php:374-377`).  
Liste : masquées sauf case **Afficher les parcelles remplacées**.  
Fiche : bandeau ambre (`Show.vue:765-782`).  
Totaux surface : exclues.  
Carte emprise dossier : exclues (`DossierFoncierController.php:1698-1700`).  
Ne peuvent plus être source d’opération (`assertSourceActive`).

### 5.6 Bâti et occupation

**Bâti** : plusieurs lignes ; états `neuf` / `a_renover` / `a_detruire`. Ajout force `bati_present=true` (`ParcelleBatiController` store). Liste des bâtis affichée seulement si `local.bati_present` (`Show.vue:1468`).

**Occupation** : courante = `statut ≠ libere` (`Parcelle.php:265` commentaire ; `estCourante()`). **Libérer** ne supprime pas : pose `statut = libere` (`ParcelleOccupationController.php:182-193`). Flash : `Occupation marquée comme libérée.`

**« Pas d’occupation » (#1563)** n’est **pas** le statut terrain `libre`. C’est un **constat** (`occupation_absente_at` + auteur).  
Liste Occup. : `oui` (au moins une occupation) / `non` (constat) / `indetermine` (ni l’un ni l’autre) (`Parcelle.php:292-311`).  
UI : « Aucune occupation enregistrée — non vérifié. » vs « Pas d’occupation » constaté par X le … (`Show.vue:1786-1811`).  
Pose bloquée si occupations existent : `Une occupation est déjà enregistrée.` (`ParcelleOccupationController.php:95-97`).  
Ajout d’occupation **lève** le marqueur (`:79`). Auteur du constat sérialisé : `occupationAbsentePar?->name` (`ParcelleController.php:1166`).

Statut terrain `libre` = une **occupation enregistrée** de type Libre — distinct du constat.

### 5.7 Actes rattachés

Un seul type d’entité : **acte d’acquisition** (`ActeFoncier`) — pas d’enum de type sur le modèle (commentaire `ActeAcquisitionService.php:13-16`).

Création requise : `parcelle_ids`, `societe_acquereur_id`, `date_acte`, `prix_numeraire` (`ActeFoncierController` + service `:33-38`).  
Effet parcelle : détention groupe + clôture externes ; **pas** de changement d’`etat_foncier`.  
Verrou : si un acte existe, `societe_detentrice_id` n’est plus modifiable manuellement (`ParcelleController.php:1473-1474`) : `Société détentrice renseignée par un acte — modification manuelle impossible (l’acte prime).`

### 5.8 Messages d’erreur bloquants (recueil)

| Message exact | Source |
|---|---|
| `Droit foncier.gestion requis.` | `ParcelleController.php:1439` |
| `Vous n’avez pas le droit de renseigner la détention par le groupe.` | `:1450` |
| `Société détentrice renseignée par un acte — modification manuelle impossible (l’acte prime).` | `:1474` |
| `Au moins une parcelle est requise.` | `ActeAcquisitionService.php:36` |
| `Société acquéreuse introuvable.` | `:57` |
| `Cette promesse est déjà verrouillée.` | `:73` |
| `Droit foncier.prix requis pour les indemnités.` | `ParcelleOccupationController.php:71` |
| `Une occupation est déjà enregistrée.` | `:97` |
| `Champ non autorisé.` / `Valeur invalide.` | `updateChamp` |
| `Champ non modifiable en ligne.` | occupation `:135` |
| `Aucune géométrie cadastrale trouvée pour cette référence (référence remaniée, parcelle divisée/supprimée, ou commune non vectorisée).` | `IgnCadastreParcelleService.php:172` |
| `Parcelle introuvable au cadastre IGN.` | fallback import `:52` |
| `Impossible d’enregistrer la géométrie : …` | `ParcelleGeometrieImportService.php:99` |
| `Géomètre (fournisseur) introuvable.` | ops `:322` |
| `Toutes les sources doivent être de la même commune (…).` | `:179` |

Flash succès (extraits) : `Parcelle créée.` · `Occupation enregistrée.` · `Parcelle marquée sans occupation.` · `Constat « pas d’occupation » retiré.` · `Contour cadastral importé depuis l’IGN.` / `Contour cadastral mis à jour depuis l’IGN.`

---

## 6. CARTE D’EMPRISE IGN

### 6.1 Source des géométries

- **API cadastre** : `GET https://apicarto.ign.fr/api/cadastre/parcelle` query `code_insee`, `section`, `numero` (`IgnCadastreParcelleService.php:16`, `:100-106`). Timeout 12 s (`:18`). Variantes section/numéro si 1er essai vide (`:47-79`).
- **Moment** : action utilisateur POST `…/geometrie/ign` (`routes/web.php:905-907` ; `ParcelleController::importGeometrieIgn`) **ou** bouton emprise dossier (boucle par parcelle sans contour).
- **Persistance** : `parcelle_geometries` via `upsertFromGeoJson(..., 'ign')`. Centroïde écrit sur la parcelle (`ParcelleGeometrieImportService.php:103-108`).
- **Cache HTTP** : aucun `Cache::remember` trouvé sur l’appel IGN → **pas de cache applicatif**. Le contour en base sert de cache métier.
- **Tuiles fond** : WMTS Plan IGN V2 `data.geopf.fr` sans clé (`ParcelleMap.vue:220-233`). Attribution « © IGN — Plan IGN V2 (Géoplateforme) ».
- Contrainte OVH : appel **WEB / PHP-FPM** uniquement (`IgnCadastreParcelleService.php:12-13`).

### 6.2 Couleurs et traits

**Fiche parcelle** (un seul geojson, `renderLegacy`) : stroke `#1B2B4B`, weight `2`, fill `#3B82F6`, opacity `0.35` (`ParcelleMap.vue:114-122`) — **indépendant de l’état**.

**Emprise dossier** (`EMPRISE_COULEURS_COURANTES`, `FoncierReferentiels.php:55-74`) :

| État | Stroke | Fill |
|---|---|---|
| Repérée | `#334155` | `#64748B` |
| En négociation | `#854D0E` | `#C8973A` |
| Sous compromis | `#9A3412` | `#EA580C` |
| Acquise | `#14532D` | `#16A34A` |
| Affectée | `#1B2B4B` | `#1E3A5F` |
| Pas d'action | `#4B5563` | `#9CA3AF` |
| Projet abandonné | `#7F1D1D` | `#DC2626` |
| Vendue client | `#5B21B6` | `#7C3AED` |
| Autres (types fonciers, Autre) | `#374151` | `#6B7280` (neutre) |

Poids trait défaut : `2`. Si `societe_detentrice_id` renseigné : stroke `#111827`, weight `4` (`DossierFoncierController.php:1736-1742`).  
Libellés polygone : référence cadastrale + surface m² (`:1775-1778`) + badge **ACHETÉ** si détenue (`ParcelleMap.vue:92-93`).  
Légende « Acheté » : trait, pas une couleur de remplissage (`FoncierReferentiels.php:857-870`).

Hover emprise : weight +1, fillOpacity 0.6 (`ParcelleMap.vue:145-152`).

### 6.3 Contour manquant

Fiche : message + **Récupérer le contour cadastral** si `peut_gestion`. Fallback GeoJSON manuel.  
Dossier : liste des parcelles sans contour + **Récupérer le contour** / **Récupérer les contours manquants** ; progression `Récupération {i}/{n}`.  
Texte : « {n} parcelle(s) sans contour — surface non comptée dans le contour » (`DossierSyntheseTab.vue:493-496`).

### 6.4 Limites connues

- Message IGN : référence remaniée, parcelle divisée/supprimée, **commune non vectorisée** (`IgnCadastreParcelleService.php:172`).
- Écart ST_Area vs cadastrale : informatif, non bloquant ; log si ratio > 10 ou < 1/10 (`ParcelleGeometrieImportService.php:17-18`, `:182-195`).
- SUIVI #1109 : risque SRID/projection ; confusion INSEE (exemple Clapiers/Castelnau dans la fiche) — **lire la fiche**, pas rejoué ici.
- **SAINTE LIVRADE** comme exception IGN parcelle : **NON DÉTERMINÉ** dans le code carte (mention SIWI ailleurs, hors périmètre).
- Parcelles hors couverture IGN : gérées uniquement via le message « commune non vectorisée » / saisie GeoJSON manuelle.

---

## 7. DROITS ET VISIBILITÉ

### 7.1 Gate::before

`AppServiceProvider.php:69-75` : si `isAdminERP()` (`GS_ADMIN_ERP` dans `m365_groups`, `User.php:103-114`) → `true` pour **toutes** les abilities Gate.  
**Ne pas conclure un droit métier depuis un test admin.**  
`hasM365Group` / `hasAnyM365Group` retournent aussi true si admin (`User.php:134-152`) — **ne pas les utiliser** pour inférer un groupe.  
`m365GroupNames()` brut : `User.php:119-122` — tableau `m365_groups` tel quel.

`assertGestion()` utilise `PermissionService::userHasPermission(..., 'foncier.gestion')` (`ParcelleController.php:1435-1440`), **pas** Gate. GS_ADMIN_ERP obtient toutefois le catalogue via `PermissionService.php:49-54`.

### 7.2 Policy parcelle

`ParcellePolicy.php` :

| Ability | Condition |
|---|---|
| `view` | `foncier.lecture` **et** `userCanViewParcelle` |
| `update` | `foncier.gestion` **et** `userCanModifyParcelle` |
| `useInDossier` | `foncier.gestion` **et** `userCanUseParcelleInDossier` |
| `manageHabilitations` | service visibilité seulement (pas de feature_key) |

Visibilité (`FoncierParcelleVisibiliteService.php:44-55`) : bypass **ou** créateur **ou** visible via dossier (détention propriétaire du dossier **ou** pivot `dossier_foncier_parcelle`).  
Bypass vue parcelle (`RecordAcl::BYPASS_PARCELLE_VIEW_GROUPS`, `:78-82`) : `GS_DIRECTION_GENERALE`, `GS_ADMIN_ERP`, `GS_HECTARE_DIRECTION`. **Pas** `GS_DSI` ni `GS_GEMME_PDG`. Commentaire : `GS_HECTARE_DIRECTION` n’existe pas encore en M365 (`:73`) — cran **inerte** jusqu’à création manuelle.

Modification : bypass / créateur / habilitation `modification` (`:78-93`).  
Usage dossier (R5) : habilitation `utilisation` \| `modification` — **n’ouvre pas** la visibilité (commentaire classe `:15-16`).

Scope SQL global : `FoncierParcelleVisibiliteScope`.

### 7.3 Contrôles serveur par action

| Action | Serveur |
|---|---|
| `show` | `authorize('view')` `ParcelleController.php:266` |
| `update` (Form PUT) | `assertGestion` + `authorize('update')` |
| `create` / `store` / `storeUnitaire` / `storeBatch` / `destroy` / `diviser` / `reunir` / `updateChamp` / géométrie / occupations / bâtis | `assertGestion` et/ou middleware `foncier.gestion` — **souvent sans** `authorize('update')` |
| Corbeille | middleware `foncier.corbeille` |
| Valorisations montants | `foncier.prix` (`ParcelleValorisationController`) |
| Indemnités occupation | `foncier.prix` |
| Société détentrice manuelle | `DetentionGroupeSaisie::GROUPES` brut : `GS_HECTARE`, `GS_DSI`, `GS_ADMIN_ERP` (`DetentionGroupeSaisie.php:22-26`) |

### 7.4 Vue `v-if` vs serveur

`Show.vue` masque les boutons via `peut_gestion` / `peut_prix` / `operation_cadastrale.peut_operer` / `societeDetentriceEditable`. Props calculées serveur. Les mutations ont un contrôle serveur (`assertGestion` / middleware / prix).

**Points à signaler** : `diviser` / `reunir` n’appellent **pas** `authorize('update', $parcelle)` — seulement `assertGestion`. Un utilisateur `foncier.gestion` **sans** habilitation `modification` ni créateur ni bypass pourrait théoriquement opérer si le middleware passe — **NON DÉTERMINÉ** si le scope global empêche déjà le binding de la parcelle (404 vs 403).

Historique (icône) : **pas** derrière `peut_gestion` (`Show.vue:823`) — visible en lecture.

### 7.5 Groupes × écrans (seed / config — vérifier DB)

| Écran / action | Feature | Groupes seed/config typiques |
|---|---|---|
| Voir liste / fiche | `foncier.lecture` + ACL visibilité | GS_HECTARE, GS_GEMME_PDG, GS_DSI, GS_ADMIN_ERP*. Menu Foncier : `nav.foncier_visible` = `FoncierContext::menuVisible` = `foncier.lecture` **et** module enseigne actif (`FoncierContext.php:33-36` ; `AppShell.vue:697-698`). `GS_DIRECTION_GENERALE` a `!foncier.*` en config (`feature_permissions.php:190-192`) donc **pas** `foncier.lecture` via catalogue — bypass vue parcelle (`RecordAcl`) n’ouvre pas le menu. |
| Créer / éditer inline / diviser / IGN / occupation / bâti | `foncier.gestion` | GS_HECTARE, GS_DSI, GS_ADMIN_ERP* — **pas** GS_GEMME_PDG |
| Prix / valo / indemnités | `foncier.prix` | GS_HECTARE, GS_GEMME_PDG, GS_DSI, GS_ADMIN_ERP* |
| Corbeille | `foncier.corbeille` | seed GS_DSI + GS_ADMIN_ERP |
| Admin communes | `foncier.referentiels` | seed DSI (+ ADMIN via `*`) |
| Saisie société détentrice | GROUPES brut | GS_HECTARE, GS_DSI, GS_ADMIN_ERP |

\*GS_ADMIN_ERP via catalogue PermissionService, distinct du Gate::before.

---

## 8. ERGONOMIE ET PIÈGES UTILISATEUR

### 8.1 Libellés trompeurs

- **État foncier** contient d’anciens « types » (Réserve, Opportunité, Bouchon, Cession…) **et** le cycle de vie, alors que **Type foncier** reste une colonne séparée, saisie en création avancée, **absente de la fiche Show**.
- **Occup.** : `Oui` / `Non` / `—` où Non = constat « pas d’occupation », `—` = non vérifié — distinct du filtre **Occupée / Pas d’occupation / Non vérifié**.
- **Date de signature** poste `date_fin_bail` (`Show.vue:1693-1698`, `:1849-1850`). Aide : « La date historique est la date de signature. » (`:1603-1605`).
- **Statut cadastral** sur la fiche : affiche le **code** `active` / `remplacee`, pas le libellé Active / Remplacée (`Show.vue:1254`).
- Légende emprise **Acheté** = trait de détention groupe, **pas** l’état « Acquise ».
- Occupation type **Libre** ≠ bouton **Pas d’occupation**.

### 8.2 Actions irréversibles / confirmation

| Action | Confirmation ? |
|---|---|
| Mettre en corbeille | Oui (`Show.vue:226`) |
| Restaurer | Oui (`Corbeille.vue:24`) |
| Clore / supprimer détention | Oui |
| Libérer occupation / supprimer bâti / valo | Oui (confirm JS) |
| **Division / réunion** | **Non** |
| Import IGN | Non |
| Édition inline | Non (sauvegarde immédiate au blur/save du champ) |

Division/réunion : mère → remplacée, pas d’undo dédié.

### 8.3 Comportements non évidents

- Inline : chaîne vide → `null` pour surfaces, dates, commentaire, bornage, société (`ParcelleController.php:673-675`).
- Filles de division : arpentée et date d’arpentage forcées null.
- Promesse signée → avancement auto vers sous_compromis (serveur).
- Acte → société détentrice + clôture détentions, **sans** passer l’état à Acquise.
- Store occupation → lève le constat « pas d’occupation ».
- `Mon secteur` défaut **ON** si préférence absente (`ParcelleController.php:1479-1487`) — peut vider la grille ; lien « Désactiver « Mon secteur » » (`Index.vue:1104-1110`).
- Batch max 50 lignes.
- Commune hors secteur à la création : message **non bloquant** (`ParcelleController.php:147-149`).
- `type_foncier` dans Form.vue `useForm` mais **sans contrôle UI** : re-posté tel quel au PUT.

### 8.4 Messages peu clairs (texte exact)

- `Échec de la division : {exception} — aucune modification conservée.`
- `Détention courante en doublon… (contrainte pp_courante_uq).` (technique, service détention)
- `Champ non autorisé.` / `Valeur invalide.`
- Message IGN long (référence remaniée / commune non vectorisée)
- Bandeau (b) promesse caduque — phrase d’arbitrage

---

## 9. PARCOURS MÉTIER TYPES

### 9.a Ajouter une parcelle à un dossier

**Voie A — depuis le référentiel (hors dossier)**  
1. Header → **Foncier** → **Parcelles**.  
2. **Nouvelle parcelle** (ou **Ajouter multiparcelle**).  
3. Saisir Section*, Numéro*, Commune*, État foncier* ; optionnellement Infos avancées, Propriété, Acte.  
4. **Enregistrer** → fiche parcelle.  
5. Aller au dossier → onglet **FONCIER** → **Choisir des parcelles** → rechercher → **Rattacher (détention)**.

**Voie B — depuis le dossier**  
1. Dossiers → ouvrir un dossier → onglet **FONCIER**.  
2. **Ajouter des parcelles** (création) ou **Choisir des parcelles** (existantes).  
3. Si triplet déjà en base : cocher rattachement / 422 sinon.

Hors périmètre : création du dossier lui-même.

### 9.b Renseigner l’occupation et le bâti

1. Ouvrir la fiche parcelle.  
2. Bloc **Bâti** → déplier → **Bâti présent** Oui → **Ajouter un bâti** → État + surface/année/commentaire → **Enregistrer le bâti**.  
3. Bloc **Occupation du terrain** → déplier.  
   - Terrain occupé : **Ajouter une occupation** → type, suivi, dates… → **Enregistrer l’occupation**.  
   - Terrain constaté libre : **Pas d’occupation** (interdit s’il existe déjà une occupation).  
4. Pour clôturer un bail : **Libérer** (passe en suivi Libéré, conserve l’historique).

### 9.c Diviser une parcelle

1. Fiche d’une parcelle **active** + `peut_gestion`.  
2. **Diviser**.  
3. Renseigner méta (date, DA recommandée, géomètre, commentaire).  
4. Au moins 2 filles : Section, Numéro, Surface m², **État foncier*** (Choisir…).  
5. Lire l’écart prévisionnel (non bloquant).  
6. **Enregistrer la division** — **sans** seconde confirmation.  
7. La mère passe Remplacée ; les filles naissent actives avec les détenteurs copiés ; **pas de contour IGN** sur les filles.

### 9.d Rattacher un acte à une parcelle

1. Fiche → **Déclarer une acquisition** (ou création unitaire bloc Acte).  
2. Saisir société acquéreuse, date, prix, parcelles.  
3. Enregistrement : société détentrice = acquéreur ; détentions externes clôturées ; **état foncier non forcé à Acquise**.  
4. La société détentrice n’est plus éditable inline (« Renseigné par l’acte … — non modifiable ici. »).

### 9.e Visualiser l’emprise sur la carte

**Sur la fiche**  
1. Bloc **Plan cadastral**.  
2. Si vide : **Récupérer le contour cadastral** (ou coller un GeoJSON → **Enregistrer la géométrie**).  
3. Carte Plan IGN V2, polygone bleu fixe.

**Sur le dossier**  
1. Dossier → **Synthèse** → **Emprise du dossier**.  
2. Couleurs par état ; trait épais **Acheté** si détention groupe.  
3. Remplacées absentes.  
4. **Récupérer les contours manquants** si besoin.

### 9.f Consulter le total de surface

**Liste Parcelles**  
Pied de grille : somme des `surface_cadastrale_m2` des lignes **actives** du filtre (toutes pages SQL, pas la page JS). Les remplacées listées ne sont **pas** dans la somme. Valorisation pied = somme des valorisations **les plus récentes** des actives — « ce n’est pas une évaluation du patrimoine » (`Index.vue:1134`).

**Synthèse dossier**  
Total du bloc Parcelles = somme JS des `surface_cadastrale_m2` du payload emprise (`DossierSyntheseTab.vue:130-136`) — payload déjà **sans remplacées**. Sous-titre emprise : `{nb_tracees}/{nb_parcelles} tracée(s)` (`:110-113`). Compteur : `{n} parcelle(s) · {m} achetée(s)` (`:123-128`). Badge ligne : `Acheté le {date}` ou `Acheté` si détenue sans date (`badgeAchete`, `:243-248`).

---

## 10. ANOMALIES REPÉRÉES

Constat seul — **aucune correction**.

1. **Double taxonomie** : mêmes codes (Réserve, Opportunité, …) dans `etat_foncier` **et** `type_foncier` (`FoncierReferentiels.php:31-46` vs `:160-166`).  
2. **`type_foncier` whitelisté en inline mais sans champ sur Show** (`ParcelleController.php:71` vs template Show).  
3. **Statut cadastral fiche** : code brut, pas libellé (`Show.vue:1254` vs `STATUTS_CADASTRAL`).  
4. **Form.vue edit** : aucun lien UI ; `type_foncier` re-posté sans contrôle.  
5. **Index.vue Parcelles** : route redirige, composant orphelin.  
6. **ParcellePanel.vue** : aucun import.  
7. **Charges de portage** : routes + UI Show, flag `false`.  
8. **TYPES_FILIATION** remembrement / alignement : constantes sans écran.  
9. **Acte ≠ état Acquise** (`ActeAcquisitionService.php:15`, `#1530`) — risque d’attente métier inverse.  
10. **`date_fin_bail` libellé Date de signature**.  
11. **`surface_acquise_m2`** dans l’état Create, toujours posté `null`.  
12. **`quote_part`** decimal(8,4) vs cast `decimal:6`.  
13. **Pivot asymétrie** : `Parcelle::actesFonciers()` sans `withPivot('surface_acquise_m2')` (`Parcelle.php:216-219`).  
14. **Division/réunion sans confirm** alors que corbeille en a une.  
15. **`diviser`/`reunir`** : `assertGestion` sans `authorize('update')`.  
16. **Liste Occup. `Non` vs filtre `Pas d’occupation`** : mêmes données, libellés différents.  
17. **`Mon secteur` défaut ON** compté dans le badge Filtres avancés (`Index.vue:196`) même si c’est le défaut.  
18. **HORS_AXE** mélange constantes `ETAT_*` et `TYPE_FONCIER_*` (`ParcelleEtatAvancement.php:24-34`).  
19. **Create.vue** lien retour `/foncier/parcelles` (redirect) alors que Show pointe `/foncier/prospection?mode=parcelle`.  
20. **GS_HECTARE_DIRECTION** dans bypass vue : groupe commenté comme inexistant en M365 (`RecordAcl.php:73`).

---

## 11. ZONES D’OMBRE

1. Valeurs distinctes réellement stockées en **production** (états, constructible legacy `'1'`/`'0'` restants, bornage).  
2. Contenu de `feature_permission_groups` **après** éventuelles modifications /admin/droits (seed ≠ vérité).  
3. Si `/admin/droits` a ré-attribué `foncier.lecture` à `GS_DIRECTION_GENERALE` en prod (config seed = exclusion). Bypass vue sans menu reste sans effet tant que `foncier.lecture` est absent.  
4. Un utilisateur `foncier.gestion` sans ACL `modification` : 403 vs 404 sur `diviser` (scope).  
5. Exemple GeoJSON réel en base ; SRID exact renvoyé par IGN pour chaque commune.  
6. **SAINTE LIVRADE** / communes homonymes : pas de code dédié sur la carte parcelle.  
7. Cache CDN/IGN hors application.  
8. `onUpdate` FK MySQL.  
9. Usage réel de `Form.vue` (favoris, anciennes URLs).  
10. `surface_cessible` : absent du modèle parcelle ; existence ailleurs (scénario) **hors extraction**.  
11. Création d’arcs `remembrement` / `alignement` hors UI (API interne `ParcelleFiliationService` accepte tout `TYPES_FILIATION`).  
12. Mapping complet des colonnes « Acte » / « Référent » de la grille liste (sérialisation `ParcelleProspectionQuery` non recopiée champ à champ).  
13. Historique : quels champs masqués sans `foncier.prix` (occupations indemnités, valo `valeur`).  
14. Comportement `store()` saisie courte encore branchée depuis un écran vivant (Index redirect + Panel orphelin → **probablement mort**, NON DÉTERMINÉ s’il reste un POST `inline` ailleurs).  
15. Contenu exact de `data.rattachements` corbeille (libellés joints par ` · `).

---

## Annexe — routes nommées (préfixe `foncier.`)

`parcelles.index` (redirect) · `parcelles.create` · `parcelles.store` · `parcelles.store-unitaire` · `parcelles.store-batch` · `parcelles.corbeille.index` · `parcelles.corbeille.restore` · `parcelles.show` · `parcelles.navigation` · `parcelles.suppression.impact` · `parcelles.destroy` · `parcelles.edit` · `parcelles.update` · `parcelles.champ.update` · `parcelles.occupations.store` · `parcelles.occupation-absente.store` · `parcelles.occupation-absente.destroy` · `parcelles.occupations.champ.update` · `parcelles.occupations.destroy` · `parcelles.batis.store` · `parcelles.batis.champ.update` · `parcelles.batis.destroy` · `parcelles.proprietaires.attach` · `parcelles.proprietaires.store` · `parcelles.proprietaires.detach` · `parcelles.detentions.update` · `parcelles.detentions.destroy` · `parcelles.geometrie.store` · `parcelles.geometrie.ign` · `parcelles.diviser` · `parcelles.reunir` · `parcelles.charges-portage.store` · `parcelles.charges-portage.destroy` · `parcelles.valorisations.store` · `parcelles.valorisations.update` · `prospection.index` · `prospection.communes.parcelles`.

Fin de l’extraction SUIVI #1565.
