Files
orion/app/modules/contracts/__init__.py
Samir Boulahtit 2250054ba2 feat: consolidate media service, add merchant users page, fix metrics overlap
- Merge ImageService into MediaService with WebP variant generation,
  DB-backed storage stats, and module-driven media usage discovery
  via new MediaUsageProviderProtocol
- Add merchant users admin page with scoped user listing, stats
  endpoint, template, JS, and i18n strings (de/en/fr/lb)
- Fix merchant user metrics so Owners and Team Members are mutually
  exclusive (filter team_members on user_type="member" and exclude
  owner IDs) ensuring stat cards add up correctly
- Update billing and monitoring services to use media_service
- Update subscription-billing and feature-gating docs

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-07 21:17:11 +01:00

104 lines
2.9 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_store_metrics(self, db, store_id, context=None) -> list[MetricValue]:
return [MetricValue(key="orders.total", value=42, label="Total", category="orders")]
Widget Provider Pattern:
from app.modules.contracts.widgets import DashboardWidgetProviderProtocol, DashboardWidget
class OrderWidgetProvider:
@property
def widgets_category(self) -> str:
return "orders"
def get_store_widgets(self, db, store_id, context=None) -> list[DashboardWidget]:
return [DashboardWidget(key="orders.recent", widget_type="list", ...)]
"""
from app.modules.contracts.audit import (
AuditEvent,
AuditProviderProtocol,
)
from app.modules.contracts.base import ServiceProtocol
from app.modules.contracts.cms import ContentServiceProtocol, MediaUsageProviderProtocol
from app.modules.contracts.features import (
FeatureDeclaration,
FeatureProviderProtocol,
FeatureScope,
FeatureType,
FeatureUsage,
)
from app.modules.contracts.metrics import (
MetricValue,
MetricsContext,
MetricsProviderProtocol,
)
from app.modules.contracts.widgets import (
BreakdownWidget,
DashboardWidget,
DashboardWidgetProviderProtocol,
ListWidget,
WidgetBreakdownItem,
WidgetContext,
WidgetListItem,
)
__all__ = [
# Base protocols
"ServiceProtocol",
# CMS protocols
"ContentServiceProtocol",
"MediaUsageProviderProtocol",
# Audit protocols
"AuditEvent",
"AuditProviderProtocol",
# Feature protocols
"FeatureType",
"FeatureScope",
"FeatureDeclaration",
"FeatureUsage",
"FeatureProviderProtocol",
# Metrics protocols
"MetricValue",
"MetricsContext",
"MetricsProviderProtocol",
# Widget protocols
"WidgetContext",
"WidgetListItem",
"WidgetBreakdownItem",
"ListWidget",
"BreakdownWidget",
"DashboardWidget",
"DashboardWidgetProviderProtocol",
]