Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

02 — User Personas (Feature Flags Module)

Roles, goals, permissions, and expected behavior for every consumer of Feature Flags. Permission values are exact from src/modules/rbac/permissions.constants.ts:78-80 (feature-flags.read/update/delete). Important: the permissions exist in ALL_PERMISSIONS but are not enforced on any flag endpoint today — RbacGuard allows when no @Roles()/@Permissions() metadata is present (rbac.guard.ts:29) and the controller declares only JwtAuthGuard (feature-flags.controller.ts:18). So every persona below with a valid JWT can mutate flags; the UI must be built as if permissions will be enforced (OQ-5).


1. Org Admin (org_admin) — owner of the flag catalog

AttributeValue
FrequencyWeekly-ish; during onboarding and channel setup
PermissionsALL_PERMISSIONS incl. feature-flags.* (role.schema.ts:23 → seeded org_admin)
GoalSee what capabilities their institution has on/off; flip channels (biometric, SMS, WhatsApp) on demand
Pain pointsDoesn't know which module a key belongs to; enabling a flag but the feature "not working" (propagation delay, OQ-1)
Core jobGET /feature-flags (browse), PUT /feature-flags (toggle one), PUT /feature-flags/bulk (rollout)
RestrictionsWrites are not permission-gated today (OQ-5) — but per contract they will be; UI hides write affordances without feature-flags.update
Expected behaviourInstant toggle feedback; clear "applies to which module" grouping; honest "why can't I see X" messages for end users
Mental model"This is my school's switchboard — flip what we paid for / bought hardware for."

2. Feature Configurator (admin delegate with feature-flags.update)

AttributeValue
FrequencyDuring rollouts and migrations; support tickets
Permissionsfeature-flags.read, feature-flags.update (custom role; possible today in RBAC config)
GoalBatch-configure flags (e.g., enable SMS for all campuses), fix label/description typos, stage a module's rollout
Core jobPUT /feature-flags/bulk (feature-flags.controller.ts:48-52), editor with key/enabled/label/description/module (update-feature-flag.dto.ts:4-26)
Pain pointsBulk is sequential, no transaction (feature-flags.service.ts:40-44) → needs per-row result; editor's description/module are silently dropped by the server upsert (feature-flag.repository.ts:40)
RestrictionsNo feature-flags.delete → delete affordance hidden (server would accept it anyway — OQ-5)
Expected behaviourSee per-flag success/failure after bulk; never "saved" when the server persisted only 2 of 5 fields
Mental model"I configure the switches; the platform team owns the keys."

3. End Users Affected by Flags (teacher, staff, parent, student)

AttributeValue
FrequencyEvery session — flags gate the app they see
PermissionsUsually none of feature-flags.*; low-permission roles (role.schema.ts:31-42)
GoalNever crash, never see a grayed "coming soon" wall; a disabled feature simply isn't there
Core interactionNone direct — the client gates UI via FeatureFlagsCubit (00-shared/06 §4: "gates UI per tenant (biometric, SMS, WhatsApp channels)")
Pain pointsA flag flips mid-session (admin toggles SMS off while teacher is in the SMS-send flow)
Expected behaviourFeature disappears/re-enables within propagation window (client TTL; server 30 s cache (planned) CACHE_ARCHITECTURE.md:48); in-flight action completes gracefully
Mental model"The app just has what my school has."

4. Platform Admin (platform_admin, cross-tenant support)

AttributeValue
PermissionsisPlatformAdmin=true when role present (jwt-auth.guard.ts:54); reads bypass tenant scope (base.repository.ts:21-23)
FrequencyOn-demand support / diagnostics / platform-level rollouts
GoalInspect a tenant's flag state during support; evaluate platform-level defaults
RestrictionsUpsert calls requireTenantId() directly (feature-flag.repository.ts:37) — platform-admin write without a tenant context throws; use org-level surface instead (PATCH /organizations/:id/feature-flags, organizations.controller.ts:81-89)
Expected behaviourRead any tenant's flags; write via the org lifecycle surface with organization.update semantics
Mental model"Support reads; tenant ops writes."

5. Downstream Module Consumers (biometric, notifications, payments) — (forward-looking)

AttributeValue
RoleServices, not users — they call FeatureFlagsService.isEnabled(key) (feature-flags.service.ts:22-25)
ContractisEnabled returns flag?.enabled ?? falsemissing flag = disabled (fail-closed)
StatusNo consumer in src/ today (grep: only the flag module itself); PLAN.md:29 scenario 2.6 documents the intent ("Feature-toggle read in downstream services")
Example keys (from handbook)"Biometric Attendance", "WhatsApp", "AI Reports", "Payroll", "Inventory" (COLLECTIONS.md:791-800); WhatsApp channel is Phase 2 (FEATURE_ROADMAP.md:27)
Client impactThese modules' screens render behind flags the admin manages here — this package specs the gating mechanism (13_State_Management.md)

6. Role → flag-appearance matrix

Valueorg_adminconfiguratorend userplatform_admin
Flags list (read)— (app is pre-gated for them)✓ (cross-tenant)
Flag editor✓ (org surface)
Bulk update
Delete flag✓ (server accepts; UI per policy)— (no perm)
Org overlay flagsvia /organization settings
Toggle visibility to end usersn/a — flags gate THEIR screens, not the admin's

Roles/goal frequency: shared baseline 00-shared/01. Every persona's flag-facing need collapses to: admin — "flip it and know it applied"; platform — "read it fast"; end user — "never see what's off." The module's differentiators (module grouping, enabled-only set, bulk, per-row results) are the admin-facing surface.