Featurevisor

Use cases

Role based access control (RBAC)

Show each user the features their roles allow. Role rules live in one place in Git, instead of in role checks scattered through the interface, while your backend keeps deciding who has which role and what they may do.

Who owns what

Keep these responsibilities separate:

ConcernOwner
Authenticating the userBackend
Determining which roles the user hasBackend
Communicating roles to the clientBackend (via API response / JWT)
Declaring which features require which rolesFeaturevisor project (Git)
Evaluating feature visibility at runtimeFeaturevisor SDK (client)
Enforcing access on sensitive operationsBackend (always)

You can also evaluate these definitions in a backend service. A frontend visibility check never replaces authorization on a protected operation.

How it works

An attribute of type array holds a list of strings, which suits roles, since a user can have several. The pattern has three parts:

  1. A roles attribute, holding the current user's roles
  2. One segment per role, matching users whose roles include it
  3. Feature rules that name those segments

The application passes the roles it gets from the backend into the SDK's context, and the SDK evaluates the rules with them.

Define the roles attribute

attributes/roles.yml
description: Roles of the signed in user, from the backend
type: array
items:
type: string
enum:
- viewer
- editor
- manager
- admin
- super-admin

The items and enum properties document allowed values and support linting. They do not reject additional roles in runtime context or replace the backend's validation of role assignments.

A segment for each role

Each segment answers one question: does this user have this role?

segments/superAdmins.yml
description: Users who have the super-admin role
conditions:
- attribute: roles
operator: includes
value: super-admin
segments/admins.yml
description: Users who have the admin role
conditions:
- attribute: roles
operator: includes
value: admin
segments/managers.yml
description: Users who have the manager role
conditions:
- attribute: roles
operator: includes
value: manager
segments/editors.yml
description: Users who have the editor role
conditions:
- attribute: roles
operator: includes
value: editor
segments/viewers.yml
description: Users who have the viewer role
conditions:
- attribute: roles
operator: includes
value: viewer

Every feature that depends on a role reuses its segment, so letting another role see a feature is a one line change.

Show features by role

Define features that target those segments.

List the roles that grant access. A not rule also matches users without roles, including signed-out visitors.

The default scaffold already declares userId, country and the netherlands segment used below. Roles do not imply a hierarchy: list each role that grants the feature.

Admins only

features/adminSettingsPanel.yml
description: |
Advanced settings panel
visible only to admins and super admins
bucketBy: userId
rules:
- key: admins
conditions:
or:
- admins
- superAdmins
percentage: 100
- key: everyone-else
conditions: '*'
percentage: 0

Managers and above

features/billingDashboard.yml
description: |
Billing dashboard
visible to managers, admins and super admins
bucketBy: userId
rules:
- key: billing_roles
conditions:
or:
- managers
- admins
- superAdmins
percentage: 100
- key: everyone-else
conditions: '*'
percentage: 0

Editors and above

features/bulkExport.yml
description: |
Bulk data export
available to editors and above
bucketBy: userId
rules:
- key: contributors
conditions:
or:
- editors
- managers
- admins
- superAdmins
percentage: 100
- key: everyone-else
conditions: '*'
percentage: 0
A grid of roles and features. Super admins and admins see all three features, managers see billingDashboard and bulkExport, editors see bulkExport and viewers see none.

Roles with other segments

Combine a role with other segments. Here, a new analytics feature is rolled out to managers in the Netherlands first:

features/advancedAnalytics.yml
description: |
Advanced analytics
gradual rollout starting with managers in the Netherlands
bucketBy: userId
rules:
- key: nl-managers-early-access
conditions:
and:
- managers
- netherlands
percentage: 100
- key: everyone-else
conditions: '*'
percentage: 0

Pass the roles as context

The backend provides the roles for the current user, and application code passes them into the SDK context in runtime:

your-app/index.js
import { createFeaturevisor } from '@featurevisor/sdk'
const DATAFILE_URL = 'https://cdn.yoursite.com/featurevisor-all.json'
const sessionResponse = await fetch('/api/me')
if (!sessionResponse.ok) throw new Error('Could not load the current session')
const session = await sessionResponse.json()
const response = await fetch(DATAFILE_URL)
if (!response.ok) throw new Error(`HTTP ${response.status}`)
const datafileContent = await response.json()
const f = createFeaturevisor({
context: {
userId: session.userId,
roles: Array.isArray(session.roles) ? session.roles : [],
country: session.country,
},
datafile: datafileContent,
})

This instance belongs to one browser session. Replace its context when the user changes or logs out. Do not retain the previous user's roles. On a shared server instance, pass trusted context to each evaluation instead of setting user context on the instance. Learn how to build datafiles.

Evaluate the features

Use the SDK instance to evaluate feature visibility:

your-app/index.js
const showAdminSettings = f.isEnabled('adminSettingsPanel')
const showBilling = f.isEnabled('billingDashboard')
const showBulkExport = f.isEnabled('bulkExport')
const showAnalytics = f.isEnabled('advancedAnalytics')

Every SDK evaluates the same definitions, so a backend in Go or Python can make the same decision.

Test role access

Verify both absent roles and overlapping assignments. A viewer who is also an editor has a contributing role, while a viewer alone does not.

tests/features/bulkExport.spec.yml
feature: bulkExport
assertions:
- description: Signed out without roles
at: 50
context: {}
expectedToBeEnabled: false
- description: Null roles
at: 50
context: { roles: null }
expectedToBeEnabled: false
- description: Empty roles
at: 50
context: { roles: [] }
expectedToBeEnabled: false
- description: Viewer alone
at: 50
context: { roles: [viewer] }
expectedToBeEnabled: false
- description: Editor
at: 50
context: { roles: [editor] }
expectedToBeEnabled: true
- description: Viewer and editor
at: 50
context: { roles: [viewer, editor] }
expectedToBeEnabled: true
- description: Manager
at: 50
context: { roles: [manager] }
expectedToBeEnabled: true
- description: Admin
at: 50
context: { roles: [admin] }
expectedToBeEnabled: true
- description: Super admin
at: 50
context: { roles: [super-admin] }
expectedToBeEnabled: true

Run npx featurevisor lint, npx featurevisor test and npx featurevisor build from your initialized project.

Previous
User entitlements