Couche API
Backend : NestJS + PostgreSQL, déployé en dev sur
https://dev.sim.strife-cyber.org (spec OpenAPI live à /docs-json). Le
frontend est client-only : tout appel part de src/core/api.
npm run api:gentélécharge la spec et génèresrc/core/api/generated/schema.ts(openapi-typescript). Les types de requête (DTO, snake_case) en sont importés — jamais dupliqués.- La spec ne déclare pas les schémas de réponse (sauf health) ni
l’enveloppe d’erreur : ces types sont déclarés à la main dans
src/core/api/types.ts(source : observations du backend réel, à revalider au smoke test / aux tests d’intégration). createApiClient({ getAccessToken, refresh, onSessionExpired })(construit parcore/auth/session.ts) exposeapiFetch<T>(path, options).
Wrapper HTTP (apiFetch)
Section intitulée « Wrapper HTTP (apiFetch) »- Base URL depuis
VITE_API_URL(défaut/api/v1, même origine). En dev, le proxy duvite.config.tsrelaie/api/*vers le backend (https://dev.sim.strife-cyber.org) — le CORS de ce backend refuselocalhost:*, un appel direct depuis le navigateur serait bloqué. - JSON en entrée/sortie ; en-tête
Authorization: Bearer <accessToken>ajouté sauf surNO_AUTH_PATHS(/auth/login,/auth/refreshet les deux chemins publics de réinitialisation :/auth/mot-de-passe-oublie,/auth/reinitialiser-mot-de-passe). - Timeout
AbortControllerde 15 s. - Réponse HTTP : l’enveloppe
{success, code, message, details?, requestId?, path?, timestamp?}est dépaquetée enApiError(status,code,details, …). - 401 → refresh single-flight → rejoue la requête une fois → en cas
d’échec
onSessionExpired()(purge session). - Les tokens ne sont jamais loggés.
Particularité de la spec à connaître
Section intitulée « Particularité de la spec à connaître »La spec déclare POST /auth/login (et /auth/refresh) comme protégés par
JWT — un artefact du backend. Le wrapper n’attache donc jamais de bearer
sur ces chemins. mot-de-passe-oublie et reinitialiser-mot-de-passe sont
eux de vraies routes publiques (utilisées sans session : lien « Mot de passe
oublié ? » de la page login, et bouton « Modifier mon mot de passe » des
pages « Mon compte » des portails) — même traitement : ni bearer, ni
refresh/retry sur 401.
Filtres required erronés
Section intitulée « Filtres required erronés »Certains endpoints listent des paramètres de requête required à tort
(ex. residence/logements, client/clients, audit/journal). Sans impact
sur la fondation ; à traiter feature par feature lors de l’implémentation
des modules.
Erreurs (ApiError)
Section intitulée « Erreurs (ApiError) »try { await authApi.login(dto)} catch (error) { const apiError = toApiError(error) getErrorMessageForCode(apiError.code) // code → message français (core/api/error-messages.ts) getFieldErrors(error) // details[].property → erreurs de formulaire}À ne pas faire
Section intitulée « À ne pas faire »- ❌
fetch()brut hors decore/api/http.ts. - ❌ Dupliquer un DTO du schéma généré.
- ❌ Attacher le bearer sur
/auth/loginou/auth/refresh. - ❌ Logger des tokens ou des corps de réponse sensibles.
