# IliaCloud — Roadmap Partage d'Acces

> Suivi etape par etape de l'implementation du partage d'acces multi-user.
> Branche : `feature/partage-acces`
> Spec complete : [PARTAGE_ACCES.md](PARTAGE_ACCES.md)
> Debut : 7 avril 2026

---

## Phase 0 — Infrastructure de dev

- [x] **DNS dev**
  - `dev.app.iliacloud.com` → 141.94.42.172 (A record)
  - `dev.api.iliacloud.com` → 141.94.42.172 (A record)

- [x] **Stack Docker dev sur le VPS**
  - `docker-compose.dev.yml` (stack `iliacloud-dev`)
  - Volume Postgres isole (`postgres_data_dev`)
  - Traefik labels : `dev.app.iliacloud.com` / `dev.api.iliacloud.com`
  - CORS_ORIGIN = `https://dev.app.iliacloud.com`
  - JWT_SECRET et ENCRYPTION_KEY differents de la prod
  - Cles Stripe TEST (a configurer plus tard)
  - Frontend : `Dockerfile.dev` avec VITE_API_URL/VITE_WS_URL pointant vers dev.api
  - Images : `iliacloud-backend-dev:latest` / `iliacloud-frontend-dev:latest`
  - Stack deployee et operationnelle (4 services healthy)
  - Source dev separee : `~/iliacloud-dev-src/` sur le VPS

- [x] **Seed de donnees dev**
  - Compte owner : `dev@iliacloud.com` / `DevTest2026!` (plan business, email verifie)
  - Compte membre test : `membre@test.com` / `TestMembre2026!` (plan free, email verifie)
  - 1 serveur : VPS OVH Principal (141.94.42.172)
  - Groupes de test : Faildaily (5 containers), CoolCare
  - 43 actions rapides predefinies en base (21 serveur + 22 Docker)
  - 24 monitors uptime avec `docker_service` rempli
  - 24 certificats SSL avec `docker_service` rempli

---

## Phase 1 — Schema SQL et migration

- [x] **1.1 Fonction `is_valid_group_permissions()`**
- [x] **1.2 Table `access_groups`** — hard-delete (soft-delete supprime)
- [x] **1.3 Table `access_group_members`**
- [x] **1.4 Table `access_group_invitations`**
- [x] **1.5 Table `access_group_servers`**
- [x] **1.6 Table `access_group_docker_targets`**
- [x] **1.7 Table `access_group_file_roots`**
- [x] **1.8 Table `access_group_cron_entries`**

- [x] **1.9 Colonnes `group_id` sur tables existantes**
  - `uptime_monitors`, `ssl_certificates`, `alert_rules`, `webhooks`, `status_pages`, `log_paths`, `annotations`, `audit_logs`
  - Colonnes NULLABLE + index

- [x] **1.10 Colonnes `docker_service` (nouveau)**
  - `uptime_monitors.docker_service` — lie un monitor au service Docker Traefik
  - `ssl_certificates.docker_service` — idem pour les certs
  - Rempli automatiquement via le scan Traefik

- [x] **1.11 Colonne `container_id` sur quick_actions (nouveau)**
  - Permet de lier une action rapide a un container Docker specifique
  - Les membres ne voient que les actions avec un container_id matchant leur groupe

- [x] **1.12 Config plans** — `groups_per_server` : Free=0, Pro=0, Business=10, Enterprise=20

- [x] **1.13 Tests migration** — zero regression, migration idempotente

---

## Phase 2 — Middlewares et helpers backend

- [x] **2.1 Helper `groupAccess.js`** — resolveGroupContext, cache LRU, satisfiesLevel
- [x] **2.2 Middleware `requireGroupContext()`** — lit X-Group-Id, remplit req.access
- [x] **2.3 Middleware `requireGroupPermission(zone, minLevel)`** — owner bypass
- [x] **2.4 Middleware `requireGroupServer(serverId)`** — verifie lien group→server

- [x] **2.5 Helper `dockerTargets.js` (nouveau)**
  - `filterByGroupTargets()` — filtre containers par docker_targets
  - `filterNamesByGroupTargets()` — filtre noms de containers (pour scans)
  - `matchesTargets()` — verifie si un nom matche les targets
  - `loadGroupTargets()` — charge les targets depuis la DB
  - Utilise par docker.js, logs.js, backups.js, uptime.js, ssl.js, quickActions.js, websocket.js

- [x] **2.6 Helper `groupScope.js` (nouveau)**
  - `applyGroupScope()` — ajoute un filtre group_id a une requete SQL

