Dashboard admin
Vue d'ensemble admin, stats live, sections et impersonation.
Le dashboard admin vit sous /admin. Accès gardé par
role === "ADMIN" || role === "MODERATOR" dans le layout
(app/[locale]/(dashboard)/layout.tsx).
Navigation : les ADMIN et MODERATOR arrivent par défaut sur l'espace utilisateur
/account(UserShell). Le panneau Administration (slide-in dans la sidebar user) donne accès aux sections admin sans quitter l'espace personnel. Naviguer vers/admincharge le DashboardShell complet.Voir Rôles & permissions pour la matrice complète des accès ADMIN / MODERATOR.
Stats live
Calculées par lib/dashboard-stats.ts, cache unstable_cache 60s :
| Stat | Source |
|---|---|
| Total users | prisma.user.count() |
| Inscriptions 30j | Comparé aux 30j précédents (delta %) |
| Sessions actives | UserSession.lastActiveAt dans les 30 dernières min |
| Abonnés payants | Subscription.status ∈ ["active", "trialing"] |
Le delta de signups est rendu en vert (positif) ou rouge (négatif) avec flèche. Si pas de données pour la période précédente, le delta est masqué.
Sections
/admin — Home
Stats + Activité récente — feed paginé (DataList) des 3 types d'événements :
| Type | Source | Affichage |
|---|---|---|
subscription | AuditLog action subscription.created | badge émeraude CreditCard |
credit_purchase | CreditTransaction raison credit_pack_purchase | badge bleu ShoppingCart + montant crédits |
credit_spend | CreditTransaction négative (hors admin) | badge ambré Zap + montant crédits |
API : GET /api/admin/dashboard/activity?cursor=... — fenêtre 30 jours,
15 items par page, pagination cursor ISO date. Guard requireApiAuth({ moderator: true }).
/admin/users
Liste DataList avec search + filtres role (USER/ADMIN) et status (active/blocked/locked).
Click sur une row → sheet 5 onglets :
- Info — métadonnées + tags (édition inline)
- Notes — notes admin internes
- Emails — 50 derniers envois pour cet user
- Historique — login history
- Actions — block/unblock/revoke/unlock/export RGPD
Voir Gestion des utilisateurs pour le détail.
Bulk API disponible (POST /api/admin/users/bulk) pour les actions
en masse — pas encore en UI multi-select.
/admin/audit
Liste DataList des AuditLog. Voir Audit log.
/admin/emails
Éditeur des templates emails. Voir Emails.
/admin/emails/logs
Tracking des envois (statut Resend, bounces, opens). Voir Email logs.
/admin/plans
CRUD plans tarifaires multi-langue. Voir Plans.
/admin/coupons
CRUD coupons. Voir Coupons.
/admin/billing
KPI MRR/ARR/churn + liste des subs avec actions (refund, comp days, cancel). Voir Facturation.
/admin/sessions
Sessions actives globales avec révocation par filtre / par session. Voir Sessions globales.
/admin/feature-flags
Création + toggle + rollout % par flag. Voir Feature flags.
/admin/system
Health checks externes (DB / Stripe / Resend / OneSignal) + métriques 24h. Voir Santé système.
/admin/announcements
Bannière site-wide + mode maintenance. Voir Annonces & maintenance.
/admin/settings
Tabs admin :
- Site — appName, appUrl, supportEmail, logo
- Theme — palette, dark/light defaults
/admin/jobs
Visualisation des jobs Trigger.dev (si module activé).
Impersonation
Action Impersonate sur un user → POST /api/admin/impersonate.
Effets :
User.impersonatedBy = adminIdsur la cible- La session admin est swap :
session.user.id = targetUserId - Audit
user.impersonate(qui par qui)
Un bandeau jaune <ImpersonationBanner> s'affiche en haut de toute page,
avec un bouton "Quitter l'impersonation" qui restaure la session admin.
Tant que impersonatedBy est rempli, le bandeau reste.
Geo-IP enrichment
Les pages /users et /audit affichent country / city quand dispo,
récupérés via lib/geoip.ts au login (stockés dans UserSession).
Sessions tracking
UserSession log : userAgent, ip, country, city, lastActiveAt.
Mis à jour par le proxy à chaque requête authentifiée. Listée dans
/account/settings onglet Sécurité (côté user) et utilisée pour les
stats sessions actives (côté admin).
Allez plus loin
- Audit log — actions trackées
- DataList — composant utilisé partout
- Compte utilisateur — équivalent côté user