Feature Flags & Pricing Tiers
This document describes the Feature Flag system used to enable/disable capabilities per tenant, control beta access, and manage pricing-tier defaults.
Goalsβ
- Pricing tiers: enable features by default based on a tenantβs tier (tier1/tier2/tier3).
- Tenant overrides: force a feature on/off for a specific tenant.
- Lifecycle safety:
devfeatures are never tenant-visible.betafeatures are off in production unless the tenant is configured for latest access.
- Single source of truth: API is authoritative; clients read the resolved feature flags from tenant config.
Definitionsβ
- Tenant / parentCompany: the parent company identifier enforced by API middleware (
verifyParent). In practice this is theCustomerdocumentβs_idand is frequently passed as a string. - Feature key: a stable string like
dispatch.v2Board. - Lifecycle:
dev: in-development, not tenant-visible.beta: preview capability (tenant-visible only when allowed).ga: generally available.
High-level flowβ
sequenceDiagram
participant Client
participant API
participant VerifyParent
participant ConfigSvc
participant Mongo
participant Flags
Client->>API: Request with x-parent-company header
API->>VerifyParent: validate tenant header matches token
VerifyParent->>ConfigSvc: retrieveCustomerConfig(parentCompanyId)
ConfigSvc->>Mongo: load Customer + Config(type=parent) + Config(type=system)
ConfigSvc->>Flags: resolveFeatureFlags(lifecycle+tier+overrides)
Flags-->>ConfigSvc: resolved featureFlags (tenant-visible) + meta (admin-only)
ConfigSvc-->>API: merged customerConfig
API-->>Client: config includes featureFlags
Data modelβ
Tenant settings (Customer / parent company)β
Stored on the Customer model:
planTier:tier1|tier2|tier3releaseChannel:stable|latestbetaAllowlist:string[]of beta feature keys
Tenant overrides (Config: parent)β
Stored in Mongo in Config:
type:parentrelativeId:<parentCompanyId>configs.featureFlagOverrides:{ [featureKey: string]: boolean }
This is the persistent per-tenant kill-switch / enablement mechanism.
Tier defaults (Config: system)β
Stored in Mongo in Config:
type:systemrelativeId:systemconfigs.featureTiers:
{
"tier1": { "some.flag": true },
"tier2": { "some.flag": true, "another.flag": true },
"tier3": { "some.flag": true, "another.flag": true, "pro.flag": true }
}
Resolution rules (authoritative)β
Lifecycle enforcement (highest precedence)β
dev:- Always resolves
falsein production. - Never included in tenant-visible
featureFlagsoutput. - Visible only in superAdmin admin tooling.
- Always resolves
betain production:- Resolves
falseunless:- tenant
releaseChannel === 'latest', and - feature key is present in tenant
betaAllowlist
- tenant
- Resolves
Precedence order (after lifecycle rules)β
- Tenant override (
Config.configs.featureFlagOverrides) - Tier default (system tier defaults)
- Registry default (code-level default for the feature key)
API endpointsβ
Tenant-facing config (includes resolved featureFlags)β
GET /api/v1/config/:id?type=parent- Returns effective tenant config, including:
config.configs.featureFlags
- For superAdmins, includes
_featureFlagsMeta(sources/tier/channel details).
- Returns effective tenant config, including:
SuperAdmin: tenant feature flagsβ
GET /api/v1/admin/feature-flags/:parentCompanyId- Returns tenant settings, overrides, resolved flags, and the registry.
PATCH /api/v1/admin/feature-flags/:parentCompanyId- Updates:
planTier,releaseChannel,betaAllowlistfeatureFlagOverrides
- Updates:
SuperAdmin: global tier defaultsβ
GET /api/v1/admin/feature-flags/tiers- Returns tier defaults (non-dev features) and registry.
PATCH /api/v1/admin/feature-flags/tiers- Updates tier defaults and clears caches so changes apply immediately.
Web admin UI (superAdmin)β
The Service (web app) includes a superAdmin page:
- Route:
/admin/feature-flags - Tabs:
- Tenant Flags: per-tenant overrides, channel, allowlist
- Tier Defaults: global tier default toggles
Operational notesβ
Cache behaviorβ
- Tenant configs are cached server-side.
- Updating tier defaults clears cache so effective configs re-resolve immediately.
Safety defaultsβ
- All new flags should default to off unless you explicitly want them on.
- Use
betafor preview/early access features; keepdevfor internal-only work.
Adding a new feature flag (developer workflow)β
- Add a new entry to the registry (
feature key,lifecycle,defaultEnabled, description). - Decide if it should be enabled by default in any tier.
- If
beta, decide which tenants get access via:releaseChannel=latestbetaAllowlistincludes the feature key
- Gate API behavior and UI rendering using the resolved
featureFlagsfrom config.