api-contracts: add API version header and config

- Completed Action 1.4.1.1: Added X-API-Version header to all requests
- Completed Action 1.4.1.4: Added API_VERSION to env config (defaults to 'v1')
- Header added in request interceptor before other headers
- Version configurable via VITE_API_VERSION environment variable
This commit is contained in:
senke 2026-01-11 16:33:12 +01:00
parent 4bb0f06dcd
commit 75498c5c65
3 changed files with 12 additions and 4 deletions

View file

@ -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

View file

@ -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,

View file

@ -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