API layer
Backend: NestJS + PostgreSQL, deployed in dev at
https://dev.sim.strife-cyber.org (live OpenAPI spec at /docs-json). The
frontend is client-only: every call goes through src/core/api.
npm run api:gendownloads the spec and generatessrc/core/api/generated/schema.ts(openapi-typescript). Request types (DTOs, snake_case) are imported from it — never duplicated.- The spec declares no response schemas (except health) nor the error
envelope: those types are declared by hand in
src/core/api/types.ts(source: observations of the real backend, to revalidate via smoke / integration tests). createApiClient({ getAccessToken, refresh, onSessionExpired })(built bycore/auth/session.ts) exposesapiFetch<T>(path, options).
HTTP wrapper (apiFetch)
Section titled “HTTP wrapper (apiFetch)”- Base URL from
VITE_API_URL(default/api/v1, same origin). In dev, thevite.config.tsproxy relays/api/*to the backend (https://dev.sim.strife-cyber.org) — that backend’s CORS rejectslocalhost:*, so a direct browser call would be blocked. - JSON in/out;
Authorization: Bearer <accessToken>header added except onNO_AUTH_PATHS(/auth/login,/auth/refresh, and the two public password-reset paths:/auth/mot-de-passe-oublie,/auth/reinitialiser-mot-de-passe). - 15 s
AbortControllertimeout. - HTTP response: the
{success, code, message, details?, requestId?, path?, timestamp?}envelope is unwrapped into anApiError(status,code,details, …). - 401 → single-flight refresh → replays the request once → on failure
onSessionExpired()(session purge). - Tokens are never logged.
Spec quirk to know
Section titled “Spec quirk to know”The spec declares POST /auth/login (and /auth/refresh) as JWT-protected —
a backend artifact. The wrapper therefore never attaches a bearer on
those paths. mot-de-passe-oublie and reinitialiser-mot-de-passe are real
public routes (used without a session: the “Mot de passe oublié ?” link on
the login page, and the “Modifier mon mot de passe” button on the portals’
“Mon compte” pages) — same treatment: no bearer, no refresh/retry on 401.
Bogus required filters
Section titled “Bogus required filters”Some endpoints wrongly list required query parameters
(e.g. residence/logements, client/clients, audit/journal). No impact
on the foundation; to be handled feature by feature when implementing the
modules.
Errors (ApiError)
Section titled “Errors (ApiError)”try { await authApi.login(dto)} catch (error) { const apiError = toApiError(error) getErrorMessageForCode(apiError.code) // code → French message (core/api/error-messages.ts) getFieldErrors(error) // details[].property → form errors}Don’ts
Section titled “Don’ts”- ❌ Raw
fetch()outsidecore/api/http.ts. - ❌ Duplicating a DTO from the generated schema.
- ❌ Attaching the bearer on
/auth/loginor/auth/refresh. - ❌ Logging tokens or sensitive response bodies.
