Administration and Feature Flags
Navaid has platform-level System Admin and tenant-level Company Admin surfaces. UI visibility is not authority: mutations are backed by RLS, guarded columns, SECURITY DEFINER RPCs, or explicitly authorized Edge Functions.
System Admin
/app/admin is wrapped by SystemAdminGuard and contains 11 tabs:
| Tab | Responsibility |
|---|---|
| Overview | user/company/session/token statistics |
| Prompts | version, activate, edit and launch Prompt Lab |
| Companies | membership inspection, experience compatibility, deletion |
| Partners | catalogue and contacts |
| Budgets | stored budget/config values and company budget master switch |
| Features | nine feature toggles |
| Invites | reusable invite-code management |
| Early access | pilot-interest review/action |
| Feedback | Kanban-style triage |
| Theme | runtime accent scale |
| Debug | controlled Sentry/debug actions |
Shared overview/prompts/companies/partners data is loaded by
pages/admin/useAdminData; mutation tabs call reload() as needed.
SystemAdminGuard prevents structural disclosure, but every database/function
operation also verifies is_system_admin.
Company Admin
/app/company has four keyboard-operable tabs:
| Tab | Responsibility |
|---|---|
| Settings | name, logo, allowed email domains and system-admin budget fields |
| Users | memberships, roles, invitations and CSV export |
| Usage | session/member/monthly/daily usage |
| Knowledge | profile facts/learnings, history, document upload/retention |
company_admin and company_consultant are equivalent. Company managers do not
receive full company-administration rights.
Budget fields are included in updates only for system admins; a database column guard enforces this even if a client sends them.
Prompt Management
Prompt versions are separated by experience slot. Activating/saving a v2 prompt deactivates sibling v2 rows before activating/inserting the new version.
Prompt Lab:
- tests advisor behaviour and prompt refinement through
prompt-test, - is system-admin only,
- records Gemini token usage,
- stores in-progress state at
prompt-lab-session-v1, - clears storage on Save and Cancel.
Admin actions call log_admin_action(), which verifies and server-stamps the
actor.
Feature Flags
System Admin → Features exposes nine flags; the budget master switch lives in Budgets.
| Key | Default | Client | Server |
|---|---|---|---|
voice_enabled | on | single voice button | not read by chat-live |
multilingual_enabled | off | in-app language selector | no |
overview_enabled | off | portfolio access/page | no |
multiplayer_enabled | off | multiplayer access | no universal backend kill switch |
aida_enabled | off | Aida widget | aida, aida-live |
group_voice_enabled | off | group voice affordance | livekit-token for session rooms |
mcp_enabled | off | admin/config display | mcp |
world_cup_theme_enabled | off | seasonal Aida visuals plus date gate | no |
lead_hunt_enabled | off | Prospect Radar | lead-hunt |
company_budgets_enabled | on | budget indicator | shared AI budget helper |
System admins bypass Aida, group voice, MCP, and lead-hunt pilot flags where implemented.
Flag factory
createFeatureFlag provides cached reads and in-tab broadcast updates for
several client flags. Features without a broadcast hook re-read on normal
render/load.
Enforcement rule
Classify a flag:
- presentation/client pilot: hides navigation/affordance only,
- server cost/access gate: checked again by the function,
- operational kill switch: must be enforced at every server entry point.
Do not document a client pilot flag as a security or operational kill switch.
Budget Configuration
The active tenant control is:
- per-user override,
- else company default,
- monthly input and output aggregates,
- gated by
company_budgets_enabled.
The Admin UI also stores daily_token_budget and alert_config, but current
main has no runtime consumer that enforces the daily value or sends alerts
from those settings.
Invitations and Feedback
Invite codes:
- public preflight is non-enumerating and rate-limited,
- list/create/revoke are system-admin only,
- consumption occurs in the Auth hook.
Feedback:
- users submit/read their own rows,
- system admins triage all,
- insert policy blocks user-set admin notes/status,
- notification links derive from
APP_URL.
Adding a Flag
- Add a migration seed with safe default.
- Add the key to the public config allowlist only if clients need it.
- Add typed config get/update functions.
- Add client hook/broadcast if needed.
- Add server enforcement for cost/privilege.
- Decide system-admin bypass explicitly.
- Add localized admin copy.
- Test flag missing, false, true, and config-read failure.
- Document enforcement in the matrix.
Troubleshooting
- Toggle changes but page does not: check broadcast/reload behaviour.
- UI hides feature but API still works: expected for client-only flags.
- Tenant admin budget save fails: protected columns are system-admin-only.
- Audit row has wrong actor: use
log_admin_action, not direct insert.