bcgov / lcfs

An online application for fuel suppliers to manage their compliance obligations under the Low Carbon Fuels Act
Apache License 2.0
5 stars 3 forks source link

LCFS - Implement Frontend-Driven Feature Flags with Build-Time Configuration #1223

Open AlexZorkin opened 1 week ago

AlexZorkin commented 1 week ago

Description:

Implement a build-time configuration system for managing feature flags in the frontend. The system will allow feature availability (e.g., Supplemental Reporting, Notifications) to be dynamically toggled using a centralized configuration class (window.lcfs_config). This approach ensures immediate updates upon reload, eliminates backend dependency, and simplifies feature flag management.

Acceptance Criteria:

  1. Centralized Configuration:

    • A global window.lcfs_config object includes a feature_flags key for managing feature states.
    • Example structure:
      window.lcfs_config = {
      feature_flags: {
       supplementalReporting: true,
       notifications: false
      },
      keycloak: { /* Other configurations */ }
      };
  2. Helper Function:

    • A utility function (isFeatureEnabled) provides safe access to feature flags.
    • Example usage:
      if (isFeatureEnabled('supplementalReporting')) {
      // Feature logic here
      }
  3. Navbar Integration:

    • Navigation menu dynamically hides items based on feature flag states.
  4. Route Management:

    • Routes for disabled features redirect users to the dashboard.
  5. Environment Injection:

    • Ensure window.lcfs_config is populated at build time with environment-specific values.
  6. Fallback Defaults:

    • Provide fallback defaults to prevent runtime errors if window.lcfs_config is incomplete.

Development Checklist:

Frontend Implementation:

  1. Update window.lcfs_config with feature_flags object:

    • Example:
      export const CONFIG = {
      FEATURE_FLAGS: window.lcfs_config.feature_flags || {},
      KEYCLOAK: {
       REALM: window.lcfs_config.keycloak.REALM || 'standard',
       CLIENT_ID: window.lcfs_config.keycloak.CLIENT_ID || 'default-client-id',
       AUTH_URL: window.lcfs_config.keycloak.AUTH_URL || 'https://auth-url',
       POST_LOGOUT_URL: window.lcfs_config.keycloak.POST_LOGOUT_URL || 'https://logout-url',
       SM_LOGOUT_URL: window.lcfs_config.keycloak.SM_LOGOUT_URL || 'https://sm-logout-url'
      }
      };
  2. Helper Function:

    • Add a utility to check feature flag states:
      export function isFeatureEnabled(featureName) {
      return CONFIG.FEATURE_FLAGS[featureName] ?? false;
      }
  3. Update Navbar:

    • Modify the Navbar to hide items based on flags:
      if (isFeatureEnabled('supplementalReporting')) {
      navItems.push({ name: 'Supplemental Reporting', route: '/reports' });
      }
  4. Route Wrapping:

    • Protect feature routes using isFeatureEnabled:
      <Route
      path="/reports"
      element={isFeatureEnabled('supplementalReporting') ? <Reports /> : <Navigate to="/" />}
      />
  5. Environment-Specific Injection:

    • Ensure window.lcfs_config is dynamically populated during the build process based on the target environment (dev, test, prod). In openshift we will need mounted config_maps with our config.js file

Testing:

  1. Unit Tests:

    • Test the isFeatureEnabled utility with various feature flag states.
  2. Integration Tests:

    • Verify that the Navbar and routes behave correctly when feature flags are toggled.
  3. Manual Verification:

    • Confirm the behavior of feature toggles across environments.

Purpose and Benefits:

kuanfandevops commented 3 days ago

The feature_flags object has been added in the configmap. The configmap is mapped as /app/config/config.js in frontend pod. $ cat config.js window.lcfs_config = { api_base: 'https://lcfs-backend-dev.apps.silver.devops.gov.bc.ca/api', keycloak: { REALM: 'standard', CLIENT_ID: 'low-carbon-fuel-standard-5147', AUTH_URL: 'https://dev.loginproxy.gov.bc.ca/auth', POST_LOGOUT_URL: 'https://lcfs-dev.apps.silver.devops.gov.bc.ca/', SM_LOGOUT_URL: 'https://logontest7.gov.bc.ca/clp-cgi/logoff.cgi?retnow=1&returl=' }, feature_flags: { supplementalReporting: true, notifications: false } }