Files
orion/app/modules/registry.py
Samir Boulahtit 1a52611438 feat: implement three-tier module classification and framework layer
Module Classification:
- Core (4): core, tenancy, cms, customers - always enabled
- Optional (7): payments, billing, inventory, orders, marketplace, analytics, messaging
- Internal (2): dev-tools, monitoring - admin-only

Key Changes:
- Rename platform-admin module to tenancy
- Promote CMS and Customers to core modules
- Create new payments module (gateway abstractions)
- Add billing→payments and orders→payments dependencies
- Mark dev-tools and monitoring as internal modules

New Infrastructure:
- app/modules/events.py: Module event bus (ENABLED, DISABLED, STARTUP, SHUTDOWN)
- app/modules/migrations.py: Module-specific migration discovery
- app/core/observability.py: Health checks, Prometheus metrics, Sentry integration

Enhanced ModuleDefinition:
- version, is_internal, permissions
- config_schema, default_config
- migrations_path
- Lifecycle hooks: on_enable, on_disable, on_startup, health_check

New Registry Functions:
- get_optional_module_codes(), get_internal_module_codes()
- is_core_module(), is_internal_module()
- get_modules_by_tier(), get_module_tier()

Migrations:
- zc*: Rename platform-admin to tenancy
- zd*: Ensure CMS and Customers enabled for all platforms

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-27 22:02:39 +01:00

341 lines
10 KiB
Python

# app/modules/registry.py
"""
Module registry defining all available platform modules.
The module system uses a three-tier classification:
1. CORE MODULES (4) - Always enabled, cannot be disabled
- core: Dashboard, settings, profile
- tenancy: Platform, company, vendor, admin user management
- cms: Content pages, media library, themes
- customers: Customer database, profiles, segmentation
2. OPTIONAL MODULES (7) - Can be enabled/disabled per platform
- payments: Payment gateway integrations (Stripe, PayPal, etc.)
- billing: Platform subscriptions, vendor invoices (requires: payments)
- inventory: Stock management, locations
- orders: Order management, customer checkout (requires: payments)
- marketplace: Letzshop integration (requires: inventory)
- analytics: Reports, dashboards
- messaging: Messages, notifications
3. INTERNAL MODULES (2) - Admin-only tools, not customer-facing
- dev-tools: Component library, icons
- monitoring: Logs, background tasks, Flower link, Grafana dashboards
Module Structure:
- Inline modules: Defined directly in this file (core, tenancy)
- 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.payments.definition import payments_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
# =============================================================================
# Core Modules (Always Enabled, Cannot Be Disabled)
# =============================================================================
CORE_MODULES: dict[str, ModuleDefinition] = {
"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",
],
},
),
"tenancy": ModuleDefinition(
code="tenancy",
name="Tenancy Management",
description="Platform, company, vendor, and admin user management. Required for multi-tenant operation.",
is_core=True,
features=[
"platform_management",
"company_management",
"vendor_management",
"admin_user_management",
],
menu_items={
FrontendType.ADMIN: [
"platforms",
"companies",
"vendors",
"admin-users",
],
FrontendType.VENDOR: [
"team",
],
},
),
# CMS module - imported from app/modules/cms/
"cms": cms_module,
# Customers module - imported from app/modules/customers/
"customers": customers_module,
}
# =============================================================================
# Optional Modules (Can Be Enabled/Disabled Per Platform)
# =============================================================================
OPTIONAL_MODULES: dict[str, ModuleDefinition] = {
# Payments module - imported from app/modules/payments/
# Gateway integrations (Stripe, PayPal, etc.)
"payments": payments_module,
# Billing module - imported from app/modules/billing/
# Platform subscriptions, vendor invoices (requires: payments)
"billing": billing_module,
# Inventory module - imported from app/modules/inventory/
"inventory": inventory_module,
# Orders module - imported from app/modules/orders/
# Order management, customer checkout (requires: payments)
"orders": orders_module,
# Marketplace module - imported from app/modules/marketplace/
# Letzshop integration (requires: inventory)
"marketplace": marketplace_module,
# Analytics module - imported from app/modules/analytics/
"analytics": analytics_module,
# Messaging module - imported from app/modules/messaging/
"messaging": messaging_module,
}
# =============================================================================
# Internal Modules (Admin-Only, Not Customer-Facing)
# =============================================================================
INTERNAL_MODULES: dict[str, ModuleDefinition] = {
# Dev-Tools module - imported from app/modules/dev_tools/
"dev-tools": dev_tools_module,
# Monitoring module - imported from app/modules/monitoring/
"monitoring": monitoring_module,
}
# =============================================================================
# Combined Module Registry
# =============================================================================
MODULES: dict[str, ModuleDefinition] = {
**CORE_MODULES,
**OPTIONAL_MODULES,
**INTERNAL_MODULES,
}
# =============================================================================
# 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 list(CORE_MODULES.values())
def get_core_module_codes() -> set[str]:
"""Get codes of all core modules."""
return set(CORE_MODULES.keys())
def get_optional_modules() -> list[ModuleDefinition]:
"""Get all optional modules (can be enabled/disabled)."""
return list(OPTIONAL_MODULES.values())
def get_optional_module_codes() -> set[str]:
"""Get codes of all optional modules."""
return set(OPTIONAL_MODULES.keys())
def get_internal_modules() -> list[ModuleDefinition]:
"""Get all internal modules (admin-only tools)."""
return list(INTERNAL_MODULES.values())
def get_internal_module_codes() -> set[str]:
"""Get codes of all internal modules."""
return set(INTERNAL_MODULES.keys())
def get_all_module_codes() -> set[str]:
"""Get all module codes."""
return set(MODULES.keys())
def is_core_module(code: str) -> bool:
"""Check if a module is a core module."""
return code in CORE_MODULES
def is_internal_module(code: str) -> bool:
"""Check if a module is an internal module."""
return code in INTERNAL_MODULES
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
def get_modules_by_tier() -> dict[str, list[ModuleDefinition]]:
"""
Get modules organized by tier.
Returns:
Dict with keys 'core', 'optional', 'internal' mapping to module lists
"""
return {
"core": list(CORE_MODULES.values()),
"optional": list(OPTIONAL_MODULES.values()),
"internal": list(INTERNAL_MODULES.values()),
}
def get_module_tier(code: str) -> str | None:
"""
Get the tier classification of a module.
Args:
code: Module code
Returns:
'core', 'optional', 'internal', or None if not found
"""
if code in CORE_MODULES:
return "core"
elif code in OPTIONAL_MODULES:
return "optional"
elif code in INTERNAL_MODULES:
return "internal"
return None
# 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__ = [
# Module dictionaries
"MODULES",
"CORE_MODULES",
"OPTIONAL_MODULES",
"INTERNAL_MODULES",
# Module retrieval
"get_module",
"get_core_modules",
"get_core_module_codes",
"get_optional_modules",
"get_optional_module_codes",
"get_internal_modules",
"get_internal_module_codes",
"get_all_module_codes",
# Module classification
"is_core_module",
"is_internal_module",
"get_modules_by_tier",
"get_module_tier",
# Menu and feature lookup
"get_menu_item_module",
"get_feature_module",
# Validation
"validate_module_dependencies",
]