# God Mode (SuperAdmin) — checklist QA complète avant prod

Runbook de vérification de l'espace SuperAdmin (`/admin`, route group `(superadmin)`)
à dérouler **avant tout passage en production**. Ne reporter que les écarts
(référencer le n° d'étape).

Surfaces couvertes : shell séparé + gate 2FA, Overview, Users, Organizations,
Billing (Stripe), Audit, Export & Metrics.

---

## 0. Pré-requis prod (à valider AVANT de tester / déployer)

> ⚠️ Règle projet : aucune migration / promotion prod sans autorisation explicite.
> Ces points sont des **conditions de mise en prod**, pas des actions automatiques.

- [ ] **Migrations appliquées en prod** : `0047_*` (`admin_audit_log`) et
      `0048_*` (`org_limit_overrides`). Vérifier `drizzle.__drizzle_migrations`
      après `db:migrate` côté prod.
- [ ] **Env** : `SUPER_ADMIN_EMAILS` défini en prod (CSV des god users). Sans lui,
      `/admin` renvoie 404 pour tout le monde.
- [ ] **Rôle admin stampé** pour les god users existants : `bun run backfill:admin-roles`
      (les appels du plugin admin — ban/impersonate/… — exigent `role="admin"`).
- [ ] **Fixes auth récents déployés** :
      - exemption `/two-factor` du proxy (sinon boucle de login infinie pour TOUT
        compte 2FA) ;
      - `DialogContent` garde le Dialog ouvert quand on interagit avec un popup
        Base UI (sinon les dialogs à combobox se ferment en boucle).
- [ ] **2FA actif** sur chaque god user (le gate `/admin` est obligatoire) ; backup
      codes conservés.
- [ ] Gate vert : `bun run test:all` (959+ pass), `bunx tsc --noEmit` (0).

---

## Pass A — Lecture seule (sans risque)

### 1. Gate & séparation
- [ ] 1.1 `/admin` → shell **dark/red « GOD MODE »**, sidebar dédiée (Overview,
      Users, Organizations, Billing, Audit, Export & Metrics), en-tête = email +
      **« Exit to app »**. Ce n'est PAS la sidebar client.
- [ ] 1.2 **Exit to app** → retour app cliente, puis re-`/admin`.
- [ ] 1.3 Compte **non super-admin** sur `/admin` → **404** (pas de redirection
      révélatrice).
- [ ] 1.4 Super-admin **sans 2FA** → interstitiel « 2FA required » (pas le
      dashboard), lien vers `/settings/account`.

### 2. Overview (`/admin`)
- [ ] 2.1 KPI réels : total users, banned, organizations, active subscriptions,
      orgs in trial.
- [ ] 2.2 Bloc « Recent admin actions » (10 dernières entrées d'audit).

### 3. Users (`/admin/users`)
- [ ] 3.1 Table (nom+email, rôle, statut, actions).
- [ ] 3.2 Recherche par email → filtre.
- [ ] 3.3 Filtre rôle (all/admin/user) + statut (all/active/banned).
- [ ] 3.4 Ligne / « Manage » → détail `/admin/users/[id]` : identité, badges
      email vérifié / rôle / 2FA, username, org memberships, sessions actives.

### 4. Organizations (`/admin/orgs`)
- [ ] 4.1 Table tenants : nom (lien), slug, nb membres, badge billing + plan,
      fin trial, créée.
- [ ] 4.2 Tri (created/members/name) + recherche.
- [ ] 4.3 Détail org : identité (slug, created, Stripe customer), Members,
      Limits (Plan vs Effective), Subscription summary, panel Stripe.

### 5. Billing (`/admin/billing`)
- [ ] 5.1 KPI : subs par statut + **MRR « estimate »** (libellé explicite).
- [ ] 5.2 Table : org → customerId → plan/statut → period end → trial ; filtre
      statut + recherche ; lien détail org.

### 6. Audit (`/admin/audit`)
- [ ] 6.1 Barre de filtres (email acteur, action contient, type cible, dates
      since/until) + pagination.
- [ ] 6.2 Colonnes : heure, acteur, action, cible, IP.

### 7. Export & Metrics (`/admin/export`)
- [ ] 7.1 Bloc métriques (churn proxy, adoption) marqué « estimates ».
- [ ] 7.2 `users.csv` → `users-AAAA-MM-JJ.csv` téléchargé, en-têtes cohérents.
- [ ] 7.3 `organizations.json`, `subscriptions.csv`, `audit.json` → OK.
- [ ] 7.4 **Sécurité** : `/admin/export/users?format=csv` en non-connecté → **403**.

---

## Pass B — Mutations ⚠️ (sur une cible JETABLE : user/org de test, jamais un vrai compte)

> Après CHAQUE action → `/admin/audit` doit montrer l'entrée (acteur = toi,
> bonne action, bonne cible). C'est le signal de succès.

### 8. Actions utilisateur (user de test)
- [ ] 8.1 **Suspendre** (raison + durée 24h) → statut suspendu + raison/expiry. `user.ban`
- [ ] 8.2 **Lever le ban** → actif. `user.unban`
- [ ] 8.3 **Edit email** (+ mark verified) → email + badge à jour. `user.update_email`
- [ ] 8.4 **Force-verify** (user non vérifié) → badge vérifié. `user.force_verify`
- [ ] 8.5 **Reset 2FA** (user avec 2FA) → badge 2FA disparaît. `user.reset_2fa`
- [ ] 8.6 **Revoke all sessions** → table sessions vidée. `user.revoke_sessions`
- [ ] 8.7 ⚠️ **Impersonate** (user non-admin) → bascule + **bandeau orange** →
      **Stop** → retour sur `/admin/users`. `user.impersonate`.
      Vérifier : bouton **caché** sur un admin/super-admin.

### 9. Organisation (org de test)
- [ ] 9.1 **Add member** (email user existant + rôle staff) → ajouté. `org.add_member`
      (email inconnu → erreur ; déjà membre → erreur ; owner non proposé).
- [ ] 9.2 **Changer rôle** (staff↔admin). `org.set_member_role`
- [ ] 9.3 **Make owner** (confirm) → ancien owner→admin, nouveau→owner. `org.transfer_owner`
- [ ] 9.4 **Remove** membre non-owner (confirm) ; **sole owner → refusé**. `org.remove_member`
- [ ] 9.5 **Override limites** (ex. `seats=25` + expiry) → colonne Effective change
      (badge « overridden ») `org.set_limit_override` ; **Clear** → retour plan
      `org.clear_limit_override`.

### 10. Stripe (panel détail org) — si Stripe configuré (sinon boutons grisés = attendu)
- [ ] 10.1 **Extend trial** (+30j) → `trialEndsAt` repoussé. `billing.extend_trial` (app-level, sûr)
- [ ] 10.2 **Grant complimentary** (plan + date + note) → trial + override. `billing.grant_comp`
- [ ] 10.3 ⚠️ **Resync** (confirm) → sub locale re-sync depuis Stripe. `billing.resync`
- [ ] 10.4 ⚠️ **Apply coupon** (ID coupon de test) → effet Stripe réel. `billing.apply_coupon`

### 11. Audit & Export (clôture)
- [ ] 11.1 `/admin/audit` : toutes les actions Pass B listées ; un filtre
      (type=user ou ton email) réduit la liste.
- [ ] 11.2 `/admin/export/audit?format=csv` → contient les actions.

---

## Notes
- Les actions sensibles re-vérifient **super-admin + 2FA** côté serveur
  (`assertSuperAdminWith2FA`) et refusent les cibles privilégiées (admins/
  super-admins) sur les ops destructives — à confirmer en testant un admin comme
  cible (doit échouer proprement).
- L'audit log est fail-soft : une action réussit même si l'écriture d'audit
  échoue (vérifier néanmoins que les entrées apparaissent).
- Quotas : un override actif change `getOrgQuotaLimits` immédiatement ; un override
  **expiré** est ignoré (vérifiable via une date d'expiry passée).
