Administration

Référence technique du domaine Administration — console super-admin, paramètres applicatifs, gestion des organisations, webhooks sortants, audit log et supervision.

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.

La console super-admin (/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

TermeEntitéDéfinition
Super-admin PulseMembre de l'équipe Pulse Group exploitant la plateforme.
OrganisationOrganizationTenant (client, bailleur ou partenaire) ; isolation complète des données.
Application SettingApplicationSettingParamètre global clé/valeur (chiffré si préfixe secret:).
Organization SettingOrganizationSettingParamètre propre à un tenant (marge par défaut, numérotation custom…).
Release NoteReleaseNoteNotice de version exposée aux utilisateurs à la prochaine connexion.
WebhookWebhookURL HTTPS externe déclenchée sur événement métier.
Webhook DeliveryWebhookDeliveryTentative 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/*)

ÉcranRouteContenu
Dashboard/adminStats globales (orgs actives, MAU, volume API, DB, stockage), courbe MAU 12 mois, alertes système.
Organisations/admin/organizationsDataTable : 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/usersTous 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-notesCRUD + publication, audience (ALL / INTERNAL / BETA), KPI d'accusé de lecture.
Webhooks/admin/webhooksListe + création + historique des livraisons, action Resend.
Audit log global/admin/auditCross-org, filtres acteur/action/target/période, export CSV/JSON.
Supervision/admin/supervisionQueues, 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/*)

OngletContenu
GénéralOrganizationSetting éditables par l'admin de l'org.
IntégrationsWebhooks sortants de l'org, lien vers /admin/webhooks.

Modèle de données (points clés)

  • ApplicationSetting.value est JSON ; les secrets sont chiffrés au repos (préfixe clé secret:).
  • ReleaseNoteReleaseNoteAcknowledgement (table de liaison user/release) : la modale "Nouveautés" est masquée dès qu'un ack existe.
  • Webhook.secret est rotatable avec une période de grâce de 7 jours (dual-sign : ancien et nouveau secret acceptés pendant la transition).
  • WebhookDelivery.status : PENDINGDELIVERED | FAILED (retry exponentiel, 10 tentatives max).
  • Organization.status : ACTIVESUSPENDEDARCHIVED (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éthodeRoutePermission
GET/api/admin/dashboardadmin.org:read
GET/api/admin/organizationsadmin.org:read
POST/api/admin/organizationsadmin.org:create
GET/api/admin/organizations/[id]admin.org:read
PATCH/api/admin/organizations/[id]admin.org:update
POST/api/admin/organizations/[id]/suspendadmin.org:suspend
POST/api/admin/organizations/[id]/archiveadmin.org:suspend
POST/api/admin/organizations/[id]/exportadmin.org:read
GET/api/admin/usersidentity.user:read
POST/api/admin/users/[id]/impersonateidentity.user:impersonate
GET/api/admin/settingsadmin.settings:read
PATCH/api/admin/settingsadmin.settings:update
GET/api/admin/release-notes(authentifié)
POST/api/admin/release-notesadmin.release_notes:manage
POST/api/admin/release-notes/[id]/publishadmin.release_notes:manage
POST/api/account/release-notes/[id]/acknowledge(authentifié)
GET / POST/api/admin/webhooksadmin.webhooks:manage
PATCH / DELETE/api/admin/webhooks/[id]admin.webhooks:manage
GET/api/admin/webhooks/[id]/deliveriesadmin.webhooks:manage
POST/api/admin/webhooks/deliveries/[id]/resendadmin.webhooks:manage
GET/api/admin/auditadmin.audit:read
GET/api/admin/supervisionadmin.audit:read
GET / POST/api/admin/banneradmin.settings:update (POST)
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)

reason
string required
Motif de suspension (affiché dans l'audit log et notifié à l'admin de l'org).

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_PROVIDER actif en permanence (verrou DB).
  • Création d'org réservée à SUPERADMIN_PROVIDER.
  • Impersonation toujours auditée (impersonatorUserId dans 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).
  • ApplicationSetting contenant un secret → préfixe secret: → 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.