refactor: fix architecture violations with provider patterns and dependency inversion

Major changes:
- Add AuditProvider protocol for cross-module audit logging
- Move customer order operations to orders module (dependency inversion)
- Add customer order metrics via MetricsProvider pattern
- Fix missing db parameter in get_admin_context() calls
- Move ProductMedia relationship to catalog module (proper ownership)
- Add marketplace breakdown stats to marketplace_widgets

New files:
- contracts/audit.py - AuditProviderProtocol
- core/services/audit_aggregator.py - Aggregates audit providers
- monitoring/services/audit_provider.py - Monitoring audit implementation
- orders/services/customer_order_service.py - Customer order operations
- orders/routes/api/vendor_customer_orders.py - Customer order endpoints
- catalog/services/product_media_service.py - Product media service
- Architecture documentation for patterns

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-02-04 21:32:32 +01:00
parent bd43e21940
commit 39dff4ab7d
34 changed files with 2751 additions and 407 deletions

View File

@@ -17,6 +17,13 @@ def _get_admin_router():
return admin_router
def _get_audit_provider():
"""Lazy import of audit provider to avoid circular imports."""
from app.modules.monitoring.services.audit_provider import audit_provider
return audit_provider
# Monitoring module definition
monitoring_module = ModuleDefinition(
code="monitoring",
@@ -112,6 +119,10 @@ monitoring_module = ModuleDefinition(
is_core=False,
is_internal=True, # Internal module - admin-only, not customer-facing
# =========================================================================
# Audit Provider
# =========================================================================
audit_provider=_get_audit_provider,
# =========================================================================
# Self-Contained Module Configuration
# =========================================================================
is_self_contained=True,

View File

@@ -0,0 +1,78 @@
# app/modules/monitoring/services/audit_provider.py
"""
Audit provider implementation for the monitoring module.
Provides database-backed audit logging using the AdminAuditLog model.
This wraps the existing admin_audit_service functionality in the
AuditProviderProtocol interface.
"""
import logging
from typing import TYPE_CHECKING
from sqlalchemy.orm import Session
from app.modules.contracts.audit import AuditEvent, AuditProviderProtocol
from app.modules.tenancy.models import AdminAuditLog
if TYPE_CHECKING:
pass
logger = logging.getLogger(__name__)
class DatabaseAuditProvider:
"""
Database-backed audit provider.
Logs admin actions to the AdminAuditLog table.
This is the default audit backend for the platform.
"""
@property
def audit_backend(self) -> str:
return "database"
def log_action(self, db: Session, event: AuditEvent) -> bool:
"""
Log an audit event to the database.
Args:
db: Database session
event: The audit event to log
Returns:
True if logged successfully, False otherwise
"""
try:
audit_log = AdminAuditLog(
admin_user_id=event.admin_user_id,
action=event.action,
target_type=event.target_type,
target_id=str(event.target_id),
details=event.details or {},
ip_address=event.ip_address,
user_agent=event.user_agent,
request_id=event.request_id,
)
db.add(audit_log)
db.flush()
logger.debug(
f"Admin action logged: {event.action} on {event.target_type}:"
f"{event.target_id} by admin {event.admin_user_id}"
)
return True
except Exception as e:
logger.error(f"Failed to log admin action: {str(e)}")
# Don't raise exception - audit logging should not break operations
return False
# Singleton instance
audit_provider = DatabaseAuditProvider()
__all__ = ["DatabaseAuditProvider", "audit_provider"]