- [x] **2.7 Evolution `ownsServer()` (nouveau)**
  - Accepte `req.access` en 3eme parametre
  - En mode groupe, verifie via `access.serverIds` au lieu de `user_id`
  - Modifie dans : serverOwnership.js, files.js, backups.js, cron.js

- [x] **2.8 Evolution SSH `getConnection()` (nouveau)**
  - Accepte les membres de groupe (requete elargie avec access_group_members)
  - Le membre utilise la connexion SSH du proprietaire du serveur

- [x] **2.9 Evolution `getEffectivePlan()` (nouveau)**
  - En mode groupe, retourne le plan du proprietaire (pas du membre)
  - Utilise dans planLimits.js, billing.js, websocket.js (checkWsFeature)
  - Le membre herite du plan business/enterprise du proprietaire

- [x] **2.10 Middleware quotas** — checkSeatQuota, checkGroupsPerServerQuota
- [x] **2.11 Tests Phase 2** — 175+ tests

---

## Phase 3 — Routes backend CRUD groupes

- [x] **3.1 Routes CRUD groupes** — POST/GET/PATCH/DELETE /groups
- [x] **3.2 Routes membres** — GET/PATCH/DELETE /groups/:id/members

- [x] **3.3 Routes invitations**
  - POST/GET/DELETE /groups/:id/invitations
  - POST resend, POST accept
  - Service : groupInvitations.js (hash SHA-256, expiration 72h, send_count max 5)

- [x] **3.4 Ajout direct de membre (nouveau)**
  - Si l'email est deja membre actif d'un AUTRE groupe du meme owner → ajout direct sans email
  - Si l'email est inconnu ou pas dans les groupes de l'owner → invitation classique
  - Securite : ne revele pas l'existence d'un compte en base
  - Message frontend : "X a ete ajoute directement au groupe"

- [x] **3.5 Liaison post-inscription** — acceptPendingInvitationsForEmail dans POST /auth/register
- [x] **3.6 Routes serveurs** — POST/DELETE /groups/:id/servers

- [x] **3.7 Routes Docker targets** — GET/POST/DELETE /groups/:id/docker-targets
- [x] **3.8 Container listing endpoint (nouveau)** — GET /groups/:id/servers/:sid/containers
  - Retourne les noms de service Docker dedupliques (Swarm)
  - Pour la UI de selection des containers dans le groupe

- [x] **3.9 Routes ressources (assignation)** — GET/PUT /groups/:id/resources/:table, GET /groups/:id/all-resources/:table
  - *Note : desactive au profit du filtrage automatique par docker_service*

- [x] **3.10 Tests Phase 3** — groupes, membres, invitations, serveurs, docker targets, invitation routes

---

## Phase 4 — Adapter les routes existantes (backend)

### Filtrage automatique par docker_targets (source unique de verite)

- [x] **4.1 Docker** — filterByGroupTargets sur containers + stacks (par services contenus)
- [x] **4.2 Logs GET** — filtre auto par docker_targets (type docker/docker-file), fichiers systeme masques en mode groupe
- [x] **4.3 Logs scan** — fichiers systeme masques, containers filtres par docker_targets
- [x] **4.4 Backups GET** — filtre auto par db_container matchant docker_targets
- [x] **4.5 Backups scan** — containers DB filtres par docker_targets

### Filtrage automatique par docker_service (uptime/SSL)

- [x] **4.6 Uptime GET** — filtre par docker_service matchant docker_targets, utilise effectiveUserId (owner du groupe)
- [x] **4.7 Uptime scan** — parse Traefik labels avec mapping service→host, filtre en mode groupe, auto-remplit docker_service
- [x] **4.8 SSL GET** — filtre par docker_service matchant docker_targets, utilise effectiveUserId
- [x] **4.9 SSL scan** — filtre par monitors uptime du groupe, auto-remplit docker_service sur certs existants

### Routes sans filtrage container (acces controle par permissions)

- [x] **4.10 Webhooks** — pas de filtrage container, acces controle par permission zone
- [x] **4.11 Status pages** — idem
- [x] **4.12 Alert rules** — filtrees par server_id + requireGroupServer
- [x] **4.13 Alert history** — filtree par server_id dans les serverIds du groupe
- [x] **4.14 Audit** — filtre par group_id
- [x] **4.15 Annotations** — checkServerOwnership avec req.access + effectiveUserId pour les requetes
- [x] **4.16 Metrics history** — acces serveur verifie via req.access.serverIds
- [x] **4.17 Dashboard** — requireGroupServer, metriques serveur

