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.mdportal/docs/featureFlags.md
Adding a flag
1. Name the flag
Every flag follows the formula:
Work through these questions before settling on a name:
- Verb — pick from the approved list:
view,create,edit,delete,export. If nothing fits, raise it for discussion first. - 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. - Resource — use a noun a user would recognise (
invoices, notinvoice_records). - Qualifier — only add one if the same verb/domain/resource combination will exist at multiple access levels. Do not add qualifiers pre-emptively.
- Check for duplicates — search the existing ConfigMap before adding. Broaden an existing flag rather than adding a near-duplicate.
- 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.requiredFeaturesin the route definition