Add RBAC (Role-Based Access Control) system - Phase 1

Implemented comprehensive role-based permission management system:

Database:
- Added m004_add_rbac_tables migration
- roles table: Define named permission bundles (Employee, Contractor, etc.)
- role_permissions table: Map roles to account permissions
- user_roles table: Assign users to roles with optional expiration
- Created 4 default roles: Employee (default), Contractor, Accountant, Manager

Models (models.py):
- Role, CreateRole, UpdateRole
- RolePermission, CreateRolePermission
- UserRole, AssignUserRole
- RoleWithPermissions, UserWithRoles

CRUD Operations (crud.py):
- Role management: create_role, get_role, get_all_roles, update_role, delete_role
- get_default_role() - get auto-assigned role for new users
- Role permissions: create_role_permission, get_role_permissions, delete_role_permission
- User role assignment: assign_user_role, get_user_roles, revoke_user_role
- Helper functions:
  - get_user_permissions_from_roles() - resolve user permissions via roles
  - check_user_has_role_permission() - check role-based access
  - auto_assign_default_role() - auto-assign default role to new users

Permission Resolution Order:
1. Individual account_permissions (direct grants/exceptions)
2. Role-based permissions (via user_roles → role_permissions)
3. Inherited permissions (hierarchical account names)
4. Deny by default

Next: API endpoints, UI, and permission resolution logic integration

🤖 Generated with Claude Code
This commit is contained in:
padreug 2025-11-11 23:34:28 +01:00
parent 142b26d7da
commit 46e910ba25
3 changed files with 679 additions and 0 deletions

View file

@ -352,3 +352,81 @@ class AccountWithPermissions(BaseModel):
parent_account: Optional[str] = None # Parent account name
level: Optional[int] = None # Depth in hierarchy (0 = top level)
has_children: Optional[bool] = None # Whether this account has sub-accounts
# ===== ROLE-BASED ACCESS CONTROL (RBAC) MODELS =====
class Role(BaseModel):
"""Role definition for RBAC system"""
id: str
name: str # Display name (e.g., "Employee", "Contractor")
description: Optional[str] = None
is_default: bool = False # Auto-assign this role to new users
created_by: str # User ID who created the role
created_at: datetime
class CreateRole(BaseModel):
"""Create a new role"""
name: str
description: Optional[str] = None
is_default: bool = False
class UpdateRole(BaseModel):
"""Update an existing role"""
name: Optional[str] = None
description: Optional[str] = None
is_default: Optional[bool] = None
class RolePermission(BaseModel):
"""Permission granted to a role for a specific account"""
id: str
role_id: str
account_id: str
permission_type: PermissionType
notes: Optional[str] = None
created_at: datetime
class CreateRolePermission(BaseModel):
"""Create a permission for a role"""
role_id: str
account_id: str
permission_type: PermissionType
notes: Optional[str] = None
class UserRole(BaseModel):
"""Assignment of a user to a role"""
id: str
user_id: str # User's wallet ID
role_id: str
granted_by: str # Admin who assigned the role
granted_at: datetime
expires_at: Optional[datetime] = None
notes: Optional[str] = None
class AssignUserRole(BaseModel):
"""Assign a user to a role"""
user_id: str
role_id: str
expires_at: Optional[datetime] = None
notes: Optional[str] = None
class RoleWithPermissions(BaseModel):
"""Role with its associated permissions and user count"""
role: Role
permissions: list[RolePermission]
user_count: int # Number of users assigned to this role
class UserWithRoles(BaseModel):
"""User information with their assigned roles"""
user_id: str
roles: list[Role]
direct_permissions: list[AccountPermission] # Individual permissions not from roles