﻿# Projet local

Stack :
- PHP 8.3.14
- Laravel
- MySQL 9.1
- n8n (automations)

# Règles générales

- Réponses en français
- Code complet uniquement
- Pas d'explications basiques
- Modifier uniquement ce qui est demandé
- Ne pas proposer de refactor inutile
- Commencer par lire le contenu de l'existant
- Modifier directement le code
- Tous les messages de confirmation doivent s'afficher dans des fenêtres modales dont la gestion est externalisée (principe DRY de Laravel)

# PHP

- Utiliser PHP 8+ strict
- PDO pour accès DB (si hors Laravel)
- Requêtes préparées obligatoires
- Pas de code obsolète (mysql_* interdit)

# Laravel

- Respecter conventions Laravel
- Utiliser Eloquent sauf demande contraire
- Utiliser migrations pour DB
- Utiliser services/controllers propres
- Pas de logique métier dans les controllers si possible

# MySQL

- SQL explicite et lisible
- Index si performance critique
- Pas de requêtes non paramétrées
- Respect schéma existant

# Divers

- Messages de confirmation dans des fenêtres modales
- Messages d'alerte dans des fenêtres modales
- Fenêtres modales toutes sur le même modèle

# API / intégrations

- JSON standard
- REST privilégié
- Toujours gérer erreurs HTTP

# Sécurité

- Validation des inputs obligatoire
- Pas d'injection SQL
- Pas de secrets en dur dans le code

# Session IAM — Juillet 2026

## Architecture
- `personnes` = référentiel maître unique (pas de doublons), `sources` (JSON) liste les apps où la personne existe
- `comptes` → `application_id` (FK → `applications.id`)
- `applications` : GestUp, RH, NC, AD, Microsoft365, Keycloak
- `Compte::forApp('AD')` scope via `whereHas('application', fn => $q->where('code', ...))`

## Connecteurs
- Types disponibles : `AD`, `Microsoft365`, `IHTS`, `Keycloak`, `Partage` (seuls ceux avec classe implémentée)
- Type modifiable en édition (select caché + lien "Changer")
- Configuration en JSON, cast `EncryptedJson` (retourne `[]` si null, null si vide)
- Actions : Découvrir, Synchroniser, Importer, Réconcilier, Scan SP (M365)
- `ConnecteurController@executer` dispatch les scans longs en jobs asynchrones

## Scans asynchrones (SharePoint + Fichiers)

### SharePoint (`ScanSharePointJob`)
- Scanne récursivement un site SharePoint via Graph API
- Sauvegarde les ACL dossier par dossier (incrémental)
- Vérifie `estStoppe()` entre chaque dossier (statut `stopped` → arrêt propre)
- `stopped_le` enregistré si arrêté
- Utilise `Microsoft365Connector` avec méthodes publiques : `authenticate()`, `api()`, `getAll()`, `findSharePointSite()`, `getItemPermissions()`, `mapPermissionEntries()`

### Fichiers Partages (`ScanPartageJob`)
- Scanne via `icacls /T` (local → UNC → net use)
- Sauvegarde les ACL en une fois après parsing
- Vérifie `estStoppe()` avant de lancer icacls et après
- Replit la logique de `PartageConnector` (execIcacls, parseIcaclsOutput, parseAclEntry)

### Queue worker
- `QUEUE_CONNECTION=database`
- `runQueueWorker()` dans `ConnecteurController` : crée un .bat temporaire → `start /B ""` (évite PHP_BINARY = httpd.exe sous Apache)
- `start-queue-worker.bat` : worker permanent (double-clic)
- Fichier `.bat` dans `storage/app/queue-worker.bat`, log dans `storage/logs/queue-worker.log`

### Statuts des scans
- `pending` → `running` → `completed` / `failed` / `stopped`
- `stopping` n'existe plus (remplacé par `stopped` direct)
- Auto-refresh page toutes les 5s si scan en cours
- Un seul scan par type à la fois (vérifié dans ConnecteurController)
- Bouton Stop → `statut='stopped'`, `stopped_le=now()`

### Tables
- `sharepoint_scans` : id, statut, site_url, site_name, scanne_le, stopped_le, total_dossiers, total_entrees_acl, erreurs, declenche_par
- `sharepoint_acl_entries` : id, sharepoint_scan_id, dossier, chemin_complet, type, principal, email, droits, heritage, est_herite
- `partage_scans` : id, statut, serveur, chemin, scanne_le, stopped_le, total_dossiers, total_entrees_acl, erreurs, declenche_par
- `partage_acl_entries` : id, partage_scan_id, dossier, chemin_complet, type, principal, sid, droits, heritage, est_herite

## Module Changements
- Supprimé (approbation des modifications de connecteurs retirée)

## Fichiers clés récents
- `app/Jobs/ScanSharePointJob.php` — Job async scan SP
- `app/Jobs/ScanPartageJob.php` — Job async scan fichiers
- `app/Http/Controllers/PermissionsController.php` — stopPartage, stopSharepoint
- `app/Modules/Connecteurs/Controllers/ConnecteurController.php` — executer() avec dispatch async, runQueueWorker()
- `app/Modules/Connecteurs/Connectors/Microsoft365Connector.php` — méthodes passées en public pour les jobs
- `app/Http/Controllers/PermissionsController.php` — stop methods
- `resources/views/permissions/index.blade.php` — statuts + stop buttons + auto-refresh
- `resources/views/permissions/detail.blade.php` — arbre ACL dépliable
- `resources/views/modules/connecteurs/index.blade.php` — boutons désactivés si scan en cours
- `resources/views/modules/connecteurs/form.blade.php` — type éditable + aides config

## Pistes futures
- Réconciliation AD/M365 intégrée dans `iam:m365-sync` (étape 2)
- Keycloak : SSL certificate issue (cURL error 60)
- GroupeService : migration `source` → `application` pour le filtre dans l'UI
- Planifier scans automatiques (cron fichiers + commande artisan)
