Reference

Feature flags

Feature access in OpsDash is controlled by two systems that work together: Stripe Entitlements (what the plan includes) and the feature_flags table (per-org toggles with role restrictions).

How feature access works

Every protected feature passes through four layers:

  1. Entitlement check: Is the feature included in the org's Stripe plan?
  2. Subscription status: Must be active or trialing
  3. Feature flag: feature_flags.enabled — is it enabled for this org?
  4. Role check: Is the user's role in feature_flags.allowed_roles?

The feature_flags table

One row per feature per org. Seeded from defaultFeatures on org creation.

feature_flags (
  id          uuid PK,
  org_id      uuid FK → organizations,
  feature_key text,          -- e.g. 'crm:contacts'
  enabled     boolean,       -- on/off for this org
  allowed_roles text[],      -- NULL = all roles; array = restrict
  created_at  timestamptz
)

UI: Settings → Admin → Feature Flags (owner/admin only)

Server-side functions

FunctionLocationPurpose
canAccessFeature()org-context.tsxClient: sidebar, command palette, route guards
requireFeatureAccess()admin.ts → admin-feature-gates.tsServer actions: returns error if no access
ensureFeatureAccess()admin.ts → admin-feature-gates.tsLayouts: redirects to dashboard if no access
ensureTieredFeatureAccess()admin.ts → admin-feature-gates.tsLayouts: Pro/Enterprise sub-features (e.g. crm:export layout)
checkFeature()admin.ts → admin-feature-gates.tsSubscription/entitlement check only — no role check
checkUsageLimit()helpers.tsUsage-capped features — checks count vs. plan limit

All feature keys

CRM

KeyFreeProEnterprise
crm:contacts25010,000Unlimited
crm:companies502,000Unlimited
crm:deals502,000Unlimited
crm:leads1005,000Unlimited
crm:lead-scoring
crm:deal-stages
crm:activities
crm:contact-fields
crm:gdpr-export
crm:quotes
crm:csv-import
crm:contact-filters
crm:lead-filters
crm:data-cleanup
crm:export
crm:email-integration
crm:custom-fields

workspace_data_export is a Pro/Enterprise org flag (not in defaultFeatures) stored in feature_flags; it gates crm:export (CRM → Data Export) together with the crm module. It appears in Workspace admin → Feature flags.

Projects

KeyFreeProEnterprise
projects:crud350Unlimited
projects:tasks100UnlimitedUnlimited
projects:kanban
projects:calendar
projects:comments
projects:time-tracking-view
projects:subtasks
projects:milestones
projects:gantt
projects:dependencies
projects:time-tracking-log
projects:estimation
projects:budget
projects:team-management
projects:custom-fields

Platform

KeyFreeProEnterprise
platform:audit-logs
platform:rbac-viewer
platform:custom-branding
platform:sso
platform:api-access
platform:webhooks
platform:reports
platform:lead-capture-api
platform:onboarding

Feature key naming convention

type FeatureKey =
  | `crm:${string}`
  | `projects:${string}`
  | `billing:${string}`
  | `automation:${string}`
  | `platform:${string}`
  | `forms:${string}`
  | `dashboard:${string}`

Defined in packages/config/src/types.ts. All keys are used in packages/config/src/defaults.ts (defaultFeatures) and seeded into feature_flags on org creation.