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

@@ -9,11 +9,11 @@ Usage:
"""
from app.modules.catalog.models.product import Product
from app.modules.catalog.models.product_translation import ProductTranslation
from app.modules.catalog.models.product_media import ProductMedia
from app.modules.catalog.models.product_translation import ProductTranslation
__all__ = [
"Product",
"ProductTranslation",
"ProductMedia",
"ProductTranslation",
]

View File

@@ -114,6 +114,9 @@ class Product(Base, TimestampMixin):
inventory_entries = relationship(
"Inventory", back_populates="product", cascade="all, delete-orphan"
)
media_associations = relationship(
"ProductMedia", back_populates="product", cascade="all, delete-orphan"
)
# === CONSTRAINTS & INDEXES ===
__table_args__ = (

View File

@@ -4,6 +4,11 @@ Product-Media association model.
Links media files to products with usage type tracking
(main image, gallery, variant images, etc.)
This model lives in the catalog module because:
- It's an association specific to products
- Catalog owns the relationship between its products and media
- CMS provides generic media storage, catalog defines how it uses media
"""
from sqlalchemy import (
@@ -25,6 +30,8 @@ class ProductMedia(Base, TimestampMixin):
Tracks which media files are used by which products,
including the usage type (main image, gallery, variant, etc.)
This is catalog's association table - CMS doesn't need to know about it.
"""
__tablename__ = "product_media"
@@ -52,8 +59,9 @@ class ProductMedia(Base, TimestampMixin):
variant_id = Column(Integer) # Reference to variant if applicable
# Relationships
product = relationship("Product")
media = relationship("MediaFile", back_populates="product_associations")
product = relationship("Product", back_populates="media_associations")
# MediaFile is generic and doesn't know about ProductMedia
media = relationship("MediaFile", lazy="joined")
__table_args__ = (
UniqueConstraint(