Administration
Administration
Périmètre : console super-admin Pulse (gestion multi-tenant des organisations clientes), paramètres applicatifs globaux et par organisation, release notes, webhooks sortants, impersonation, audit log cross-org et supervision temps réel. Ce domaine est strictement réservé à l'équipe Pulse Group ; aucun utilisateur d'organisation cliente n'y a accès.
/admin/*) affiche un banner rouge persistant et exige
un MFA récent (< 24 h) pour toute action destructive. Routes API sous
/api/admin/*. Source de cette page : docs/16-domain-admin.md.Vocabulaire & entités
| Terme | Entité | Définition |
|---|---|---|
| Super-admin Pulse | — | Membre de l'équipe Pulse Group exploitant la plateforme. |
| Organisation | Organization | Tenant (client, bailleur ou partenaire) ; isolation complète des données. |
| Application Setting | ApplicationSetting | Paramètre global clé/valeur (chiffré si préfixe secret:). |
| Organization Setting | OrganizationSetting | Paramètre propre à un tenant (marge par défaut, numérotation custom…). |
| Release Note | ReleaseNote | Notice de version exposée aux utilisateurs à la prochaine connexion. |
| Webhook | Webhook | URL HTTPS externe déclenchée sur événement métier. |
| Webhook Delivery | WebhookDelivery | Tentative d'envoi d'un webhook (statut, retry, payload). |
La structure complète est dans
docs/04-data-model.md§14.
Écrans
Console super-admin (/admin/*)
| Écran | Route | Contenu |
|---|---|---|
| Dashboard | /admin | Stats globales (orgs actives, MAU, volume API, DB, stockage), courbe MAU 12 mois, alertes système. |
| Organisations | /admin/organizations | DataTable : nom, slug, SIREN, plan, statut, membres, assets, contrats actifs. |
| Fiche organisation | /admin/organizations/[id] | Onglets : Synthèse, Membres, Paramètres, Quotas, Webhooks, Audit, Actions. |
| Utilisateurs globaux | /admin/users | Tous les users cross-org, suspension, reset password, impersonation. |
| Paramètres applicatifs | /admin/settings | Édition des ApplicationSetting par section (intégrations, métier, email, stockage, sécurité, conformité). |
| Release Notes | /admin/release-notes | CRUD + publication, audience (ALL / INTERNAL / BETA), KPI d'accusé de lecture. |
| Webhooks | /admin/webhooks | Liste + création + historique des livraisons, action Resend. |
| Audit log global | /admin/audit | Cross-org, filtres acteur/action/target/période, export CSV/JSON. |
| Supervision | /admin/supervision | Queues, sessions DB, latence HTTP P95, replay/vider jobs, lien Grafana/Loki. |
| Banner global | — (API) | Message affiché sur toutes les pages, audience configurable. |
Paramètres workspace (/workspace/admin/settings/*)
| Onglet | Contenu |
|---|---|
| Général | OrganizationSetting éditables par l'admin de l'org. |
| Intégrations | Webhooks sortants de l'org, lien vers /admin/webhooks. |
Modèle de données (points clés)
ApplicationSetting.valueest JSON ; les secrets sont chiffrés au repos (préfixe clésecret:).ReleaseNote→ReleaseNoteAcknowledgement(table de liaison user/release) : la modale "Nouveautés" est masquée dès qu'unackexiste.Webhook.secretest rotatable avec une période de grâce de 7 jours (dual-sign : ancien et nouveau secret acceptés pendant la transition).WebhookDelivery.status:PENDING→DELIVERED|FAILED(retry exponentiel, 10 tentatives max).Organization.status:ACTIVE→SUSPENDED→ARCHIVED(irréversible après la période de grâce de 90 j).
API
Toutes les routes /api/admin/* exigent le rôle SUPERADMIN_PROVIDER.
| Méthode | Route | Permission |
|---|---|---|
GET | /api/admin/dashboard | admin.org:read |
GET | /api/admin/organizations | admin.org:read |
POST | /api/admin/organizations | admin.org:create |
GET | /api/admin/organizations/[id] | admin.org:read |
PATCH | /api/admin/organizations/[id] | admin.org:update |
POST | /api/admin/organizations/[id]/suspend | admin.org:suspend |
POST | /api/admin/organizations/[id]/archive | admin.org:suspend |
POST | /api/admin/organizations/[id]/export | admin.org:read |
GET | /api/admin/users | identity.user:read |
POST | /api/admin/users/[id]/impersonate | identity.user:impersonate |
GET | /api/admin/settings | admin.settings:read |
PATCH | /api/admin/settings | admin.settings:update |
GET | /api/admin/release-notes | (authentifié) |
POST | /api/admin/release-notes | admin.release_notes:manage |
POST | /api/admin/release-notes/[id]/publish | admin.release_notes:manage |
POST | /api/account/release-notes/[id]/acknowledge | (authentifié) |
GET / POST | /api/admin/webhooks | admin.webhooks:manage |
PATCH / DELETE | /api/admin/webhooks/[id] | admin.webhooks:manage |
GET | /api/admin/webhooks/[id]/deliveries | admin.webhooks:manage |
POST | /api/admin/webhooks/deliveries/[id]/resend | admin.webhooks:manage |
GET | /api/admin/audit | admin.audit:read |
GET | /api/admin/supervision | admin.audit:read |
GET / POST | /api/admin/banner | admin.settings:update (POST) |
/api/admin/organizations/[id]/suspendAuth Suspend une organisation : invalide toutes les sessions actives, refuse les connexions ultérieures et conserve les données en lecture seule.
Corps (JSON)
Requête
curl -s -X POST "$API/api/admin/organizations/$ORG_ID/suspend" \
-H "Content-Type: application/json" -H "Cookie: $SESSION" \
-d '{"reason":"Impayés — suspension préventive"}'
Réponse
{ "id": "org_…", "status": "SUSPENDED", "suspendedAt": "2026-06-16T09:00:00Z" }
Workflows
Suspension d'organisation
ACTIVE
└──→ SUSPENDED (raison obligatoire + double confirmation)
├─ sessions membres invalidées
├─ login refusé (page dédiée)
├─ API rejette toutes requêtes sauf endpoints admin
├─ audit log + notification email admin org + super-admin
└──→ ARCHIVED après 90 j de grâce (irréversible)
├─ tables purgées (sauf audit, factures, contrats — obligation légale)
└─ zip JSON archivé S3 (10 ans)
Webhooks sortants
Événement métier (ex : lease.contract.signed)
└──→ webhooks.service.dispatch(event, payload)
└──→ pour chaque Webhook souscrit
├─ crée WebhookDelivery (PENDING)
└─ job send-webhook-deliveries (toutes les 30 s)
├─ charge 50 deliveries PENDING
├─ signe body HMAC
├─ POST → si 2xx → DELIVERED
└─ sinon retry exponentiel (max 10) → FAILED + alerte
Format payload standard :
{
"event": "lease.contract.signed",
"deliveredAt": "2026-06-16T10:30:00Z",
"data": { "...": "..." },
"organizationId": "org_…",
"webhookId": "wh_…"
}
Headers envoyés :
X-Pulse-Event: lease.contract.signed
X-Pulse-Delivery: <delivery-id>
X-Pulse-Signature: t=<timestamp>,v1=<hex-hmac>
Release Notes
Création (draft) → Publication → Modal "Nouveautés" à la prochaine connexion
└──→ bouton "OK, lu" → ReleaseNoteAcknowledgement
└──→ KPI : % users ayant accusé réception
Backup & restauration
- Snapshot DB horaire (rétention 7 j), quotidien (rétention 30 j), PITR 7 j.
- Versioning S3 activé ; Object Lock sur buckets légaux.
- DR drill trimestriel documenté.
Règles métier
Séparation console vs workspace
/admin/* = exclusif SUPERADMIN_PROVIDER. Les admins d'organisation accèdent
uniquement à /workspace/admin/settings/* pour leurs OrganizationSetting.
Aucune route /api/admin/* n'est accessible depuis un contexte workspace.
Verrous de sécurité
- Au moins 1
SUPERADMIN_PROVIDERactif en permanence (verrou DB). - Création d'org réservée à
SUPERADMIN_PROVIDER. - Impersonation toujours auditée (
impersonatorUserIddans l'audit log), en lecture seule. - MFA récent (< 24 h) requis pour les actions destructives.
Webhooks
- URL de destination en HTTPS uniquement.
- Secret rotatable : dual-sign pendant 7 j (ancien + nouveau secret acceptés).
ApplicationSettingcontenant un secret → préfixesecret:→ chiffrement au repos automatique.
Cycle de vie organisation
- Suspension réversible pendant 90 j.
- Archivage = définitif (données légales conservées : audit, factures, contrats).
- Export données → ZIP via URL signée temporaire.