feat: add flexible capability-based RBAC with per-tenant customization
Introduces a capability layer on top of existing roles that controls feature visibility and access. Capabilities follow an area.feature.action taxonomy (~35 capabilities) with sensible defaults per role. Tenant admins can customize via grant/revoke overrides stored in org settings JSONB. Key changes: - Add vice_president role to DB schema - Backend: capability constants, resolution logic, CapabilityGuard (global), @RequireCapability decorator on all 16 tenant controllers - Frontend: permission hooks (useCanEdit, useHasCapability), CapabilityGate component, sidebar filtering by capability, all 17 pages migrated from useIsReadOnly to capability-based checks - New admin UI: /settings/permissions matrix page for per-tenant role customization with grant/revoke delta model - GET /organizations/my-capabilities endpoint for capability refresh - Validation of permissionOverrides in settings updates Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
131
frontend/src/permissions/capabilities.ts
Normal file
131
frontend/src/permissions/capabilities.ts
Normal file
@@ -0,0 +1,131 @@
|
||||
/**
|
||||
* Capability taxonomy for the HOA Financial Platform.
|
||||
*
|
||||
* This file mirrors backend/src/common/permissions/capabilities.ts.
|
||||
* Keep both files in sync when adding new capabilities.
|
||||
*/
|
||||
export const CAPABILITIES = {
|
||||
DASHBOARD_VIEW: 'dashboard.view',
|
||||
|
||||
FINANCIALS_ACCOUNTS_VIEW: 'financials.accounts.view',
|
||||
FINANCIALS_ACCOUNTS_EDIT: 'financials.accounts.edit',
|
||||
FINANCIALS_CASHFLOW_VIEW: 'financials.cashflow.view',
|
||||
FINANCIALS_CASHFLOW_EDIT: 'financials.cashflow.edit',
|
||||
FINANCIALS_ACTUALS_VIEW: 'financials.actuals.view',
|
||||
FINANCIALS_ACTUALS_EDIT: 'financials.actuals.edit',
|
||||
FINANCIALS_BUDGETS_VIEW: 'financials.budgets.view',
|
||||
FINANCIALS_BUDGETS_EDIT: 'financials.budgets.edit',
|
||||
FINANCIALS_BUDGETS_APPROVE: 'financials.budgets.approve',
|
||||
|
||||
ASSESSMENTS_UNITS_VIEW: 'assessments.units.view',
|
||||
ASSESSMENTS_UNITS_EDIT: 'assessments.units.edit',
|
||||
ASSESSMENTS_GROUPS_VIEW: 'assessments.groups.view',
|
||||
ASSESSMENTS_GROUPS_EDIT: 'assessments.groups.edit',
|
||||
|
||||
PLANNING_BUDGETS_VIEW: 'planning.budgets.view',
|
||||
PLANNING_BUDGETS_EDIT: 'planning.budgets.edit',
|
||||
PLANNING_PROJECTS_VIEW: 'planning.projects.view',
|
||||
PLANNING_PROJECTS_EDIT: 'planning.projects.edit',
|
||||
PLANNING_SCENARIOS_VIEW: 'planning.scenarios.view',
|
||||
PLANNING_SCENARIOS_EDIT: 'planning.scenarios.edit',
|
||||
PLANNING_SCENARIOS_APPROVE: 'planning.scenarios.approve',
|
||||
PLANNING_INVESTMENTS_VIEW: 'planning.investments.view',
|
||||
PLANNING_INVESTMENTS_EDIT: 'planning.investments.edit',
|
||||
|
||||
REFERENCE_VENDORS_VIEW: 'reference.vendors.view',
|
||||
REFERENCE_VENDORS_EDIT: 'reference.vendors.edit',
|
||||
|
||||
TRANSACTIONS_VIEW: 'transactions.view',
|
||||
TRANSACTIONS_EDIT: 'transactions.edit',
|
||||
TRANSACTIONS_APPROVE: 'transactions.approve',
|
||||
|
||||
REPORTS_VIEW: 'reports.view',
|
||||
|
||||
SETTINGS_ORG_VIEW: 'settings.org.view',
|
||||
SETTINGS_ORG_EDIT: 'settings.org.edit',
|
||||
SETTINGS_MEMBERS_VIEW: 'settings.members.view',
|
||||
SETTINGS_MEMBERS_MANAGE: 'settings.members.manage',
|
||||
SETTINGS_PERMISSIONS_MANAGE: 'settings.permissions.manage',
|
||||
} as const;
|
||||
|
||||
export type Capability = (typeof CAPABILITIES)[keyof typeof CAPABILITIES];
|
||||
|
||||
export const ALL_CAPABILITIES = new Set<string>(Object.values(CAPABILITIES));
|
||||
|
||||
/** Human-readable labels for capability areas (for admin UI) */
|
||||
export const CAPABILITY_AREAS: { label: string; capabilities: { key: string; label: string }[] }[] = [
|
||||
{
|
||||
label: 'Dashboard',
|
||||
capabilities: [
|
||||
{ key: CAPABILITIES.DASHBOARD_VIEW, label: 'View Dashboard' },
|
||||
],
|
||||
},
|
||||
{
|
||||
label: 'Financials',
|
||||
capabilities: [
|
||||
{ key: CAPABILITIES.FINANCIALS_ACCOUNTS_VIEW, label: 'View Accounts' },
|
||||
{ key: CAPABILITIES.FINANCIALS_ACCOUNTS_EDIT, label: 'Edit Accounts' },
|
||||
{ key: CAPABILITIES.FINANCIALS_CASHFLOW_VIEW, label: 'View Cash Flow' },
|
||||
{ key: CAPABILITIES.FINANCIALS_CASHFLOW_EDIT, label: 'Edit Cash Flow' },
|
||||
{ key: CAPABILITIES.FINANCIALS_ACTUALS_VIEW, label: 'View Monthly Actuals' },
|
||||
{ key: CAPABILITIES.FINANCIALS_ACTUALS_EDIT, label: 'Edit Monthly Actuals' },
|
||||
{ key: CAPABILITIES.FINANCIALS_BUDGETS_VIEW, label: 'View Budgets' },
|
||||
{ key: CAPABILITIES.FINANCIALS_BUDGETS_EDIT, label: 'Edit Budgets' },
|
||||
{ key: CAPABILITIES.FINANCIALS_BUDGETS_APPROVE, label: 'Approve Budgets' },
|
||||
],
|
||||
},
|
||||
{
|
||||
label: 'Assessments',
|
||||
capabilities: [
|
||||
{ key: CAPABILITIES.ASSESSMENTS_UNITS_VIEW, label: 'View Units' },
|
||||
{ key: CAPABILITIES.ASSESSMENTS_UNITS_EDIT, label: 'Edit Units' },
|
||||
{ key: CAPABILITIES.ASSESSMENTS_GROUPS_VIEW, label: 'View Assessment Groups' },
|
||||
{ key: CAPABILITIES.ASSESSMENTS_GROUPS_EDIT, label: 'Edit Assessment Groups' },
|
||||
],
|
||||
},
|
||||
{
|
||||
label: 'Board Planning',
|
||||
capabilities: [
|
||||
{ key: CAPABILITIES.PLANNING_BUDGETS_VIEW, label: 'View Budget Planning' },
|
||||
{ key: CAPABILITIES.PLANNING_BUDGETS_EDIT, label: 'Edit Budget Planning' },
|
||||
{ key: CAPABILITIES.PLANNING_PROJECTS_VIEW, label: 'View Projects' },
|
||||
{ key: CAPABILITIES.PLANNING_PROJECTS_EDIT, label: 'Edit Projects' },
|
||||
{ key: CAPABILITIES.PLANNING_SCENARIOS_VIEW, label: 'View Scenarios' },
|
||||
{ key: CAPABILITIES.PLANNING_SCENARIOS_EDIT, label: 'Edit Scenarios' },
|
||||
{ key: CAPABILITIES.PLANNING_SCENARIOS_APPROVE, label: 'Approve Scenarios' },
|
||||
{ key: CAPABILITIES.PLANNING_INVESTMENTS_VIEW, label: 'View Investments' },
|
||||
{ key: CAPABILITIES.PLANNING_INVESTMENTS_EDIT, label: 'Edit Investments' },
|
||||
],
|
||||
},
|
||||
{
|
||||
label: 'Board Reference',
|
||||
capabilities: [
|
||||
{ key: CAPABILITIES.REFERENCE_VENDORS_VIEW, label: 'View Vendors' },
|
||||
{ key: CAPABILITIES.REFERENCE_VENDORS_EDIT, label: 'Edit Vendors' },
|
||||
],
|
||||
},
|
||||
{
|
||||
label: 'Transactions',
|
||||
capabilities: [
|
||||
{ key: CAPABILITIES.TRANSACTIONS_VIEW, label: 'View Transactions' },
|
||||
{ key: CAPABILITIES.TRANSACTIONS_EDIT, label: 'Edit Transactions' },
|
||||
{ key: CAPABILITIES.TRANSACTIONS_APPROVE, label: 'Approve Transactions' },
|
||||
],
|
||||
},
|
||||
{
|
||||
label: 'Reports',
|
||||
capabilities: [
|
||||
{ key: CAPABILITIES.REPORTS_VIEW, label: 'View Reports' },
|
||||
],
|
||||
},
|
||||
{
|
||||
label: 'Administration',
|
||||
capabilities: [
|
||||
{ key: CAPABILITIES.SETTINGS_ORG_VIEW, label: 'View Org Settings' },
|
||||
{ key: CAPABILITIES.SETTINGS_ORG_EDIT, label: 'Edit Org Settings' },
|
||||
{ key: CAPABILITIES.SETTINGS_MEMBERS_VIEW, label: 'View Members' },
|
||||
{ key: CAPABILITIES.SETTINGS_MEMBERS_MANAGE, label: 'Manage Members' },
|
||||
{ key: CAPABILITIES.SETTINGS_PERMISSIONS_MANAGE, label: 'Manage Permissions' },
|
||||
],
|
||||
},
|
||||
];
|
||||
Reference in New Issue
Block a user