# Chantier — Flag `peut_intervenir_terrain` sur compte admin

> ## ✅ CHANTIER LIVRÉ EN PRODUCTION
> **Vérifié le 2026-05-29** — Ne plus relire pour valider la livraison.

**Date :** 2026-05-16
**Statut :** livré en local, en attente de validation visuelle + push prod
**Périmètre :** CoolCare (port MissioFlow à faire après validation)

## Pourquoi

Avant ce chantier, les comptes admin étaient **inclus de facto** dans toutes les listes "terrain" via des pansements éparpillés :

| Endroit | Pansement | Effet |
|---------|-----------|-------|
| Sélecteur tech pour intervention | `Technicien::getForSelect()` exclut seulement `superadmin` | Tous les admins (y compris Violaine) apparaissaient |
| Gestion du stock bouteilles | `BouteilleGaz::statsParTechnicien()` filtrait `role IN ('technicien','admin')` (commit 9e00767 du 2026-05-16) | Tous les admins apparaissaient |
| Matrice activité dashboard | `MatriceActiviteService::loadTechniciens()` sous-requête "admin avec intervention sur la période" (cas Amadou) | Tous les admins ayant une intervention historique apparaissaient |

**Cas Violaine** (admin métier, jamais sur le terrain) : impossible à exclure sans nouveau pansement spécifique. Et chaque nouvel admin métier aurait demandé un nouveau bricolage.

**Décision :** un flag explicite par compte (`peut_intervenir_terrain` TINYINT, default 1 → rétro-compat). La checkbox n'est visible que pour `role=admin` dans la modale utilisateur (les techniciens sont toujours considérés terrain).

## Quoi (livré)

### Phase 1 — BDD + modèle

- [database/migration_techniciens_peut_intervenir_terrain.sql](../coolcare-app/database/migration_techniciens_peut_intervenir_terrain.sql) + rollback
- [database/schema.sql](../coolcare-app/database/schema.sql) : colonne ajoutée pour les tests d'intégration (CI)
- [src/models/Technicien.php](../coolcare-app/src/models/Technicien.php) :
  - `appendIntFields()` gère le champ pour `update()`
  - `create()` (INSERT) inclut explicitement le champ avec fallback 1
  - `formatTechnicien()` retourne `peut_intervenir_terrain` au JSON API (sans ça, le JS reçoit `undefined` à l'édition)

### Phase 2 — UI

- [public/admin/techniciens.php](../coolcare-app/public/admin/techniciens.php) : section verticale dédiée `adminTerrainRow` (vert pâle), visible uniquement si role=admin (masquage, pas disabled). Case cochée par défaut.
- [public/js/admin/techniciens.js](../coolcare-app/public/js/admin/techniciens.js) :
  - `updateAdminTerrainRowVisibility()` toggle show/hide lors d'un change de role
  - `getAdminTerrainPayload()` extrait 0/1 si role=admin, `{}` sinon
  - `openAddTechnicienModal()` reset checkbox à coché + appel toggle
  - `editTechnicien()` pré-remplit selon `tech.peut_intervenir_terrain` (fallback 1)
  - `saveTechnicien()` payload enrichi via spread

### Phase 3 — Retrait des 3 pansements

- [src/models/Technicien.php](../coolcare-app/src/models/Technicien.php) `getForSelect()` : filtre admins avec `peut_intervenir_terrain != 1`
- [src/models/BouteilleGaz.php](../coolcare-app/src/models/BouteilleGaz.php) `statsParTechnicien()` : `role IN ('technicien','admin')` → `role = 'technicien' OR (role = 'admin' AND COALESCE(peut_intervenir_terrain,1) = 1)`
- [src/services/MatriceActiviteService.php](../coolcare-app/src/services/MatriceActiviteService.php) `loadTechniciens()` : sous-query "admin avec intervention sur période" supprimée, remplacée par filtre direct sur le flag. Signature de méthode conservée (`$startDate`, `$endDate`) pour rétro-compat appelants ; les paramètres ne sont plus utilisés.
- [tests/Integration/Cases/MatriceActiviteIntegrationTest.php](../coolcare-app/tests/Integration/Cases/MatriceActiviteIntegrationTest.php) : 2 tests réécrits pour refléter la nouvelle logique (admin terrain par défaut + admin bureau exclu même avec intervention)

## Décisions validées (2026-05-16)

- **Migration data** : tous les admins existants migrés à `peut_intervenir_terrain = 1` (default DDL). Violaine sera décochée manuellement via l'UI après déploiement prod.
- **Matrice activité** : un admin avec `peut_intervenir_terrain = 0` est **masqué complètement**, même s'il a des interventions historiques sur la période affichée. Cohérent avec le flag.
- **Techniciens** : pas de checkbox dans la modale (techniciens implicitement terrain), default 1 cote BDD.

## Validation

- ✅ Migration appliquée en local (BDD `coolcare_app` dans container `coolcare-test_database`)
- ✅ 4265 tests unit passent
- ⏳ Test visuel manuel Phase 2 confirmé par Bruno (modale OK)
- ⏳ Test visuel Phase 3 (sélecteur intervention, stock, matrice) à confirmer
- ⏳ Migration prod OVH à appliquer par Bruno avant push code

## Port MissioFlow

À faire à l'identique après validation coolcare. Le MD miroir vit dans
`missioflow-app/docs/CHANTIER_FLAG_ADMIN_TERRAIN.md` (non commit jusqu'à port effectif).
