From a6bafcbcc551618a9987eb28fedab1225842c895 Mon Sep 17 00:00:00 2001 From: senke Date: Wed, 11 Feb 2026 22:11:38 +0100 Subject: [PATCH] feat(web): externalize feature flags via VITE_FEATURE_* env vars (P3.2) - Parse VITE_FEATURE_* from env with fallback to current defaults - Add all flags to .env.example and ENV_CONFIG.md - parseFeatureEnv accepts true/1/yes for enabled Co-authored-by: Cursor --- ENV_CONFIG.md | 29 +++++++++++++++++++ apps/web/.env.example | 15 ++++++++++ apps/web/src/config/features.ts | 49 +++++++++++++++++++++++++++------ apps/web/src/vite-env.d.ts | 9 ++++++ 4 files changed, 93 insertions(+), 9 deletions(-) diff --git a/ENV_CONFIG.md b/ENV_CONFIG.md index 57de8c8a3..67697c5db 100644 --- a/ENV_CONFIG.md +++ b/ENV_CONFIG.md @@ -1,5 +1,18 @@ # Configuration des Variables d'Environnement +## Connexion Backend ↔ Infra Docker + +Pour `make infra-up`, Postgres, Redis et RabbitMQ sont exposés sur des ports décalés pour éviter les conflits : + +| Service | Port host | Port interne | Connexion depuis host | +|-----------|-----------|--------------|-----------------------------------| +| PostgreSQL| 15432 | 5432 | `postgres://veza:password@veza.fr:15432/veza` | +| Redis | 16379 | 6379 | `redis://veza.fr:16379` | +| RabbitMQ | 15672 (AMQP), 25672 (UI) | 5672, 15672 | `amqp://veza:password@veza.fr:15672/` | + +Le backend **dans Docker** utilise les noms de service internes (`postgres:5432`, `redis:6379`, `rabbitmq:5672`). +Le backend **sur la machine hôte** doit utiliser les ports mappés ci-dessus. Copiez `veza-backend-api/.env.template` vers `veza-backend-api/.env` et adaptez selon votre cas. + ## Backend API Pour activer le logging centralisé vers `/var/log/veza`, ajoutez ces variables à votre fichier `.env` : @@ -72,3 +85,19 @@ Avant de lancer : ```bash docker-compose -f docker-compose.prod.yml up -d ``` + +## Feature Flags (Frontend) + +Les feature flags sont configurables via les variables `VITE_FEATURE_*` (voir `apps/web/.env.example`). +Valeurs acceptées : `true`, `1`, `yes` = activé ; sinon désactivé. + +| Variable | Défaut | Description | +|----------|--------|--------------| +| VITE_FEATURE_TWO_FACTOR_AUTH | true | Authentification 2FA | +| VITE_FEATURE_PLAYLIST_COLLABORATION | true | Collaboration sur les playlists | +| VITE_FEATURE_PLAYLIST_SEARCH | false | Recherche dans les playlists | +| VITE_FEATURE_PLAYLIST_SHARE | false | Partage de playlists | +| VITE_FEATURE_PLAYLIST_RECOMMENDATIONS | false | Recommandations de playlists | +| VITE_FEATURE_HLS_STREAMING | false | Streaming HLS | +| VITE_FEATURE_ROLE_MANAGEMENT | false | Gestion des rôles | +| VITE_FEATURE_NOTIFICATIONS | false | Notifications | diff --git a/apps/web/.env.example b/apps/web/.env.example index b56c8cb4a..ee0fdab8b 100644 --- a/apps/web/.env.example +++ b/apps/web/.env.example @@ -6,6 +6,10 @@ # Change this + /etc/hosts to switch domain. VITE_DOMAIN=veza.fr +# --- BACKEND PORT (Vite proxy target) --- +# Must match PORT_BACKEND in docker-compose / config.mk. Default 18080 avoids conflicts. +VITE_BACKEND_PORT=18080 + # API Configuration # Base URL for the REST API (can be absolute URL or path starting with /) # DEV: use /api/v1 so the Vite proxy forwards to the backend (same-origin cookies). @@ -48,3 +52,14 @@ VITE_USE_MSW=0 # Sentry Error Tracking # Sentry DSN for error tracking (optional) # VITE_SENTRY_DSN=https://your-sentry-dsn@sentry.io/project-id + +# --- Feature Flags (optional, defaults in parens) --- +# Override feature flags without rebuild. Values: true, 1, yes = enabled; else disabled. +# VITE_FEATURE_TWO_FACTOR_AUTH=true +# VITE_FEATURE_PLAYLIST_COLLABORATION=true +# VITE_FEATURE_PLAYLIST_SEARCH=false +# VITE_FEATURE_PLAYLIST_SHARE=false +# VITE_FEATURE_PLAYLIST_RECOMMENDATIONS=false +# VITE_FEATURE_HLS_STREAMING=false +# VITE_FEATURE_ROLE_MANAGEMENT=false +# VITE_FEATURE_NOTIFICATIONS=false diff --git a/apps/web/src/config/features.ts b/apps/web/src/config/features.ts index 7f6f392a6..339021661 100644 --- a/apps/web/src/config/features.ts +++ b/apps/web/src/config/features.ts @@ -4,42 +4,73 @@ * Controls which features are enabled/disabled for MVP. * Features marked as false are not yet implemented in the backend. * - * TODO: Move these to environment variables or backend config after MVP. + * All flags can be overridden via VITE_FEATURE_* env vars (see .env.example). + * Ghost features (Studio, Inventory, Education, Gamification, Live) are documented + * in docs/FEATURE_STATUS.md — UI exists but backend is missing or mock-only. */ +function parseFeatureEnv(value: string | undefined, defaultValue: boolean): boolean { + if (value === undefined || value === '') return defaultValue; + const v = value.toLowerCase().trim(); + return v === 'true' || v === '1' || v === 'yes'; +} + export const FEATURES = { /** * Two-Factor Authentication * Backend endpoints: /auth/2fa/setup, /auth/2fa/verify, /auth/2fa/disable, /auth/2fa/status */ - TWO_FACTOR_AUTH: true, + TWO_FACTOR_AUTH: parseFeatureEnv( + import.meta.env.VITE_FEATURE_TWO_FACTOR_AUTH, + true, + ), /** * Playlist Collaboration Features * Backend endpoints: /playlists/:id/collaborators (GET, POST, PUT, DELETE) */ - PLAYLIST_COLLABORATION: true, - PLAYLIST_SEARCH: import.meta.env.VITE_STORYBOOK === 'true', - PLAYLIST_SHARE: false, - PLAYLIST_RECOMMENDATIONS: false, + PLAYLIST_COLLABORATION: parseFeatureEnv( + import.meta.env.VITE_FEATURE_PLAYLIST_COLLABORATION, + true, + ), + PLAYLIST_SEARCH: + import.meta.env.VITE_STORYBOOK === 'true' || + parseFeatureEnv(import.meta.env.VITE_FEATURE_PLAYLIST_SEARCH, false), + PLAYLIST_SHARE: parseFeatureEnv( + import.meta.env.VITE_FEATURE_PLAYLIST_SHARE, + false, + ), + PLAYLIST_RECOMMENDATIONS: parseFeatureEnv( + import.meta.env.VITE_FEATURE_PLAYLIST_RECOMMENDATIONS, + false, + ), /** * HLS Streaming * Backend endpoints: /api/v1/tracks/:id/hls/info, /api/v1/tracks/:id/hls/status (NOT IMPLEMENTED) */ - HLS_STREAMING: false, + HLS_STREAMING: parseFeatureEnv( + import.meta.env.VITE_FEATURE_HLS_STREAMING, + false, + ), /** * Role Management * Backend endpoints: /api/v1/users/:userId/roles, /api/v1/roles/* (NOT IMPLEMENTED) */ - ROLE_MANAGEMENT: false, + ROLE_MANAGEMENT: parseFeatureEnv( + import.meta.env.VITE_FEATURE_ROLE_MANAGEMENT, + false, + ), /** * Notifications API * Backend endpoints: /api/v1/notifications/* (NOT IMPLEMENTED) */ - NOTIFICATIONS: false, + NOTIFICATIONS: parseFeatureEnv( + import.meta.env.VITE_FEATURE_NOTIFICATIONS, + false, + ), } as const; /** diff --git a/apps/web/src/vite-env.d.ts b/apps/web/src/vite-env.d.ts index e7553e386..4293c3ec0 100644 --- a/apps/web/src/vite-env.d.ts +++ b/apps/web/src/vite-env.d.ts @@ -10,6 +10,15 @@ interface ImportMetaEnv { readonly VITE_USE_MSW: string; readonly VITE_STORYBOOK?: string; readonly VITE_FCM_VAPID_KEY: string; + /** Feature flags (optional) */ + readonly VITE_FEATURE_TWO_FACTOR_AUTH?: string; + readonly VITE_FEATURE_PLAYLIST_COLLABORATION?: string; + readonly VITE_FEATURE_PLAYLIST_SEARCH?: string; + readonly VITE_FEATURE_PLAYLIST_SHARE?: string; + readonly VITE_FEATURE_PLAYLIST_RECOMMENDATIONS?: string; + readonly VITE_FEATURE_HLS_STREAMING?: string; + readonly VITE_FEATURE_ROLE_MANAGEMENT?: string; + readonly VITE_FEATURE_NOTIFICATIONS?: string; // more env variables... }