# /opt/docker/dev/service_finder/backend/app/models/system/rbac.py """ RBAC Phase 1: Database-Driven Role-Based Access Control models. These models replace the hardcoded SYSTEM_CAPABILITIES_MATRIX and UserRole enum with fully database-driven roles, permissions, and role-permission mappings. Schema: system Tables: - system.roles - system.permissions - system.role_permissions """ from __future__ import annotations from datetime import datetime from typing import Optional, List, TYPE_CHECKING from sqlalchemy import String, Integer, Boolean, DateTime, ForeignKey, Text, UniqueConstraint from sqlalchemy.orm import Mapped, mapped_column, relationship from sqlalchemy.sql import func from app.database import Base if TYPE_CHECKING: pass class SystemRole(Base): """ System-level roles for the entire platform. Replaces the hardcoded UserRole enum. Each role has a hierarchical rank (100=SUPERADMIN, 0=USER) for quick privilege comparisons. System roles are protected (is_system=True) and cannot be deleted via admin UI. """ __tablename__ = "roles" __table_args__ = ( {"schema": "system", "extend_existing": True} ) id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) name: Mapped[str] = mapped_column(String(50), unique=True, nullable=False, index=True) description: Mapped[Optional[str]] = mapped_column(Text, nullable=True) rank: Mapped[int] = mapped_column(Integer, default=0, nullable=False) is_system: Mapped[bool] = mapped_column(Boolean, default=True, nullable=False) is_active: Mapped[bool] = mapped_column(Boolean, default=True, nullable=False) created_at: Mapped[datetime] = mapped_column( DateTime(timezone=True), server_default=func.now(), nullable=False ) updated_at: Mapped[Optional[datetime]] = mapped_column( DateTime(timezone=True), onupdate=func.now(), nullable=True ) # --- RELATIONSHIPS --- permissions: Mapped[List["SystemRolePermission"]] = relationship( "SystemRolePermission", back_populates="role", cascade="all, delete-orphan" ) def __repr__(self) -> str: return f"" class SystemPermission(Base): """ Granular permission codes for the entire platform. Format: domain:action (e.g., fleet:view, user:create, finance:approve) Domains: fleet, user, finance, system, org, reports, audit, settings Actions: view, create, edit, delete, approve, manage, export, refund, manage-roles """ __tablename__ = "permissions" __table_args__ = ( {"schema": "system", "extend_existing": True} ) id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) code: Mapped[str] = mapped_column(String(100), unique=True, nullable=False, index=True) domain: Mapped[str] = mapped_column(String(50), nullable=False, index=True) action: Mapped[str] = mapped_column(String(50), nullable=False) description: Mapped[Optional[str]] = mapped_column(Text, nullable=True) is_system: Mapped[bool] = mapped_column(Boolean, default=True, nullable=False) created_at: Mapped[datetime] = mapped_column( DateTime(timezone=True), server_default=func.now(), nullable=False ) # --- RELATIONSHIPS --- role_assignments: Mapped[List["SystemRolePermission"]] = relationship( "SystemRolePermission", back_populates="permission", cascade="all, delete-orphan" ) def __repr__(self) -> str: return f"" class SystemRolePermission(Base): """ Many-to-many mapping between roles and permissions with explicit grant/deny. The `granted` boolean allows explicit denial of a permission for a role, which can override inherited permissions in hierarchical role structures. """ __tablename__ = "role_permissions" __table_args__ = ( UniqueConstraint("role_id", "permission_id", name="uix_role_permission"), {"schema": "system", "extend_existing": True} ) id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) role_id: Mapped[int] = mapped_column( Integer, ForeignKey("system.roles.id", ondelete="CASCADE"), nullable=False ) permission_id: Mapped[int] = mapped_column( Integer, ForeignKey("system.permissions.id", ondelete="CASCADE"), nullable=False ) granted: Mapped[bool] = mapped_column(Boolean, default=True, nullable=False) created_at: Mapped[datetime] = mapped_column( DateTime(timezone=True), server_default=func.now(), nullable=False ) # --- RELATIONSHIPS --- role: Mapped["SystemRole"] = relationship("SystemRole", back_populates="permissions") permission: Mapped["SystemPermission"] = relationship( "SystemPermission", back_populates="role_assignments" ) def __repr__(self) -> str: return ( f"" )