diff --git a/EXHAUSTIVE_TODO_LIST.md b/EXHAUSTIVE_TODO_LIST.md index 6bf38ac06..57556b941 100644 --- a/EXHAUSTIVE_TODO_LIST.md +++ b/EXHAUSTIVE_TODO_LIST.md @@ -393,11 +393,11 @@ Critical path dependencies: ### Sub-Epic 1.4: API Versioning Strategy 🟢 #### Task 1.4.1: Implement Version Headers -- [ ] **Action 1.4.1.1**: Add `X-API-Version` header to all requests +- [x] **Action 1.4.1.1**: Add `X-API-Version` header to all requests - **Scope**: `apps/web/src/services/api/client.ts` - Add header in request interceptor - **Dependencies**: None - **Risk**: LOW - - **Validation**: All requests include header + - **Validation**: ✅ Header added to request interceptor, uses env.API_VERSION - **Rollback**: Remove header - [ ] **Action 1.4.1.2**: Backend returns `X-API-Deprecated` header for old versions @@ -414,11 +414,11 @@ Critical path dependencies: - **Validation**: Warning appears when deprecated version used - **Rollback**: Remove warning logic -- [ ] **Action 1.4.1.4**: Store API version in config +- [x] **Action 1.4.1.4**: Store API version in config - **Scope**: `apps/web/src/config/env.ts` - Add API_VERSION constant - **Dependencies**: None - **Risk**: LOW 🔒 - - **Validation**: Version stored in config + - **Validation**: ✅ API_VERSION added to env config, defaults to 'v1' - **Rollback**: Remove from config - [ ] **Action 1.4.1.5**: Use config version in header diff --git a/apps/web/src/config/env.ts b/apps/web/src/config/env.ts index e7285d781..da7940915 100644 --- a/apps/web/src/config/env.ts +++ b/apps/web/src/config/env.ts @@ -8,6 +8,7 @@ const envSchema = z.object({ VITE_STREAM_URL: z.string().url().default('ws://127.0.0.1:8082/stream'), VITE_UPLOAD_URL: z.string().url().default('http://127.0.0.1:8080/upload'), VITE_APP_NAME: z.string().default('Veza'), + VITE_API_VERSION: z.string().default('v1'), VITE_DEBUG: z .string() .transform((val) => val === 'true' || val === '1') @@ -30,6 +31,7 @@ const parseEnv = () => { VITE_STREAM_URL: import.meta.env.VITE_STREAM_URL, VITE_UPLOAD_URL: import.meta.env.VITE_UPLOAD_URL, VITE_APP_NAME: import.meta.env.VITE_APP_NAME, + VITE_API_VERSION: import.meta.env.VITE_API_VERSION, VITE_DEBUG: import.meta.env.VITE_DEBUG, VITE_USE_MSW: import.meta.env.VITE_USE_MSW, VITE_FCM_VAPID_KEY: import.meta.env.VITE_FCM_VAPID_KEY, @@ -58,6 +60,7 @@ export const env = { STREAM_URL: validatedEnv.VITE_STREAM_URL, UPLOAD_URL: validatedEnv.VITE_UPLOAD_URL, APP_NAME: validatedEnv.VITE_APP_NAME, + API_VERSION: validatedEnv.VITE_API_VERSION, DEBUG: validatedEnv.VITE_DEBUG, USE_MSW: validatedEnv.VITE_USE_MSW, FCM_VAPID_KEY: validatedEnv.VITE_FCM_VAPID_KEY, diff --git a/apps/web/src/services/api/client.ts b/apps/web/src/services/api/client.ts index 8e58230f6..bf43c1749 100644 --- a/apps/web/src/services/api/client.ts +++ b/apps/web/src/services/api/client.ts @@ -217,6 +217,11 @@ const processQueue = (error: Error | null, token: string | null = null) => { // CRITIQUE: Récupérer TOUJOURS le token frais depuis localStorage car Zustand peut ne pas être hydraté apiClient.interceptors.request.use( async (config: InternalAxiosRequestConfig) => { + // API Versioning: Add X-API-Version header to all requests + if (config.headers) { + config.headers['X-API-Version'] = env.API_VERSION; + } + // INT-AUTH-004: Vérifier l'expiration du token avant d'envoyer la requête // Buffer de 60 secondes pour éviter les 401 inutiles const PRE_REQUEST_REFRESH_BUFFER_MS = 60 * 1000; // 60 secondes