Transform CMS from a thin wrapper into a fully self-contained module with all code living within app/modules/cms/: Module Structure: - models/: ContentPage model (canonical location with dynamic discovery) - schemas/: Pydantic schemas for API validation - services/: ContentPageService business logic - exceptions/: Module-specific exceptions - routes/api/: REST API endpoints (admin, vendor, shop) - routes/pages/: HTML page routes (admin, vendor) - templates/cms/: Jinja2 templates (namespaced) - static/: JavaScript files (admin/vendor) - locales/: i18n translations (en, fr, de, lb) Key Changes: - Move ContentPage model to module with dynamic model discovery - Create Pydantic schemas package for request/response validation - Extract API routes from app/api/v1/*/ to module - Extract page routes from admin_pages.py/vendor_pages.py to module - Move static JS files to module with dedicated mount point - Update templates to use cms_static for module assets - Add module static file mounting in main.py - Delete old scattered files (no shims - hard errors on old imports) This establishes the pattern for migrating other modules to be fully autonomous and independently deployable. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
258 lines
6.8 KiB
Python
258 lines
6.8 KiB
Python
# models/database/__init__.py
|
|
"""
|
|
Database models package.
|
|
|
|
This package imports all SQLAlchemy models to ensure they are registered
|
|
with Base.metadata. This includes:
|
|
1. Core models (defined in this directory)
|
|
2. Module models (discovered from app/modules/<module>/models/)
|
|
|
|
Module Model Discovery:
|
|
- Modules can define their own models in app/modules/<module>/models/
|
|
- These are automatically imported when this package loads
|
|
- Module models must use `from app.core.database import Base`
|
|
"""
|
|
|
|
import importlib
|
|
import logging
|
|
from pathlib import Path
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
# ============================================================================
|
|
# CORE MODELS (always loaded)
|
|
# ============================================================================
|
|
|
|
from .admin import (
|
|
AdminAuditLog,
|
|
AdminNotification,
|
|
AdminSession,
|
|
AdminSetting,
|
|
PlatformAlert,
|
|
)
|
|
from .admin_menu_config import AdminMenuConfig, FrontendType, MANDATORY_MENU_ITEMS
|
|
from .admin_platform import AdminPlatform
|
|
from .architecture_scan import (
|
|
ArchitectureScan,
|
|
ArchitectureViolation,
|
|
ViolationAssignment,
|
|
ViolationComment,
|
|
)
|
|
from .base import Base
|
|
from .company import Company
|
|
from .platform import Platform
|
|
from .platform_module import PlatformModule
|
|
from .vendor_platform import VendorPlatform
|
|
from .customer import Customer, CustomerAddress
|
|
from .password_reset_token import PasswordResetToken
|
|
from .email import EmailCategory, EmailLog, EmailStatus, EmailTemplate
|
|
from .vendor_email_template import VendorEmailTemplate
|
|
from .vendor_email_settings import EmailProvider, VendorEmailSettings, PREMIUM_EMAIL_PROVIDERS
|
|
from .feature import Feature, FeatureCategory, FeatureCode, FeatureUILocation
|
|
from .inventory import Inventory
|
|
from .inventory_transaction import InventoryTransaction, TransactionType
|
|
from .invoice import (
|
|
Invoice,
|
|
InvoiceStatus,
|
|
VATRegime,
|
|
VendorInvoiceSettings,
|
|
)
|
|
from .letzshop import (
|
|
LetzshopFulfillmentQueue,
|
|
LetzshopHistoricalImportJob,
|
|
LetzshopSyncLog,
|
|
VendorLetzshopCredentials,
|
|
)
|
|
from .marketplace_import_job import MarketplaceImportError, MarketplaceImportJob
|
|
from .message import (
|
|
Conversation,
|
|
ConversationParticipant,
|
|
ConversationType,
|
|
Message,
|
|
MessageAttachment,
|
|
ParticipantType,
|
|
)
|
|
from .marketplace_product import (
|
|
DigitalDeliveryMethod,
|
|
MarketplaceProduct,
|
|
ProductType,
|
|
)
|
|
from .media import MediaFile, ProductMedia
|
|
from .marketplace_product_translation import MarketplaceProductTranslation
|
|
from .onboarding import OnboardingStatus, OnboardingStep, VendorOnboarding
|
|
from .order import Order, OrderItem
|
|
from .order_item_exception import OrderItemException
|
|
from .product import Product
|
|
from .product_translation import ProductTranslation
|
|
from .subscription import (
|
|
AddOnCategory,
|
|
AddOnProduct,
|
|
BillingHistory,
|
|
BillingPeriod,
|
|
StripeWebhookEvent,
|
|
SubscriptionStatus,
|
|
SubscriptionTier,
|
|
TierCode,
|
|
TIER_LIMITS,
|
|
VendorAddOn,
|
|
VendorSubscription,
|
|
)
|
|
from .test_run import TestCollection, TestResult, TestRun
|
|
from .user import User
|
|
from .vendor import Role, Vendor, VendorUser
|
|
from .vendor_domain import VendorDomain
|
|
from .vendor_theme import VendorTheme
|
|
|
|
# ============================================================================
|
|
# MODULE MODELS (dynamically discovered)
|
|
# ============================================================================
|
|
|
|
|
|
def _discover_module_models():
|
|
"""
|
|
Discover and import models from app/modules/<module>/models/ directories.
|
|
|
|
This ensures module models are registered with Base.metadata for:
|
|
1. Alembic migrations
|
|
2. SQLAlchemy queries
|
|
|
|
Module models must:
|
|
- Be in app/modules/<module>/models/__init__.py or individual files
|
|
- Import Base from app.core.database
|
|
"""
|
|
modules_dir = Path(__file__).parent.parent.parent / "app" / "modules"
|
|
|
|
if not modules_dir.exists():
|
|
return
|
|
|
|
for module_dir in sorted(modules_dir.iterdir()):
|
|
if not module_dir.is_dir():
|
|
continue
|
|
|
|
models_init = module_dir / "models" / "__init__.py"
|
|
if models_init.exists():
|
|
module_name = f"app.modules.{module_dir.name}.models"
|
|
try:
|
|
importlib.import_module(module_name)
|
|
logger.debug(f"[Models] Loaded module models: {module_name}")
|
|
except ImportError as e:
|
|
logger.warning(f"[Models] Failed to import {module_name}: {e}")
|
|
|
|
|
|
# Run discovery at import time
|
|
_discover_module_models()
|
|
|
|
# ============================================================================
|
|
# EXPORTS
|
|
# ============================================================================
|
|
|
|
__all__ = [
|
|
# Admin-specific models
|
|
"AdminAuditLog",
|
|
"AdminMenuConfig",
|
|
"FrontendType",
|
|
"AdminNotification",
|
|
"AdminPlatform",
|
|
"AdminSetting",
|
|
"MANDATORY_MENU_ITEMS",
|
|
"PlatformAlert",
|
|
"AdminSession",
|
|
# Architecture/Code Quality
|
|
"ArchitectureScan",
|
|
"ArchitectureViolation",
|
|
"ViolationAssignment",
|
|
"ViolationComment",
|
|
# Test Runs
|
|
"TestRun",
|
|
"TestResult",
|
|
"TestCollection",
|
|
# Base
|
|
"Base",
|
|
# User & Auth
|
|
"User",
|
|
# Company & Vendor
|
|
"Company",
|
|
"Vendor",
|
|
"VendorUser",
|
|
"Role",
|
|
"VendorDomain",
|
|
"VendorTheme",
|
|
# Platform
|
|
"Platform",
|
|
"PlatformModule",
|
|
"VendorPlatform",
|
|
# Customer & Auth
|
|
"Customer",
|
|
"CustomerAddress",
|
|
"PasswordResetToken",
|
|
# Email
|
|
"EmailCategory",
|
|
"EmailLog",
|
|
"EmailStatus",
|
|
"EmailTemplate",
|
|
"VendorEmailTemplate",
|
|
"VendorEmailSettings",
|
|
"EmailProvider",
|
|
"PREMIUM_EMAIL_PROVIDERS",
|
|
# Features
|
|
"Feature",
|
|
"FeatureCategory",
|
|
"FeatureCode",
|
|
"FeatureUILocation",
|
|
# Product - Enums
|
|
"ProductType",
|
|
"DigitalDeliveryMethod",
|
|
# Product - Models
|
|
"MarketplaceProduct",
|
|
"MarketplaceProductTranslation",
|
|
"Product",
|
|
"ProductTranslation",
|
|
# Import
|
|
"MarketplaceImportJob",
|
|
"MarketplaceImportError",
|
|
# Inventory
|
|
"Inventory",
|
|
"InventoryTransaction",
|
|
"TransactionType",
|
|
# Media
|
|
"MediaFile",
|
|
"ProductMedia",
|
|
# Invoicing
|
|
"Invoice",
|
|
"InvoiceStatus",
|
|
"VATRegime",
|
|
"VendorInvoiceSettings",
|
|
# Orders
|
|
"Order",
|
|
"OrderItem",
|
|
"OrderItemException",
|
|
# Letzshop Integration
|
|
"VendorLetzshopCredentials",
|
|
"LetzshopFulfillmentQueue",
|
|
"LetzshopSyncLog",
|
|
"LetzshopHistoricalImportJob",
|
|
# Subscription & Billing
|
|
"VendorSubscription",
|
|
"SubscriptionStatus",
|
|
"SubscriptionTier",
|
|
"TierCode",
|
|
"TIER_LIMITS",
|
|
"AddOnProduct",
|
|
"AddOnCategory",
|
|
"BillingPeriod",
|
|
"VendorAddOn",
|
|
"BillingHistory",
|
|
"StripeWebhookEvent",
|
|
# Messaging
|
|
"Conversation",
|
|
"ConversationParticipant",
|
|
"ConversationType",
|
|
"Message",
|
|
"MessageAttachment",
|
|
"ParticipantType",
|
|
# Onboarding
|
|
"OnboardingStatus",
|
|
"OnboardingStep",
|
|
"VendorOnboarding",
|
|
]
|