Console Super-Admin (plateforme)
Console d'administration plateforme — distincte du back-office d'une institution. Elle sert à gérer l'ensemble des tenants (institutions) hébergés sur Kairos MFI.
Accès
- URL :
https://app.kairos-mfi.com/super-admin/login - Authentification : compte
SuperAdmin(email + mot de passe, 2FA TOTP optionnel), totalement séparé des comptes back-office des tenants. - Fallback pour scripts / CI : header
x-super-admin-key(variableSUPER_ADMIN_KEY).
Le super-admin n'est rattaché à aucun tenant (pas de tenantId dans son
JWT, type: 'super-admin').
Créer le premier super-admin
Les tables vivent dans le schéma public (SuperAdmin,
SuperAdminAuditLog). Si elles n'existent pas encore, appliquer
migrations/2026-06-24-super-admin-tables.sql.
Créer le compte (sur le VPS) :
# 1. Générer le hash bcrypt (chemin pnpm du module bcryptjs)
docker compose -f docker-compose.prod.yml --env-file .env.prod exec api \
node -e "console.log(require('/app/node_modules/.pnpm/bcryptjs@2.4.3/node_modules/bcryptjs').hashSync('MonMotDePasse', 12))"
# 2. Insérer via un FICHIER (⚠️ ne PAS passer le hash en argument bash :
# les $ du hash bcrypt seraient interprétés comme des variables shell).
cat > /tmp/sa.sql <<'SQL'
INSERT INTO public."SuperAdmin"
(id, email, "passwordHash", "firstName", "lastName", "isActive", "createdAt", "updatedAt")
VALUES
(gen_random_uuid()::text, 'admin@kairos-mfi.com', 'COLLER_LE_HASH', 'Super', 'Admin', true, now(), now());
SQL
docker compose -f docker-compose.prod.yml --env-file .env.prod exec -T postgres \
psql -U kairos -d kairos_mfi < /tmp/sa.sql
rm /tmp/sa.sql
Piège classique : ne jamais mettre un hash bcrypt (
$2a$12$...) directement dans une commandepsql -c "..."entre guillemets doubles. Bash interprète$2a,$12,$5comme des variables et corrompt le hash. Toujours passer par un heredoc quoté (<<'SQL') ou un fichier.
Fonctionnalités
Tenants
- Liste des institutions avec compteurs (membres, comptes, prêts).
- Fiche tenant : infos, plan (STARTER / PROFESSIONAL / ENTERPRISE), statut actif/inactif, usage (membres, comptes, prêts, SMS, stockage).
- Provisionner une nouvelle institution (clone du schéma template + directeur initial).
- Activer / désactiver / supprimer un tenant (suppression avec confirmation par le slug).
Gestion des comptes utilisateurs d'un tenant
Sur la fiche tenant, section Back-office accounts :
| Action | Endpoint | Effet |
|---|---|---|
| Lister | GET /v1/super-admin/tenants/:id/users |
Users back-office du tenant (rôle, statut, 2FA, dernière connexion) |
| Reset mdp | POST .../users/:userId/reset-password |
Génère un mdp temporaire 10 car., force mustChangePassword, le retourne une fois |
| Activer/désactiver | POST .../users/:userId/set-active |
{ isActive }. Refuse de désactiver le dernier DIRECTOR actif |
| Désactiver 2FA | POST .../users/:userId/disable-2fa |
Lève le TOTP (dépannage perte de device) |
Toutes ces actions sont auditées dans SuperAdminAuditLog avec
l'id du super-admin, l'action, le tenant ciblé et l'ip.
Techniquement : le super-admin résout le tenant → son schéma Postgres,
puis obtient un PrismaClient scopé via TenantPrismaService.forTenant()
(cf. super-admin-tenant-ops.service.ts).
Feature flags par tenant
Sur la fiche tenant, section Features : des toggles activent / désactivent par institution :
| Feature | Clé | Effet si désactivé |
|---|---|---|
| Mobile Money | mobile_money |
/v1/mobile-money/* → 403 |
| Reporting réglementaire | regulatory |
/v1/regulatory/* → 403 |
| Portail membre | member_portal |
(UI back-office masquée — cf. note) |
| Agent terrain | field_agent |
/v1/field-agent/* → 403 |
| Webhooks sortants | webhooks |
/v1/webhooks/* → 403 |
Stockage : colonne Tenant.features (JSONB). null ou clé absente =
activé (rétro-compat). Seul false désactive.
Enforcement : décorateur @RequiresFeature('...') sur les controllers
concernés + FeatureGuard global qui lit req.tenant.features
(posé par le TenantMiddleware). Après un changement, le cache du
TenantService est invalidé → effet immédiat.
Note portail membre : les routes
/v1/portal/*sont bypassées par le TenantMiddleware (le tenant est résolu depuis le JWT membre, pasreq.tenant). Le flagmember_portalgate donc l'UI et la visibilité, mais l'enforcement backend strict des routes portail nécessitera un hook dédié dans une itération ultérieure.
Endpoints :
GET /v1/super-admin/tenants/:id/features→{ catalog, features }PATCH /v1/super-admin/tenants/:id/features→ merge{ key: boolean }
Monitoring & incidents (/super-admin/monitoring)
Vue plateforme de la santé et des incidents, toutes institutions confondues :
- Infra : latence DB.
- Tableau par institution : users actifs / total, dernière connexion (max sur les users du tenant), nb d'événements d'audit sur 7 jours, nb de notifications échouées sur 7 jours.
- Rafraîchissement auto toutes les 60 s.
Sur la fiche tenant, carte Activity & incidents :
- Notifications en échec (canal, template, destinataire, message d'erreur, date) — le vrai signal « incident ».
- 25 derniers événements d'audit du tenant (action, entité, date).
Endpoints :
GET /v1/super-admin/monitoring/health→{ infra, tenants[], generatedAt }GET /v1/super-admin/tenants/:id/activity→{ tenant, recentAudit[], recentFailedNotifications[] }
Implémentation : agrégation cross-schéma via $queryRawUnsafe, chaque
requête protégée par try/catch (un schéma absent ne casse pas la vue),
cache mémoire 30 s. Pour les erreurs applicatives détaillées (stack
traces), la source de vérité reste Sentry (API + Web).
Audit log super-admin
GET /v1/super-admin/audit — journal de toutes les opérations plateforme
(login, création tenant, activation/désactivation, reset mdp user, etc.).
Sécurité
- 2FA fortement recommandé sur les comptes super-admin (option dans Profil → 2FA setup).
- Le mot de passe super-admin doit être unique (ne pas réutiliser celui d'un compte back-office ou du SMTP).
- La clé statique
SUPER_ADMIN_KEYest un secret : à faire tourner avant chaque mise en production et à ne jamais commiter.
À venir
- Feature flags par tenant — activer/désactiver Mobile Money, reporting réglementaire, portail membre, app agent par institution.
- Incidents & logs centralisés — santé par tenant, dernières connexions, audit cross-tenant, intégration Sentry.