Skip to content

How to add a new feature flag

Feature flags are the single mechanism used to gate access to functionality. The backend resolves flags from a ConfigMap; the frontend consumes the resolved list via FeatureFlagService. Neither side should reference user types directly.

For full architecture detail see:

  • feature-flag-backend/docs/featureFlags.md
  • portal/docs/featureFlags.md

Adding a flag

1. Name the flag

Every flag follows the formula:

{verb}_{domain}_{resource}_{qualifier?}

Work through these questions before settling on a name:

  1. Verb — pick from the approved list: view, create, edit, delete, export. If nothing fits, raise it for discussion first.
  2. Domain — pick from the registered list: reporting | admin | billing | dashboard | integrations | settings. If the feature spans domains, consider two flags or propose a new domain via PR discussion.
  3. Resource — use a noun a user would recognise (invoices, not invoice_records).
  4. Qualifier — only add one if the same verb/domain/resource combination will exist at multiple access levels. Do not add qualifiers pre-emptively.
  5. Check for duplicates — search the existing ConfigMap before adding. Broaden an existing flag rather than adding a near-duplicate.
  6. Write a one-line description — if you cannot clearly describe what the flag gates and what the off state means for a user, the scope is not well-defined yet.

2. Add the rule to the ConfigMap

Add an entry to feature-flag-rules in the appropriate environment ConfigMap:

flags:
  create_reporting_exports_schedule:   # existing entry
    userType: ['admin', 'partner']

  view_your_new_flag:                # new entry
    userType: ['user']              # admin | partner | user

[!IMPORTANT] Pod restart required

The ConfigMap is read once at service startup and cached in memory. A pod restart is required for the change to take effect — there is no hot-reload.

3. Add the constant to the frontend

In feature-flags.ts, add a new constant with a description comment:

export const FeatureFlags = {
  // ...existing flags...

  /** One-line description of what the flag gates. Off = what happens when disabled. */
  YOUR_NEW_FLAG: 'view_your_new_flag',
} as const;

Never use raw strings in components, guards, or directives — always reference the constant.

4. Use the flag

  • Template: <element *appCan="FeatureFlags.YOUR_NEW_FLAG">
  • Component: this.accessService.can(FeatureFlags.YOUR_NEW_FLAG)
  • Route guard: add to data.requiredFeatures in the route definition