Files
orion/app/modules/contracts/__init__.py
Samir Boulahtit a8fae0fbc7 feat: implement metrics provider pattern for modular dashboard statistics
This commit introduces a protocol-based metrics architecture that allows
each module to provide its own statistics for dashboards without creating
cross-module dependencies.

Key changes:
- Add MetricsProviderProtocol and MetricValue dataclass in contracts module
- Add StatsAggregatorService in core module that discovers and aggregates
  metrics from all enabled modules
- Implement metrics providers for all modules:
  - tenancy: vendor/user counts, team members, domains
  - customers: customer counts
  - cms: pages, media files
  - catalog: products
  - inventory: stock levels
  - orders: order counts, revenue
  - marketplace: import jobs, staging products
- Update dashboard routes to use StatsAggregator instead of direct imports
- Fix VendorPlatform junction table usage (Vendor.platform_id doesn't exist)
- Add comprehensive documentation for the pattern

This architecture ensures:
- Dashboards always work (aggregator in core)
- Each module owns its metrics (no cross-module coupling)
- Optional modules are truly optional (can be removed without breaking app)
- Multi-platform vendors are properly supported via VendorPlatform table

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-03 21:11:29 +01:00

55 lines
1.6 KiB
Python

# app/modules/contracts/__init__.py
"""
Cross-module contracts using Protocol pattern.
This module defines type-safe interfaces for cross-module communication.
Modules depend on protocols rather than concrete implementations, enabling:
- Loose coupling between modules
- Testability through mock implementations
- Clear dependency boundaries
Usage:
from app.modules.contracts.cms import ContentServiceProtocol
class OrderService:
def __init__(self, content: ContentServiceProtocol | None = None):
self._content = content
@property
def content(self) -> ContentServiceProtocol:
if self._content is None:
from app.modules.cms.services import content_page_service
self._content = content_page_service
return self._content
Metrics Provider Pattern:
from app.modules.contracts.metrics import MetricsProviderProtocol, MetricValue
class OrderMetricsProvider:
@property
def metrics_category(self) -> str:
return "orders"
def get_vendor_metrics(self, db, vendor_id, context=None) -> list[MetricValue]:
return [MetricValue(key="orders.total", value=42, label="Total", category="orders")]
"""
from app.modules.contracts.base import ServiceProtocol
from app.modules.contracts.cms import ContentServiceProtocol
from app.modules.contracts.metrics import (
MetricValue,
MetricsContext,
MetricsProviderProtocol,
)
__all__ = [
# Base protocols
"ServiceProtocol",
# CMS protocols
"ContentServiceProtocol",
# Metrics protocols
"MetricValue",
"MetricsContext",
"MetricsProviderProtocol",
]