### Actions rapides Docker pour les membres

- [x] **4.18 Quick actions GET** — membres ne voient que les actions avec container_id matchant docker_targets
- [x] **4.19 Quick actions RUN** — execution via `docker exec -i` pour les membres, commande passee par stdin
- [x] **4.20 Quick actions POST** — champ container_id optionnel pour creer des actions Docker

### Chat IA pour les membres

- [x] **4.21 Chat sessions** — check serveur via req.access.serverIds au lieu de user_id
- [x] **4.22 Chat cle API** — utilise la cle API du proprietaire du groupe (keyOwnerId)

### Tests Phase 4

- [x] **4.23 Tests groupe-aware** — 37+ tests dans 14 fichiers existants
- [x] **4.24 Deploy stack dev OK** — 3830 tests, 85 fichiers, zero echec

---

## Phase 5 — WebSocket groupe-aware

- [x] **5.1 Subscribe groupe-aware** — verifyServerAccess centralise avec groupId
- [x] **5.2 Terminal SSH owner** — shell SSH complet sur le serveur
- [x] **5.3 Terminal Docker membre (nouveau)**
  - Selecteur de container dans le drawer terminal
  - `docker exec -it` dans le container du groupe
  - Le membre est enferme dans le container (pas d'acces serveur)
  - `docker ps` non disponible dans le container
  - Commande `clear` apres ouverture pour masquer le prompt SSH
- [x] **5.4 Docker logs streaming** — permission docker=read requise
- [x] **5.5 WebSocket metrics** — frontend envoie groupId dans le message subscribe
- [x] **5.6 Plan inheritance WebSocket** — checkWsFeature utilise le plan du owner du groupe
- [x] **5.7 Tests WebSocket** — 7+ tests groupe-aware

---

## Phase 6 — Frontend

### Infrastructure

- [x] **6.1 `api.js`** — injection X-Group-Id, initialisation depuis localStorage au chargement
- [x] **6.2 `GroupContext.jsx`** — charger groupes, persister groupe actif, hasPermission, isOwner
  - Auto-selection du premier groupe pour les membres a la premiere connexion
- [x] **6.3 `usePlan.js`** — re-fetch /billing/status quand le groupe change (plan du owner)

### Selecteurs header

- [x] **6.4 Ordre header** — Serveur en premier, puis Groupe
- [x] **6.5 GroupSelector** — n'apparait que si le serveur selectionne a des groupes lies
  - Filtre les groupes par serveur actif
  - Option "Tout le serveur" (mode global, owner only)
  - Desactivation auto si changement de serveur incompatible
- [x] **6.6 ServerContext** — depend de activeGroup, re-fetch quand le groupe change
- [x] **6.7 GET /groups** — retourne server_ids via json_agg pour le frontend

### Pages — re-fetch au changement de groupe

- [x] **6.8 Toutes les pages data** — activeGroup?.id dans les deps du useEffect principal
  - UptimePage, SSLPage, DockerPage, LogsPage, BackupPage, CronPage, WebhooksPage, StatusPagesPage, AuditPage, ActionsPage
  - Reset du state (setData([])) avant le re-fetch pour eviter le flash de donnees perimees

### Permissions et acces

- [x] **6.9 Menu hamburger** — liens filtres par hasPermission(zone, 'read') + isOwner pour owner_only
- [x] **6.10 Bottom nav** — idem
- [x] **6.11 PermissionRoute** — guard sur chaque route dans App.jsx, redirect vers / si pas d'acces
- [x] **6.12 Pages owner-only** — Fichiers et Import/Export masques et proteges pour les membres
- [x] **6.13 Terminal dans le menu** — deplace du bouton flottant vers le menu hamburger

### Settings

- [x] **6.14 Onglet Groupes** — CRUD groupes, serveurs, invitations, docker targets (checkboxes)
  - Section "Repertoires accessibles" supprimee (fichiers = owner only)
- [x] **6.15 Matrice de permissions** — niveaux adaptes par zone
  - `['none', 'read']` : Dashboard, Metriques, Logs, Uptime, SSL, Webhooks, Status pages, Audit
  - `['none', 'read', 'write']` : Docker, Cron, Backups, Alertes, Annotations
  - `['none', 'write']` : Terminal, Actions rapides, Chat IA
  - Presets adaptes : Lecteur, Operateur, Admin
- [x] **6.16 Tabs filtres par role** — membres voient uniquement "Compte"
  - Groupes, Alertes, SSH, Serveurs, IA, Email, Rapport, API, Billing = owner only
  - Tab par defaut = account pour les membres
  - Fallback auto si tab actif non visible

### Actions lecture seule pour les membres

- [x] **6.17 readOnly vs canWrite** — logique splitee
  - `readOnly` (owner only) : Scan, Ajouter, Supprimer
  - `canWrite` (permission write) : Start/Stop/Restart, Restore, Run, Toggle, Edit
  - Applique sur : Docker, Backups, Cron, Webhooks, Actions, SSL, Uptime, Audit, Status pages, Logs

### Onboarding et UX membre

- [x] **6.18 OnboardingGuide** — masque pour les membres de groupe
- [x] **6.19 Texte sombre corrige** — Modal.jsx avec text-gray-100 par defaut
- [x] **6.20 Message succes invitation** — "X a ete ajoute directement" ou "Invitation envoyee"
- [x] **6.21 Acceptation invitation** — InviteAcceptPage.jsx, redirect apres 2s

### Tests Frontend

- [x] **6.22 Tests** — 1479 tests frontend, 66 fichiers, mock GroupContext dans tous les tests
  - GroupSelector, Layout, TerminalDrawer, App routing, OnboardingGuide, usePlan
  - Pages adaptees avec mocks GroupContext + ServerContext

---

## Phase 7 — Tests complets

- [x] **7.1 Couverture tests groupes** — 3830 tests backend, 85 fichiers
  - Groups CRUD : 27 tests
  - Group invitations service : 19 tests
  - Group members : 17 tests (dont 5 ajout direct)
  - Group servers : 12 tests (dont 4 container listing)
  - Group permissions : 131 tests
  - Group context : 30 tests
  - Group seat quota : 14 tests
  - Docker targets CRUD : 10 tests
  - Invitation API routes : 9 tests
  - Plan inheritance : 4 tests
  - Audit group filtering : 1 test
  - Integration tests : 37+ tests dans 14 fichiers (docker, logs, backups, uptime, ssl, quickActions, websocket, alerts, files, annotations, metrics)

---

## Phase 8 — Migration des donnees existantes

> Non necessaire : un seul utilisateur en prod, colonnes group_id NULLABLE,
> le code gere `NULL` en mode global. Les groupes sont crees a la demande.
> A reconsiderer uniquement si migration multi-tenant avec utilisateurs existants.

- [x] **8.1-8.3** — Non applicable (pas de donnees a migrer)

---

## Phase 9 — Tests E2E

- [x] **9.1 Scenarios Playwright** — 7 scenarios, 18 tests E2E total (auth + nav + status + groupes)
  - Setup auth via API (storageState) pour eviter le rate limiter
  - S1 : Owner accede a Docker avec groupe selectionne
  - S2 : Membre ne voit que les groupes auxquels il appartient (pas CoolCare)
  - S3 : Membre docker=read ne voit pas les boutons start/stop/restart
  - S4 : Membre sans permission terminal ne voit pas le lien
  - S5 : Membre avec terminal ouvre le drawer terminal
  - S6 : Membre accede aux actions rapides Docker
  - S7 : Owner accede a l'audit filtre par groupe

---

## Phase 10 — Mise en production

- [x] **10.1 Checklist pre-prod**
  - 3830 tests backend : 100% ✅
  - 1471 tests frontend : 100% ✅
  - Schema SQL retrocompatible (colonnes NULLABLE, IF NOT EXISTS, pas de DROP) ✅
  - Mode global (sans groupe) : req.access = null, tout le code de filtrage saute ✅
  - Aucune regression sur les fonctionnalites existantes ✅

- [x] **10.2 Merge et deploiement**
  - Merge feature/partage-acces → main (fast-forward, 130 fichiers, +10902 lignes)
  - Push sur main → CI/CD declenche
  - Schema SQL se migre automatiquement (ALTER TABLE idempotents)
  - App fonctionne en mode global pour l'owner existant (aucun groupe = comportement identique a avant)
  - L'owner cree ses groupes quand il est pret depuis Parametres > Groupes

---

## Phase 11 — Mise a jour ROADMAP.md et site vitrine

- [x] **11.1 Mise a jour roadmap produit globale** — ROADMAP.md : feature cochee avec details
- [ ] **11.2 Mise a jour monetisation** — MONETISATION.md a mettre a jour avec quotas groupes
- [x] **11.3 Mise a jour API et docs techniques** — Section 11 ajoutee dans API.md (routes, permissions, filtrage, codes erreur, quotas)
- [x] **11.4 Verification site vitrine (pricing + features)** — Home, pricing, features, comparaison (FR+EN)
- [ ] **11.5 Validation marketing** — Captures d'ecran, cas d'usage concret
- [ ] **11.6 Checklist publication documentaire** — Relecture finale

---

## Phase 12 — Retrospective et optimisations post-lancement

- [ ] **12.1 Retrospective produit (J+7 / J+30)**
- [ ] **12.2 Monitoring erreurs post-lancement**
- [ ] **12.3 Analyse performance et charge**
- [ ] **12.4 Analyse adoption fonctionnalite**
- [ ] **12.5 Optimisations UX prioritaires**
- [ ] **12.6 Ajustements quotas et packaging**
- [ ] **12.7 Correctifs et hardening securite**
- [ ] **12.8 Plan d'iteration suivante**

---

## Phase 13 — Documentation utilisateur et FAQ

> Documentation exhaustive de l'application. FAQ in-app publiee sur `/faq`.

- [x] **13.1 a 13.14** — Toutes les sections FAQ completees (Onboarding, SSH, Dashboard, Docker, Uptime, SSL, Logs, Fichiers, Cron, Backups, Chat, Alertes, Audit, Parametres)

---

## Resume des fichiers crees/modifies

### Backend — nouveaux fichiers
- `src/helpers/dockerTargets.js` — filtrage containers par docker_targets
- `src/helpers/groupScope.js` — filtrage SQL par group_id
- `src/helpers/groupAccess.js` — resolution contexte groupe + cache
- `src/services/groupInvitations.js` — invitations email + acceptation
- `src/routes/groups.js` — CRUD groupes, membres, invitations, docker targets, file roots, containers
- `src/middleware/groupContext.js` — middlewares groupe

### Backend — fichiers modifies
- `src/services/ssh.js` — support membres groupe dans getConnection
- `src/helpers/serverOwnership.js` — ownsServer avec req.access
- `src/middleware/planLimits.js` — getEffectivePlan (plan owner du groupe)
- `src/routes/billing.js` — /billing/status retourne plan du owner en mode groupe
- `src/routes/docker.js` — filterByGroupTargets, stacks par services
- `src/routes/logs.js` — filtrage auto docker_targets + scan filtre
- `src/routes/backups.js` — filtrage auto docker_targets
- `src/routes/uptime.js` — docker_service, effectiveUserId, scan Traefik mapping
- `src/routes/ssl.js` — docker_service, effectiveUserId, scan auto-fill
- `src/routes/alerts.js` — filtrage alert_history par serverIds
- `src/routes/audit.js` — filtrage par group_id
- `src/routes/annotations.js` — checkServerOwnership avec access
- `src/routes/metrics.js` — acces serveur via access.serverIds
- `src/routes/quickActions.js` — docker exec pour membres, container_id, shellEscape
- `src/routes/chat.js` — access.serverIds, keyOwnerId pour cle API
- `src/routes/webhooks.js` — permission read suffit
- `src/routes/statusPage.js` — permission read suffit
- `src/routes/servers.js` — filtrage par groupe
- `src/websocket.js` — terminal Docker, plan inheritance, groupId dans subscribe
- `src/db/schema.sql` — 7 tables + colonnes docker_service, container_id

### Frontend — nouveaux fichiers
- `src/components/GroupSelector.jsx`
- `src/components/PermissionGate.jsx`
- `src/components/settings/GroupsTab.jsx`
- `src/contexts/GroupContext.jsx`
- `src/pages/InviteAcceptPage.jsx`

### Frontend — fichiers modifies
- `src/lib/api.js` — X-Group-Id header, activeGroupId depuis localStorage
- `src/lib/usePlan.js` — re-fetch sans cache quand groupe change
- `src/lib/websocket.js` — groupId dans subscribe
- `src/components/Layout.jsx` — ordre selecteurs, menu filtre, terminal dans menu
- `src/components/TerminalDrawer.jsx` — selecteur container pour membres
- `src/components/OnboardingGuide.jsx` — masque pour membres
- `src/components/Modal.jsx` — text-gray-100 dark mode
- `src/contexts/ServerContext.jsx` — depend de activeGroup
- `src/App.jsx` — PermissionRoute, useGroup
- `src/pages/*.jsx` — 10 pages avec activeGroup deps, readOnly/canWrite logique
- `src/pages/SettingsPage.jsx` — tabs owner-only, fallback tab actif
