Music Store Management Platform Permissions & Role-Based Access Control Version 1.0 | Draft # 1. Overview The platform uses a permission-based access control system. Permissions are granular actions (view accounts, edit inventory, approve tax exemptions). Roles are named collections of permissions. Stores can create custom roles by selecting which permissions to include. The system ships with default roles that cover common staff configurations. # 2. Permission Structure Each permission follows the pattern: `{domain}.{action}` ## 2.1 Actions Action | Description view | Read-only access — list, search, view detail edit | Create, update, soft-delete admin | Full control — includes configuration, approval workflows, destructive actions manage | Alias for edit + admin (shorthand for full domain control) ## 2.2 Domains & Permissions Domain | Permissions | Description accounts | accounts.view, accounts.edit, accounts.admin | Customer accounts, members, payment methods inventory | inventory.view, inventory.edit, inventory.admin | Products, categories, suppliers, stock pos | pos.view, pos.edit, pos.admin | Transactions, cash drawer, discounts rentals | rentals.view, rentals.edit, rentals.admin | Rental contracts, fleet, billing lessons | lessons.view, lessons.edit, lessons.admin | Scheduling, enrollment, attendance repairs | repairs.view, repairs.edit, repairs.admin | Repair tickets, parts, labor accounting | accounting.view, accounting.edit, accounting.admin | Journal entries, chart of accounts, reports personnel | personnel.view, personnel.edit, personnel.admin | Time clock, scheduling, payroll files | files.view, files.upload, files.delete | File storage operations email | email.view, email.send, email.admin | Email logs, send mass email, manage templates settings | settings.view, settings.edit | Store settings, locations, tax rates users | users.view, users.edit, users.admin | User accounts, roles, permissions reports | reports.view, reports.export | View reports, export data # 3. What Each Action Controls ## 3.1 accounts Permission | Allows accounts.view | List/search accounts, view account detail, view members, view payment methods, view tax exemptions accounts.edit | Create/update accounts, add/edit/move members, add payment methods, create tax exemption requests accounts.admin | Delete accounts, delete members, approve/revoke tax exemptions, set primary member, manage identifiers ## 3.2 inventory Permission | Allows inventory.view | List/search products, view detail, view stock levels, view categories/suppliers inventory.edit | Create/update products, receive stock, update inventory units, manage categories/suppliers inventory.admin | Delete products, adjust stock (cycle counts), manage lookup values (custom statuses/conditions), bulk operations ## 3.3 pos Permission | Allows pos.view | View transaction history, view cash drawer sessions pos.edit | Process sales, take payments, apply discounts (within threshold), open/close drawer pos.admin | Void transactions, override prices below min_price, apply discounts above threshold, manage discount rules ## 3.4 rentals Permission | Allows rentals.view | View rental contracts, fleet inventory, billing history rentals.edit | Create rentals, process returns, manage fleet, generate agreements rentals.admin | Override rental terms, adjust equity, cancel contracts, approve buyouts ## 3.5 repairs Permission | Allows repairs.view | View repair tickets, parts inventory, technician assignments repairs.edit | Create tickets, log parts/labor, update status, manage repair parts inventory repairs.admin | Override estimates, adjust billing, manage repair templates, delete tickets ## 3.6 files Permission | Allows files.view | View/download files files.upload | Upload files files.delete | Delete files ## 3.7 users Permission | Allows users.view | List users, view roles users.edit | Create/update users, assign roles users.admin | Create/modify roles, manage permissions, delete users # 4. Database Schema ## 4.1 permission System-defined. Seeded on first run. Not editable by stores. Column | Type | Notes id | uuid PK | slug | varchar | Unique. e.g. accounts.view, pos.edit domain | varchar | e.g. accounts, pos, inventory action | varchar | e.g. view, edit, admin description | varchar | Human-readable description created_at | timestamptz | ## 4.2 role Store-defined roles. System provides defaults, stores can create custom. Column | Type | Notes id | uuid PK | company_id | uuid FK | Tenant scoping name | varchar | Role display name. e.g. "Sales Associate", "Repair Tech" slug | varchar | Unique per company. e.g. sales_associate description | text | is_system | boolean | System roles can't be deleted (admin, manager, staff, technician, instructor) is_active | boolean | created_at | timestamptz | updated_at | timestamptz | ## 4.3 role_permission Many-to-many: which permissions a role has. Column | Type | Notes id | uuid PK | role_id | uuid FK | permission_id | uuid FK | created_at | timestamptz | Unique constraint on (role_id, permission_id). ## 4.4 user_role Replaces the current `role` enum on the user table. Users can have multiple roles. Column | Type | Notes id | uuid PK | user_id | uuid FK | role_id | uuid FK | assigned_by | uuid FK | Who assigned this role created_at | timestamptz | Unique constraint on (user_id, role_id). # 5. Default Roles ## 5.1 System Roles (seeded per company) Role | Permissions | Typical User Admin | All permissions | Store owner, IT admin Manager | All except users.admin, settings.edit | Assistant manager, department head Sales Associate | accounts.view, accounts.edit, pos.view, pos.edit, inventory.view, rentals.view, files.view, files.upload | Front counter staff Technician | repairs.view, repairs.edit, inventory.view, files.view, files.upload | Repair technician Instructor | lessons.view, lessons.edit, accounts.view | Music teacher Viewer | *.view (all view permissions) | Read-only access, auditors ## 5.2 Custom Role Example A store could create: **"School Sales Rep"** - accounts.view, accounts.edit - rentals.view, rentals.edit - pos.view, pos.edit - inventory.view This gives them everything they need to work with school accounts and rental contracts without access to repairs, lessons, or admin functions. # 6. Permission Checking ## 6.1 API Route Guards ```typescript // Single permission app.get('/accounts', { preHandler: [app.authenticate, app.requirePermission('accounts.view')] }, handler) // Any of multiple permissions app.post('/transactions', { preHandler: [app.authenticate, app.requirePermission('pos.edit')] }, handler) // Admin-level action app.post('/tax-exemptions/:id/approve', { preHandler: [app.authenticate, app.requirePermission('accounts.admin')] }, handler) ``` ## 6.2 Frontend Guards ```typescript // Route level { beforeLoad: () => requirePermission('accounts.view'), component: AccountsList, } // Component level {hasPermission('accounts.edit') && } ``` ## 6.3 Resolution When checking a permission: 1. Get all roles assigned to the user 2. Get all permissions for those roles 3. Check if the required permission is in the set 4. Cache the permission set in memory for the request duration (loaded on auth) # 7. Migration Plan ## 7.1 Current State The `user` table has a `role` enum column with values: admin, manager, staff, technician, instructor. This is checked via `app.requireRole()` in a few places. ## 7.2 Migration Steps 1. Create permission, role, role_permission, user_role tables 2. Seed system permissions (all domain.action combinations) 3. Seed default roles with their permission mappings 4. Migrate existing users: map current `role` enum to the equivalent new role 5. Add `app.requirePermission()` decorator alongside existing `app.requireRole()` 6. Gradually replace `requireRole()` calls with `requirePermission()` in routes 7. Drop the `role` enum column from user table (after full migration) 8. Update frontend to check permissions instead of roles ## 7.3 Backward Compatibility During migration, both `requireRole()` and `requirePermission()` work. The JWT payload includes both `role` (legacy) and `permissions` (new array of slugs). Once all routes are migrated, the legacy role field can be removed. # 8. Admin UI ## 8.1 Roles Page - List all roles (system + custom) - Create custom role: name, description, select permissions via checkboxes grouped by domain - Edit custom role permissions - View which users are assigned to each role - System roles show as locked (can't delete, can edit description) ## 8.2 User Management - Assign/remove roles from users - View effective permissions for a user (union of all role permissions) - Quick-assign: dropdown of available roles when creating/editing a user # 9. Business Rules - Every user must have at least one role - Admin role cannot be removed from the last admin user in a company - System roles can be customized (add/remove permissions) but not deleted - Custom roles are company-scoped - Permission checks are additive — if any assigned role has the permission, the user has it - New permissions added in updates are automatically added to the Admin role - Role changes take effect on next login (JWT refresh) - Audit log records all role assignments and permission changes