---
suivi: 1504
date: 2026-09-10
sujet: Arrêt RGPD — UI saisie destination Projet
chantier: factures / depot / destination-projet
type: diagnostic
statut: poussé
hash: 9c91d9b2
fichiers:
  - docs/suivi/SUIVI_1504_ui_saisie_destination_projet.md
---

# SUIVI #1504 — ARRÊT : UI saisie destination Projet (RGPD)

## PROMPT ENVOYÉ

Étape 3/5 : activer le bouton « Projet », cascade dossier foncier
(AutoComplete) → poste budgétaire filtré par enseigne. Maquette Robin.
Clause d’arrêt RGPD : noms de propriétaires dans un sélecteur ouvert à
tous les déposants. Pas de schéma, pas de visibilité, pas de
comptabilisation.

## BASE GIT

HEAD `f63d9594` (fiche #1503). origin/main à jour. Aucun lot en cours.
#1493 jamais lancé (pas de fiche disque) — numéro consommé, ce lot = 1504.

## FICHES LUES

- **#1492 LEÇON** — ancrer sur le TYPE de nomenclature, pas la ligne
  `postes_budgetaires` (conversion dossier → programme). Impact : ce lot
  devait poster `poste_budgetaire_type_id`, jamais recréer
  `poste_budgetaire_id`.
- **#1490 LEÇON** — `hasColumn` autour d’une colonne jamais migrée = garde
  morte. Impact : schéma #1492 déjà en prod, ne pas migrer.
- **#1467 LEÇON** — dégriser PROJETS sans schéma ni CLASSID = pollution FG.
  Impact : le bouton reste désactivé tant que l’étape 3 n’est pas livrée ;
  cet arrêt le laisse désactivé.
- **#1450 LEÇON** — ne pas assouplir l’enregistrement sans durcir l’envoi.
  Impact : `required_if` / `prohibited_unless` #1492 non touchés.
- **#1107** — `proprietaire_access_logs` = accès RGPD (view / anonymise),
  pas les modifications. Impact : un libellé dans un sélecteur n’écrit
  **pas** dans cette table.

## SYNTHÈSE — CLAUSE D’ARRÊT RGPD

**Aucun code applicatif.** Le libellé maquette
`PONTEILLA — MARTIN, BLANC (DF-2026-003)` affiche des **noms de
propriétaires** dans un sélecteur de dépôt de facture. Le dépôt est ouvert
à des utilisateurs **sans** `foncier.lecture`. C’est incompatible avec le
dispositif existant. Robin (DPO) arbitre. Pas de contournement (masquer
les noms, inventer un autre format).

### 1. Ce que `proprietaire_access_logs` enregistre

Table créée `database/migrations/2026_07_30_140000_create_proprietaires_tables.php`
L47-55. Modèle `app/Models/ProprietaireAccessLog.php`.

| Colonne | Type |
|---|---|
| `id` | PK |
| `proprietaire_id` | FK `proprietaires` CASCADE |
| `user_id` | FK `users` NULL ON DELETE |
| `action` | varchar(32) |
| `accessed_at` | timestamp |

Pas de trigger SQL. Écriture **uniquement** dans
`ProprietaireController` :

- `show()` L77-82 : `action = view` à l’ouverture de la **fiche**
  propriétaire (adresse, tel, e-mail, etc.).
- `anonymise()` L325-330 : `action = anonymise`.

Aucune autre occurrence d’écriture dans le dépôt. Les listes dossiers /
offres / parcelles qui affichent `libelleAffiche()` **ne journalisent
pas**.

### 2. Un nom dans ce sélecteur = un accès à journaliser ?

**Au sens du mécanisme existant : non.** Le journal couvre la consultation
de la fiche complète, pas l’apparition d’un nom dans un libellé. Afficher
`MARTIN, BLANC` dans l’AutoComplete **n’écrirait rien** dans
`proprietaire_access_logs`. Ce n’est pas une raison de le faire : ce serait
un traitement de donnée personnelle **hors journal**.

### 3. `foncier.lecture` / `foncier.prix` et les noms ailleurs

- Module Foncier entier : middleware `feature.permission:foncier.lecture`
  (`routes/web.php` ~L720, L764).
- `foncier.prix` : montants / valorisations **absents du JSON** sans le
  droit (couche données, pas masquage UI). Les **noms** ne sont pas liés à
  `foncier.prix`.
- Groupes mesurés dans `config/feature_permissions.php` :
  - `foncier.lecture` : **GS_DSI**, **GS_GEMME_PDG**, **GS_HECTARE**.
  - **GS_DSI ≠ GS_ADMIN_ERP** (deux groupes).
  - **GS_COMPTABILITE** : `factures.*` (donc dépôt), **pas** `foncier.*`.
  - **GS_ENVOL** : `factures.depot.ecriture` **et** `!foncier.*`
    (exclusion explicite).

Les noms de propriétaires n’apparaissent aujourd’hui que derrière
`foncier.lecture`. Les livrer dans le formulaire de dépôt les exposerait
à la comptabilité et au commercial ENVOL, populations **volontairement
hors foncier**.

➡️ **Incompatible.** Arrêt. Arbitrage Robin attendu, par exemple :
(A) livrer le format maquette tel quel (élargissement d’audience assumé,
éventuellement journaliser) ; (B) libellé sans nom
(`PONTEILLA (DF-2026-003)`) ; (C) restreindre le dépôt Projet à
`foncier.lecture` (contredit « ouvert à tous »).

## FAITS ÉTABLIS POUR LA REPRISE (non livrés)

### Résolution INSEE (mécanisme EXISTANT — ne pas en créer un second)

`DossierFoncier::commune()` — `app/Models/DossierFoncier.php` L137-140 :
`belongsTo(Commune::class, 'code_insee_commune', 'code_insee')`.
Table `communes`, PK `code_insee`, nom dans `communes.nom`
(`app/Models/Commune.php`). Même relation que `SecteurPerimetre` et
`Parcelle`. Front : `CommuneSelect` / `ReferentielCommunes` consomment
cette table, pas une seconde correspondance.

Repli proposé (non tranché, non codé) : code NULL ou commune introuvable
→ `SANS COMMUNE` (majuscules, jamais vide, jamais `null`).

### Ordre des 2 propriétaires (si l’arbitrage A débloque)

Pivot `dossier_foncier_proprietaire` (`id`, `dossier_foncier_id`,
`proprietaire_id`, timestamps), unique `(dossier, proprio)`.
`sync()` peut recréer les lignes pivot → `pivot.id` **instable**.
Critère proposé : `orderBy('proprietaires.id')` croissant (id technique
stable). Personne morale : pas de nom de famille → `raison_sociale`
(comme `Proprietaire::libelleAffiche()`, sans prénom).

### Types inactifs

Colonne littérale `postes_budgetaires_types.actif` (boolean, défaut true)
— create `2026_04_18_100100` L28 ; enseigne
`2026_07_23_120000` L62-108 (`enseigne_id` NOT NULL, unique
`(enseigne_id, code_interne)`). Code = `code_interne` (pas `code`).
Libellé = `libelle`.

Précédents pour **choisir** un type :
- `PosteBudgetaireType::scopeActif` → `where('actif', true)`
- `ProvidesPosteBudgetaireTypeOptions` : actifs + éventuellement un
  inactif **déjà lié**
- `DossierFoncierPosteBudgetaireService::typesActifsPourEnseigne` : actifs
  uniquement
Admin nomenclature : affiche aussi les inactifs (écran de gestion).

Pour une **nouvelle** facture Projet : **actifs seulement** (aucun type
déjà lié). Aligné sur le service dossier #1448.

### Mapping prévu (non branché)

| Composant | Libellé affiché | Valeur postée | Libellé back |
|---|---|---|---|
| Destination | Programmes | `PROGRAMMES` | `ocr_raw.saisie.destination` / Rule::in |
| Destination | Frais généraux | `FRAIS_GENERAUX` | idem |
| Destination | **Projet** (singulier) | `PROJET` | idem — `PROJETS` PAS dans Rule::in |
| Dossier | `COMMUNE — NOM1, NOM2 (REF)` | `dossier_foncier_id` (int) | `depot_factures.dossier_foncier_id` |
| Poste | `A03 — Frais de notaires` | `poste_budgetaire_type_id` (int) | `depot_factures.poste_budgetaire_type_id` |

Bouton actuel L8450-8457 `DepotFactureSaisieForm.vue` : `disabled`,
libellé **PROJETS**. `destinationOptions` L1658 n’a que deux valeurs.

Masse / Outlook : refus PROJET à conserver (`DepotFactureController`
L198, L290).

## DÉPLOIEMENT-TEST

Aucun. Pas de migrate, pas de journal:sync, pas de rebuild. Le bouton
« PROJETS » reste grisé.

## LEÇON

Un format d’affichage validé qui contient un nom de personne n’est pas
un détail UI : il élargit le public des données personnelles. Le journal
`proprietaire_access_logs` ne couvre que la fiche. `!foncier.*` sur
GS_ENVOL + absence de `foncier.lecture` sur GS_COMPTABILITE = le dépôt
n’est pas un écran foncier. Trancher l’audience **avant** d’activer le
bouton.
