console-admin
À quoi sert cette brique
Section intitulée « À quoi sert cette brique »console-admin est le back-office interne de Titreo E-Pay — l’outil d’administration utilisé par les équipes Titreo (pas par les marchands). Elle répond à une question simple : comment crée-t-on et administre-t-on les marchands de la plateforme sans toucher à la base de données à la main ?
Elle couvre cinq responsabilités, toutes de scope admin :
| Responsabilité | Détail |
|---|---|
| Marchands | Créer, lister, éditer (nom, webhook, TTL de session), activer/désactiver un marchand |
| Clés API | Émettre et révoquer les clés API d’un marchand (scopes restreints, jamais admin) |
| Configs PSP | Consulter et supprimer les configs PSP d’un marchand (en lecture surtout : ces clés sont saisies par le marchand depuis sa propre console) |
| Audit | Lire les journaux d’audit, globalement ou filtrés par marchand |
| Admins Titreo | Lister et créer les comptes admin qui ont accès à cette console |
À ne pas confondre avec console-merchant : celle-ci est destinée au marchand pour gérer ses clés et ses PSP ; console-admin est l’outil interne qui voit tous les marchands.
flowchart LR A["Équipe Titreo (navigateur)"] --> B["console-admin (Next.js, port 3400)"] B -->|"server actions / RSC, cookie tep_session"| C["API E-Pay (port 3000)"] C --> D["Firebird"] E["Marchand"] -.->|"sa propre console"| F["console-merchant"] F --> C
Stack et démarrage
Section intitulée « Stack et démarrage »D’après console-admin/package.json :
- Next.js 15 (App Router) + React 19
- Zod pour valider les entrées de formulaires côté serveur
- Tailwind CSS (config
console-admin/tailwind.config.ts, tokens dansconsole-admin/app/tokens.css) - Biome pour le lint/format
- Pas de base de données ni d’ORM ici : la console est sans état, tout passe par l’API.
Scripts npm réels (package.json) :
| Script | Effet |
|---|---|
dev |
next dev -p 3400 |
build |
next build |
start |
next start -p 3400 |
typecheck |
tsc --noEmit |
lint / lint:fix |
biome check . / biome check --write . |
La console tourne sur le port 3400. Une seule variable d’environnement compte (console-admin/.env.example) :
# URL de l'API E-Pay (appels server-side uniquement)TITREO_API_BASE_URL=http://localhost:3000NODE_ENV=developmentElle est lue à un seul endroit, console-admin/lib/config.ts :
export const config = { apiBaseUrl: process.env.TITREO_API_BASE_URL ?? 'http://localhost:3000',}Un Dockerfile multi-étapes (deps → builder → runner) existe à la racine de la brique et expose le port 3400. Voir aussi l’environnement de dev local.
Structure des routes
Section intitulée « Structure des routes »L’arborescence App Router (console-admin/app/) est organisée autour d’un groupe (authed) protégé par le middleware :
app/ page.tsx -> redirige vers /merchants login/page.tsx -> formulaire de connexion (authed)/ layout.tsx -> requireAdmin() + Sidebar merchants/ page.tsx -> liste des marchands (+ filtre actif/en attente) new/page.tsx -> création d'un marchand [id]/ page.tsx -> aperçu + édition du marchand api-keys/page.tsx -> clés API du marchand (+ create-form) psp-configs/page.tsx -> configs PSP du marchand (lecture + suppression) audit-logs/page.tsx -> journaux d'audit du marchand admin-users/ page.tsx -> liste des admins Titreo new/page.tsx -> création d'un admin (+ form) settings/page.tsx -> compte admin courant + déconnexionLa navigation latérale (console-admin/components/Sidebar.tsx) n’expose que trois entrées : Marchands, Admins Titreo, Paramètres. Les écrans par marchand (PSP configs, API keys, audit) sont atteints via des onglets (console-admin/components/MerchantTabs.tsx), pas depuis la sidebar.
Comment la console parle à l’API
Section intitulée « Comment la console parle à l’API »Toute la logique réseau est centralisée dans console-admin/lib/api.ts. Les pages sont des Server Components et les mutations des server actions ('use server') ; le navigateur ne contacte jamais l’API directement.
sequenceDiagram
participant U as "Navigateur"
participant C as "console-admin (server)"
participant A as "API E-Pay (3000)"
U->>C: "POST login (server action)"
C->>A: "POST /v1/auth/admin/login"
A-->>C: "Set-Cookie: tep_session=..."
C-->>U: "cookie httpOnly tep_session + redirect /merchants"
U->>C: "GET /merchants"
C->>A: "GET /v1/admin/merchants (Cookie: tep_session)"
A-->>C: "{ data, nextCursor, hasMore }"
C-->>U: "HTML rendu (RSC)"
Authentification
Section intitulée « Authentification »Le flux complet de session (console-admin/lib/actions/auth.ts + console-admin/lib/auth.ts) :
loginActionposte les identifiants surPOST /v1/auth/admin/login.- L’API renvoie un cookie
tep_session; la console le ré-émet côté serveur en cookiehttpOnly,sameSite: 'strict',secure: true. - À chaque rendu,
getCurrentUser()appelleGET /v1/auth/meet exigekind === 'admin'(requireAdmin()redirige sinon vers/login). logoutActionappellePOST /v1/auth/logoutet supprime le cookie.
Le cookie est le credential bearer de l’API : console-admin/lib/api.ts le réinjecte dans l’en-tête Cookie de chaque appel sortant.
Endpoints admin visés
Section intitulée « Endpoints admin visés »Tous les appels sont concentrés dans console-admin/lib/actions/*.ts. Les routes consommées (vérifiées présentes côté api/src/http/routes/) :
| Server action (fichier) | Méthode + endpoint API |
|---|---|
auth.ts |
POST /v1/auth/admin/login, POST /v1/auth/logout, GET /v1/auth/me |
merchants.ts |
GET/POST /v1/admin/merchants, GET/PATCH /v1/admin/merchants/{id} |
api-keys.ts |
GET/POST /v1/admin/merchants/{id}/api-keys, DELETE …/api-keys/{keyId} |
psp-configs.ts |
GET /v1/admin/merchants/{id}/psp-configs, DELETE …/psp-configs/{provider} |
audit-logs.ts |
GET /v1/audit-logs (filtres merchantId, action, limit, cursor) |
admin-users.ts |
GET/POST /v1/admin/users |
Le préfixe /v1/admin/ côté API porte les opérations réservées à l’administration. Le contrat de réponse en cas d’erreur ({ code, message }) est mappé sur ApiHttpError dans lib/api.ts puis affiché dans les formulaires. Voir les contrats inter-briques pour la forme exacte des enveloppes.
Sécurité
Section intitulée « Sécurité »Deux protections explicites valent d’être notées (détails dans Sécurité) :
- CSP par nonce (
console-admin/middleware.ts) :Content-Security-Policyconstruite par requête avec un nonce surscript-srcet'strict-dynamic'. Le middleware redirige aussi vers/logintoute route non publique sans cookietep_session. La politique part enReport-Only(basculerCSP_REPORT_ONLY=falsepour l’appliquer). - Scopes de clés API verrouillés (
console-admin/lib/actions/api-keys.ts) : la liste autorisée énumère explicitement six scopes (sessions:read,sessions:write,psp:read,psp:write,webhooks:read,webhooks:write) et exclut volontairement tout scopeadmin, pour qu’une clé liée à un marchand ne puisse jamais être tout-accès.
Pour aller plus loin
Section intitulée « Pour aller plus loin »- console-merchant — la console jumelle côté marchand
- Backend — l’API qui sert les endpoints
/v1/admin/* - Vue d’ensemble de l’écosystème — où se place cette brique