refactor: complete module-driven architecture migration

This commit completes the migration to a fully module-driven architecture:

## Models Migration
- Moved all domain models from models/database/ to their respective modules:
  - tenancy: User, Admin, Vendor, Company, Platform, VendorDomain, etc.
  - cms: MediaFile, VendorTheme
  - messaging: Email, VendorEmailSettings, VendorEmailTemplate
  - core: AdminMenuConfig
- models/database/ now only contains Base and TimestampMixin (infrastructure)

## Schemas Migration
- Moved all domain schemas from models/schema/ to their respective modules:
  - tenancy: company, vendor, admin, team, vendor_domain
  - cms: media, image, vendor_theme
  - messaging: email
- models/schema/ now only contains base.py and auth.py (infrastructure)

## Routes Migration
- Moved admin routes from app/api/v1/admin/ to modules:
  - menu_config.py -> core module
  - modules.py -> tenancy module
  - module_config.py -> tenancy module
- app/api/v1/admin/ now only aggregates auto-discovered module routes

## Menu System
- Implemented module-driven menu system with MenuDiscoveryService
- Extended FrontendType enum: PLATFORM, ADMIN, VENDOR, STOREFRONT
- Added MenuItemDefinition and MenuSectionDefinition dataclasses
- Each module now defines its own menu items in definition.py
- MenuService integrates with MenuDiscoveryService for template rendering

## Documentation
- Updated docs/architecture/models-structure.md
- Updated docs/architecture/menu-management.md
- Updated architecture validation rules for new exceptions

## Architecture Validation
- Updated MOD-019 rule to allow base.py in models/schema/
- Created core module exceptions.py and schemas/ directory
- All validation errors resolved (only warnings remain)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-02-01 21:02:56 +01:00
parent 09d7d282c6
commit d7a0ff8818
307 changed files with 5536 additions and 3826 deletions

View File

@@ -20,9 +20,9 @@ from app.modules.tenancy.exceptions import (
AdminOperationException,
CannotModifySelfException,
)
from models.database.admin_platform import AdminPlatform
from models.database.platform import Platform
from models.database.user import User
from app.modules.tenancy.models import AdminPlatform
from app.modules.tenancy.models import Platform
from app.modules.tenancy.models import User
logger = logging.getLogger(__name__)

View File

@@ -32,13 +32,13 @@ from app.modules.tenancy.exceptions import (
VendorVerificationException,
)
from middleware.auth import AuthManager
from models.database.company import Company
from app.modules.tenancy.models import Company
from app.modules.marketplace.models import MarketplaceImportJob
from models.database.platform import Platform
from models.database.user import User
from models.database.vendor import Role, Vendor
from app.modules.tenancy.models import Platform
from app.modules.tenancy.models import User
from app.modules.tenancy.models import Role, Vendor
from app.modules.marketplace.schemas import MarketplaceImportJobResponse
from models.schema.vendor import VendorCreate
from app.modules.tenancy.schemas.vendor import VendorCreate
logger = logging.getLogger(__name__)
@@ -422,7 +422,7 @@ class AdminService:
# Assign vendor to platforms if provided
if vendor_data.platform_ids:
from models.database.vendor_platform import VendorPlatform
from app.modules.tenancy.models import VendorPlatform
for platform_id in vendor_data.platform_ids:
# Verify platform exists

View File

@@ -13,9 +13,9 @@ from sqlalchemy import func, select
from sqlalchemy.orm import Session, joinedload
from app.modules.tenancy.exceptions import CompanyNotFoundException, UserNotFoundException
from models.database.company import Company
from models.database.user import User
from models.schema.company import CompanyCreate, CompanyTransferOwnership, CompanyUpdate
from app.modules.tenancy.models import Company
from app.modules.tenancy.models import User
from app.modules.tenancy.schemas.company import CompanyCreate, CompanyTransferOwnership, CompanyUpdate
logger = logging.getLogger(__name__)

View File

@@ -21,8 +21,8 @@ from app.modules.tenancy.exceptions import (
PlatformNotFoundException,
)
from app.modules.cms.models import ContentPage
from models.database.platform import Platform
from models.database.vendor_platform import VendorPlatform
from app.modules.tenancy.models import Platform
from app.modules.tenancy.models import VendorPlatform
logger = logging.getLogger(__name__)

View File

@@ -15,8 +15,8 @@ from typing import Any
from sqlalchemy.orm import Session
from app.exceptions import ValidationException
from models.database.user import User
from models.database.vendor import Role, VendorUser
from app.modules.tenancy.models import User
from app.modules.tenancy.models import Role, VendorUser
logger = logging.getLogger(__name__)

View File

@@ -29,9 +29,9 @@ from app.modules.tenancy.exceptions import (
VendorDomainNotFoundException,
VendorNotFoundException,
)
from models.database.vendor import Vendor
from models.database.vendor_domain import VendorDomain
from models.schema.vendor_domain import VendorDomainCreate, VendorDomainUpdate
from app.modules.tenancy.models import Vendor
from app.modules.tenancy.models import VendorDomain
from app.modules.tenancy.schemas.vendor_domain import VendorDomainCreate, VendorDomainUpdate
logger = logging.getLogger(__name__)

View File

@@ -25,10 +25,10 @@ from app.modules.tenancy.exceptions import (
)
from app.modules.marketplace.models import MarketplaceProduct
from app.modules.catalog.models import Product
from models.database.user import User
from models.database.vendor import Vendor
from app.modules.tenancy.models import User
from app.modules.tenancy.models import Vendor
from app.modules.catalog.schemas import ProductCreate
from models.schema.vendor import VendorCreate
from app.modules.tenancy.schemas.vendor import VendorCreate
logger = logging.getLogger(__name__)
@@ -63,7 +63,7 @@ class VendorService:
UnauthorizedVendorAccessException: If user is not company owner
InvalidVendorDataException: If vendor data is invalid
"""
from models.database.company import Company
from app.modules.tenancy.models import Company
try:
# Validate company_id is provided
@@ -159,7 +159,7 @@ class VendorService:
# Non-admin users can only see active and verified vendors, plus their own
if current_user.role != "admin":
# Get vendor IDs the user owns through companies
from models.database.company import Company
from app.modules.tenancy.models import Company
owned_vendor_ids = (
db.query(Vendor.id)
@@ -243,7 +243,7 @@ class VendorService:
"""
from sqlalchemy.orm import joinedload
from models.database.company import Company
from app.modules.tenancy.models import Company
vendor = (
db.query(Vendor)
@@ -291,7 +291,7 @@ class VendorService:
"""
from sqlalchemy.orm import joinedload
from models.database.company import Company
from app.modules.tenancy.models import Company
vendor = (
db.query(Vendor)
@@ -325,7 +325,7 @@ class VendorService:
"""
from sqlalchemy.orm import joinedload
from models.database.company import Company
from app.modules.tenancy.models import Company
# Try as integer ID first
try:

View File

@@ -26,8 +26,8 @@ from app.modules.tenancy.exceptions import (
)
from app.modules.billing.exceptions import TierLimitExceededException
from middleware.auth import AuthManager
from models.database.user import User
from models.database.vendor import Role, Vendor, VendorUser, VendorUserType
from app.modules.tenancy.models import User
from app.modules.tenancy.models import Role, Vendor, VendorUser, VendorUserType
logger = logging.getLogger(__name__)