refactor: implement module-driven permissions and relocate business logic
File Relocations: - Delete app/config/ folder (empty after menu_registry removal) - Move feature_gate.py → app/modules/billing/dependencies/ - Move theme_presets.py → app/modules/cms/services/ Module-Driven Permissions System: - Add PermissionDefinition dataclass to app/modules/base.py - Create PermissionDiscoveryService in tenancy module - Update module definitions to declare their own permissions: - core: dashboard.view, settings.* - catalog: products.* - orders: orders.* - inventory: stock.* - customers: customers.* - tenancy: team.* - Update app/core/permissions.py to use discovery service - Role presets (owner, manager, staff, etc.) now use module permissions This follows the same pattern as module-driven menus: - Each module defines its permissions in definition.py - PermissionDiscoveryService aggregates all permissions at runtime - Tenancy module handles role-to-permission assignment Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -134,6 +134,48 @@ class MenuSectionDefinition:
|
||||
is_collapsible: bool = True
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# Permission Definitions
|
||||
# =============================================================================
|
||||
|
||||
|
||||
@dataclass
|
||||
class PermissionDefinition:
|
||||
"""
|
||||
Definition of a permission that a module exposes.
|
||||
|
||||
Permissions are granular capabilities that can be assigned to roles/users.
|
||||
Each module defines its own permissions, which are then discovered and
|
||||
aggregated by the tenancy module for role assignment.
|
||||
|
||||
Attributes:
|
||||
id: Unique identifier in format "resource.action" (e.g., "products.view")
|
||||
label_key: i18n key for the permission label
|
||||
description_key: i18n key for permission description
|
||||
category: Grouping category for UI organization (e.g., "products", "orders")
|
||||
is_owner_only: If True, only vendor owners can have this permission
|
||||
|
||||
Example:
|
||||
PermissionDefinition(
|
||||
id="products.view",
|
||||
label_key="catalog.permissions.products_view",
|
||||
description_key="catalog.permissions.products_view_desc",
|
||||
category="products",
|
||||
)
|
||||
"""
|
||||
|
||||
id: str
|
||||
label_key: str
|
||||
description_key: str = ""
|
||||
category: str = "general"
|
||||
is_owner_only: bool = False
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# Scheduled Task Definitions
|
||||
# =============================================================================
|
||||
|
||||
|
||||
@dataclass
|
||||
class ScheduledTask:
|
||||
"""
|
||||
@@ -275,7 +317,7 @@ class ModuleDefinition:
|
||||
# =========================================================================
|
||||
features: list[str] = field(default_factory=list)
|
||||
menu_items: dict[FrontendType, list[str]] = field(default_factory=dict)
|
||||
permissions: list[str] = field(default_factory=list)
|
||||
permissions: list[PermissionDefinition] = field(default_factory=list)
|
||||
|
||||
# =========================================================================
|
||||
# Menu Definitions (Module-Driven Menus)
|
||||
@@ -400,9 +442,13 @@ class ModuleDefinition:
|
||||
"""Check if this module provides a specific feature."""
|
||||
return feature_code in self.features
|
||||
|
||||
def has_permission(self, permission_code: str) -> bool:
|
||||
def has_permission(self, permission_id: str) -> bool:
|
||||
"""Check if this module defines a specific permission."""
|
||||
return permission_code in self.permissions
|
||||
return any(p.id == permission_id for p in self.permissions)
|
||||
|
||||
def get_permission_ids(self) -> set[str]:
|
||||
"""Get all permission IDs defined by this module."""
|
||||
return {p.id for p in self.permissions}
|
||||
|
||||
# =========================================================================
|
||||
# Dependency Methods
|
||||
|
||||
Reference in New Issue
Block a user