Phase 1 - Vendor Router Integration: - Wire up vendor module routers in app/api/v1/vendor/__init__.py - Use lazy imports via __getattr__ to avoid circular dependencies Phase 2 - Extract Remaining Modules: - Create 6 new module directories: customers, cms, analytics, messaging, dev_tools, monitoring - Each module has definition.py and route wrappers - Update registry to import from extracted modules Phase 3 - Database Table Migration: - Add PlatformModule junction table for auditable module tracking - Add migration zc2m3n4o5p6q7_add_platform_modules_table.py - Add modules relationship to Platform model - Update ModuleService with JSON-to-junction-table migration Phase 4 - Module-Specific Configuration UI: - Add /api/v1/admin/module-config/* endpoints - Add module-config.html template and JS Phase 5 - Integration Tests: - Add tests/fixtures/module_fixtures.py - Add tests/integration/api/v1/admin/test_modules.py - Add tests/integration/api/v1/modules/test_module_access.py Architecture fixes: - Fix JS-003 errors: use ...data() directly in Alpine components - Fix JS-005 warnings: add init() guards to prevent duplicate init - Fix API-001 errors: add MenuActionResponse Pydantic model - Add FE-008 noqa for dynamic number input in template Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
225 lines
7.1 KiB
Python
225 lines
7.1 KiB
Python
# app/modules/registry.py
|
|
"""
|
|
Module registry defining all available platform modules.
|
|
|
|
Each module bundles related features and menu items that can be
|
|
enabled/disabled per platform. Core modules cannot be disabled.
|
|
|
|
Module Granularity (Medium - ~12 modules):
|
|
Matches menu sections for intuitive mapping between modules and UI.
|
|
|
|
Module Structure:
|
|
- Inline modules: Defined directly in this file (core, platform-admin, etc.)
|
|
- Extracted modules: Imported from app/modules/{module}/ (billing, etc.)
|
|
|
|
As modules are extracted to their own directories, they are imported
|
|
here and their inline definitions are replaced.
|
|
"""
|
|
|
|
from app.modules.base import ModuleDefinition
|
|
from models.database.admin_menu_config import FrontendType
|
|
|
|
# Import extracted modules
|
|
from app.modules.billing.definition import billing_module
|
|
from app.modules.inventory.definition import inventory_module
|
|
from app.modules.marketplace.definition import marketplace_module
|
|
from app.modules.orders.definition import orders_module
|
|
from app.modules.customers.definition import customers_module
|
|
from app.modules.cms.definition import cms_module
|
|
from app.modules.analytics.definition import analytics_module
|
|
from app.modules.messaging.definition import messaging_module
|
|
from app.modules.dev_tools.definition import dev_tools_module
|
|
from app.modules.monitoring.definition import monitoring_module
|
|
|
|
|
|
# =============================================================================
|
|
# Module Definitions
|
|
# =============================================================================
|
|
|
|
MODULES: dict[str, ModuleDefinition] = {
|
|
# =========================================================================
|
|
# Core Modules (Always Enabled)
|
|
# =========================================================================
|
|
"core": ModuleDefinition(
|
|
code="core",
|
|
name="Core Platform",
|
|
description="Dashboard, settings, and profile management. Required for basic operation.",
|
|
is_core=True,
|
|
features=[
|
|
"dashboard",
|
|
"settings",
|
|
"profile",
|
|
],
|
|
menu_items={
|
|
FrontendType.ADMIN: [
|
|
"dashboard",
|
|
"settings",
|
|
"email-templates",
|
|
"my-menu",
|
|
],
|
|
FrontendType.VENDOR: [
|
|
"dashboard",
|
|
"profile",
|
|
"settings",
|
|
"email-templates",
|
|
],
|
|
},
|
|
),
|
|
"platform-admin": ModuleDefinition(
|
|
code="platform-admin",
|
|
name="Platform Administration",
|
|
description="Company, vendor, and admin user management. Required for multi-tenant operation.",
|
|
is_core=True,
|
|
features=[
|
|
"company_management",
|
|
"vendor_management",
|
|
"admin_user_management",
|
|
"platform_management",
|
|
],
|
|
menu_items={
|
|
FrontendType.ADMIN: [
|
|
"admin-users",
|
|
"companies",
|
|
"vendors",
|
|
"platforms",
|
|
],
|
|
FrontendType.VENDOR: [
|
|
"team",
|
|
],
|
|
},
|
|
),
|
|
# =========================================================================
|
|
# Optional Modules
|
|
# =========================================================================
|
|
# Billing module - imported from app/modules/billing/
|
|
"billing": billing_module,
|
|
# Inventory module - imported from app/modules/inventory/
|
|
"inventory": inventory_module,
|
|
# Orders module - imported from app/modules/orders/
|
|
"orders": orders_module,
|
|
# Marketplace module - imported from app/modules/marketplace/
|
|
"marketplace": marketplace_module,
|
|
# Customers module - imported from app/modules/customers/
|
|
"customers": customers_module,
|
|
# CMS module - imported from app/modules/cms/
|
|
"cms": cms_module,
|
|
# Analytics module - imported from app/modules/analytics/
|
|
"analytics": analytics_module,
|
|
# Messaging module - imported from app/modules/messaging/
|
|
"messaging": messaging_module,
|
|
# Dev-Tools module - imported from app/modules/dev_tools/
|
|
"dev-tools": dev_tools_module,
|
|
# Monitoring module - imported from app/modules/monitoring/
|
|
"monitoring": monitoring_module,
|
|
}
|
|
|
|
|
|
# =============================================================================
|
|
# Helper Functions
|
|
# =============================================================================
|
|
|
|
|
|
def get_module(code: str) -> ModuleDefinition | None:
|
|
"""Get a module definition by code."""
|
|
return MODULES.get(code)
|
|
|
|
|
|
def get_core_modules() -> list[ModuleDefinition]:
|
|
"""Get all core modules (cannot be disabled)."""
|
|
return [m for m in MODULES.values() if m.is_core]
|
|
|
|
|
|
def get_core_module_codes() -> set[str]:
|
|
"""Get codes of all core modules."""
|
|
return {m.code for m in MODULES.values() if m.is_core}
|
|
|
|
|
|
def get_optional_modules() -> list[ModuleDefinition]:
|
|
"""Get all optional modules (can be enabled/disabled)."""
|
|
return [m for m in MODULES.values() if not m.is_core]
|
|
|
|
|
|
def get_all_module_codes() -> set[str]:
|
|
"""Get all module codes."""
|
|
return set(MODULES.keys())
|
|
|
|
|
|
def get_menu_item_module(menu_item_id: str, frontend_type: FrontendType) -> str | None:
|
|
"""
|
|
Find which module provides a specific menu item.
|
|
|
|
Args:
|
|
menu_item_id: The menu item ID to find
|
|
frontend_type: The frontend type to search in
|
|
|
|
Returns:
|
|
Module code if found, None otherwise
|
|
"""
|
|
for module in MODULES.values():
|
|
if menu_item_id in module.get_menu_items(frontend_type):
|
|
return module.code
|
|
return None
|
|
|
|
|
|
def get_feature_module(feature_code: str) -> str | None:
|
|
"""
|
|
Find which module provides a specific feature.
|
|
|
|
Args:
|
|
feature_code: The feature code to find
|
|
|
|
Returns:
|
|
Module code if found, None otherwise
|
|
"""
|
|
for module in MODULES.values():
|
|
if module.has_feature(feature_code):
|
|
return module.code
|
|
return None
|
|
|
|
|
|
def validate_module_dependencies() -> list[str]:
|
|
"""
|
|
Validate that all module dependencies are valid.
|
|
|
|
Returns:
|
|
List of error messages for invalid dependencies
|
|
"""
|
|
errors = []
|
|
all_codes = get_all_module_codes()
|
|
|
|
for module in MODULES.values():
|
|
for required in module.requires:
|
|
if required not in all_codes:
|
|
errors.append(
|
|
f"Module '{module.code}' requires unknown module '{required}'"
|
|
)
|
|
# Core modules should not depend on optional modules
|
|
if module.is_core and required not in get_core_module_codes():
|
|
errors.append(
|
|
f"Core module '{module.code}' depends on optional module '{required}'"
|
|
)
|
|
|
|
return errors
|
|
|
|
|
|
# Validate dependencies on import (development check)
|
|
_validation_errors = validate_module_dependencies()
|
|
if _validation_errors:
|
|
import warnings
|
|
|
|
for error in _validation_errors:
|
|
warnings.warn(f"Module registry validation: {error}", stacklevel=2)
|
|
|
|
|
|
__all__ = [
|
|
"MODULES",
|
|
"get_module",
|
|
"get_core_modules",
|
|
"get_core_module_codes",
|
|
"get_optional_modules",
|
|
"get_all_module_codes",
|
|
"get_menu_item_module",
|
|
"get_feature_module",
|
|
"validate_module_dependencies",
|
|
]
|