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>
This commit is contained in:
@@ -2,14 +2,29 @@
|
||||
"""
|
||||
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.
|
||||
The module system uses a three-tier classification:
|
||||
|
||||
Module Granularity (Medium - ~12 modules):
|
||||
Matches menu sections for intuitive mapping between modules and UI.
|
||||
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, platform-admin, etc.)
|
||||
- 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
|
||||
@@ -21,6 +36,7 @@ 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
|
||||
@@ -33,13 +49,10 @@ from app.modules.monitoring.definition import monitoring_module
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# Module Definitions
|
||||
# Core Modules (Always Enabled, Cannot Be Disabled)
|
||||
# =============================================================================
|
||||
|
||||
MODULES: dict[str, ModuleDefinition] = {
|
||||
# =========================================================================
|
||||
# Core Modules (Always Enabled)
|
||||
# =========================================================================
|
||||
CORE_MODULES: dict[str, ModuleDefinition] = {
|
||||
"core": ModuleDefinition(
|
||||
code="core",
|
||||
name="Core Platform",
|
||||
@@ -65,48 +78,67 @@ MODULES: dict[str, ModuleDefinition] = {
|
||||
],
|
||||
},
|
||||
),
|
||||
"platform-admin": ModuleDefinition(
|
||||
code="platform-admin",
|
||||
name="Platform Administration",
|
||||
description="Company, vendor, and admin user management. Required for multi-tenant operation.",
|
||||
"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",
|
||||
"platform_management",
|
||||
],
|
||||
menu_items={
|
||||
FrontendType.ADMIN: [
|
||||
"admin-users",
|
||||
"platforms",
|
||||
"companies",
|
||||
"vendors",
|
||||
"platforms",
|
||||
"admin-users",
|
||||
],
|
||||
FrontendType.VENDOR: [
|
||||
"team",
|
||||
],
|
||||
},
|
||||
),
|
||||
# =========================================================================
|
||||
# Optional Modules
|
||||
# =========================================================================
|
||||
# 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,
|
||||
# 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,
|
||||
}
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# 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/
|
||||
@@ -114,6 +146,17 @@ MODULES: dict[str, ModuleDefinition] = {
|
||||
}
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# Combined Module Registry
|
||||
# =============================================================================
|
||||
|
||||
MODULES: dict[str, ModuleDefinition] = {
|
||||
**CORE_MODULES,
|
||||
**OPTIONAL_MODULES,
|
||||
**INTERNAL_MODULES,
|
||||
}
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# Helper Functions
|
||||
# =============================================================================
|
||||
@@ -126,17 +169,32 @@ def get_module(code: str) -> ModuleDefinition | None:
|
||||
|
||||
def get_core_modules() -> list[ModuleDefinition]:
|
||||
"""Get all core modules (cannot be disabled)."""
|
||||
return [m for m in MODULES.values() if m.is_core]
|
||||
return list(CORE_MODULES.values())
|
||||
|
||||
|
||||
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}
|
||||
return set(CORE_MODULES.keys())
|
||||
|
||||
|
||||
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]
|
||||
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]:
|
||||
@@ -144,6 +202,16 @@ def get_all_module_codes() -> set[str]:
|
||||
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.
|
||||
@@ -202,6 +270,39 @@ def validate_module_dependencies() -> list[str]:
|
||||
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:
|
||||
@@ -212,13 +313,28 @@ if _validation_errors:
|
||||
|
||||
|
||||
__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",
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user