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

@@ -2,34 +2,26 @@
## Overview
This project uses a **hybrid architecture** for models and schemas:
This project uses a **module-based architecture** for models and schemas:
1. **CORE models/schemas** in `models/database/` and `models/schema/` - Framework-level entities used across modules
2. **Module models/schemas** in `app/modules/<module>/models/` and `app/modules/<module>/schemas/` - Domain-specific entities
1. **Infrastructure** in `models/database/` and `models/schema/` - Base classes only
2. **Module models/schemas** in `app/modules/<module>/models/` and `app/modules/<module>/schemas/` - All domain entities
3. **Inline schemas** defined directly in API route files - Endpoint-specific request/response models
## Directory Structure
```
models/ # CORE framework models
├── database/ # SQLAlchemy models (ORM)
│ ├── __init__.py # Exports all models + module discovery
── base.py # Base class, mixins
│ ├── user.py # User authentication
│ ├── vendor.py # Vendor, VendorUser, Role
│ ├── company.py # Company management
│ ├── platform.py # Multi-platform support
│ ├── media.py # MediaFile (cross-cutting)
│ └── ...
models/ # INFRASTRUCTURE ONLY
├── database/ # SQLAlchemy base classes
│ ├── __init__.py # Exports Base, TimestampMixin only
── base.py # Base class, mixins
└── schema/ # Pydantic schemas (API validation)
├── __init__.py
├── auth.py # Login, tokens, password reset
── vendor.py # Vendor CRUD schemas
├── company.py # Company schemas
└── ...
└── schema/ # Pydantic base classes
├── __init__.py # Exports base and auth only
├── base.py # Base schema classes
── auth.py # Auth schemas (cross-cutting)
app/modules/<module>/ # Domain modules
app/modules/<module>/ # Domain modules (ALL domain entities)
├── models/ # Module-specific database models
│ ├── __init__.py # Canonical exports
│ └── *.py # Model definitions
@@ -43,20 +35,28 @@ app/modules/<module>/ # Domain modules
## Architecture Principles
### 1. CORE vs Module Models
### 1. Infrastructure vs Module Code
**CORE models** (`models/database/`) are framework-level entities used across multiple modules:
- `User` - Authentication, used by all modules
- `Vendor` - Multi-tenant anchor, used by all vendor-scoped modules
- `Company` - Business entity management
- `Platform` - Multi-platform CMS support
- `MediaFile` - File storage, used by catalog, CMS, etc.
**Infrastructure** (`models/database/`, `models/schema/`) provides base classes only:
- `Base` - SQLAlchemy declarative base
- `TimestampMixin` - created_at/updated_at columns
- `BaseModel` patterns in `models/schema/base.py`
- `auth.py` - Authentication schemas (cross-cutting concern)
**Module models** (`app/modules/<module>/models/`) are domain-specific:
- `billing/models/` - Feature, SubscriptionTier, VendorSubscription
- `catalog/models/` - Product, ProductTranslation, ProductMedia
- `orders/models/` - Order, OrderItem, Invoice
- `inventory/models/` - Inventory, InventoryTransaction
**Module code** (`app/modules/<module>/`) contains all domain-specific entities:
| Module | Models | Schemas |
|--------|--------|---------|
| `tenancy` | User, Admin, Vendor, Company, Platform, VendorDomain | company, vendor, admin, team, vendor_domain |
| `billing` | Feature, SubscriptionTier, VendorSubscription | billing, subscription |
| `catalog` | Product, ProductTranslation, ProductMedia | catalog, product, vendor_product |
| `orders` | Order, OrderItem, Invoice | order, invoice, order_item_exception |
| `inventory` | Inventory, InventoryTransaction | inventory |
| `cms` | ContentPage, MediaFile, VendorTheme | content_page, media, image, vendor_theme |
| `messaging` | Email, VendorEmailSettings, VendorEmailTemplate, Message, Notification | email, message, notification |
| `customers` | Customer, PasswordResetToken | customer, context |
| `marketplace` | 5 models | 4 schemas |
| `core` | AdminMenuConfig | (inline) |
### 2. Schema Patterns
@@ -84,7 +84,7 @@ class InventoryResponse(BaseModel):
For schemas only used by a single endpoint or closely related endpoints.
```python
# app/api/v1/admin/platforms.py
# app/modules/tenancy/routes/api/admin_platforms.py
class PlatformResponse(BaseModel):
"""Platform response schema - only used in this file."""
id: int
@@ -122,7 +122,6 @@ class VendorPlatform(Base):
| Schema used by single endpoint | Inline | In the route file |
| Admin-only endpoint schemas | Inline | In the admin route file |
| Model not exposed via API | No schema | N/A |
| Cross-module utility schemas | Dedicated file | `models/schema/` |
---
@@ -168,74 +167,100 @@ class VendorPlatform(Base):
## Import Guidelines
### Canonical Imports (Preferred)
### Canonical Imports (Required)
```python
# CORE models - from models.database
from models.database import User, Vendor, MediaFile
# Infrastructure - base classes only
from models.database import Base, TimestampMixin
from models.schema.auth import LoginRequest, TokenResponse
# Module models - from app.modules.<module>.models
from app.modules.tenancy.models import User, Vendor, Company
from app.modules.billing.models import Feature, SubscriptionTier
from app.modules.catalog.models import Product, ProductMedia
from app.modules.orders.models import Order, OrderItem
# CORE schemas - from models.schema
from models.schema.auth import LoginRequest, TokenResponse
from app.modules.cms.models import MediaFile, VendorTheme
from app.modules.messaging.models import Email, VendorEmailTemplate
# Module schemas - from app.modules.<module>.schemas
from app.modules.tenancy.schemas import VendorCreate, CompanyResponse
from app.modules.cms.schemas import MediaItemResponse, VendorThemeResponse
from app.modules.messaging.schemas import EmailTemplateResponse
from app.modules.inventory.schemas import InventoryCreate, InventoryResponse
from app.modules.orders.schemas import OrderResponse
```
### Legacy Re-exports (Backwards Compatibility)
### Legacy Imports (DEPRECATED)
`models/database/__init__.py` re-exports module models for backwards compatibility:
The following import patterns are deprecated and will cause architecture validation errors:
```python
# These work but prefer canonical imports
from models.database import Product # Re-exported from catalog module
from models.database import Order # Re-exported from orders module
# DEPRECATED - Don't import domain models from models.database
from models.database import User, Vendor # WRONG
# DEPRECATED - Don't import domain schemas from models.schema
from models.schema.vendor import VendorCreate # WRONG
from models.schema.company import CompanyResponse # WRONG
```
---
## Gap Analysis: Models vs Schemas
## Module Ownership Reference
Not every database model needs a dedicated schema file. Here's the current alignment:
### Tenancy Module (`app/modules/tenancy/`)
### CORE Framework
**Models:**
- `User` - User authentication and profile
- `Admin` - Admin user management
- `Vendor` - Vendor/merchant entities
- `VendorUser` - Vendor team members
- `Company` - Company management
- `Platform` - Multi-platform support
- `AdminPlatform` - Admin-platform association
- `VendorPlatform` - Vendor-platform association
- `PlatformModule` - Module configuration per platform
- `VendorDomain` - Custom domain configuration
| Database Model | Schema | Notes |
|----------------|--------|-------|
| `user.py` | `auth.py` | Auth schemas cover user operations |
| `vendor.py` | `vendor.py` | Full CRUD schemas |
| `company.py` | `company.py` | Full CRUD schemas |
| `media.py` | `media.py` | Upload/response schemas |
| `platform.py` | Inline | Admin-only, in `platforms.py` route |
| `platform_module.py` | Inline | Admin-only, in `modules.py` route |
| `admin_menu_config.py` | Inline | Admin-only, in `menu_config.py` route |
| `vendor_email_settings.py` | Inline | In `email_settings.py` route |
| `vendor_email_template.py` | None | Internal email service use |
| `vendor_platform.py` | None | Internal association table |
**Schemas:**
- `company.py` - Company CRUD schemas
- `vendor.py` - Vendor CRUD and Letzshop export schemas
- `admin.py` - Admin user and audit log schemas
- `team.py` - Team management and invitation schemas
- `vendor_domain.py` - Domain configuration schemas
### Modules
### CMS Module (`app/modules/cms/`)
| Module | Models | Schemas | Alignment |
|--------|--------|---------|-----------|
| billing | feature, subscription | billing, subscription | ✅ |
| cart | cart | cart | ✅ |
| catalog | product, product_media, product_translation | catalog, product, vendor_product | ✅ |
| checkout | - | checkout | Schema-only (orchestration) |
| cms | content_page | content_page, homepage_sections | ✅ |
| customers | customer, password_reset_token | customer, context | ✅ (password reset uses auth schemas) |
| dev_tools | architecture_scan, test_run | Inline | Admin-only, inline in route files |
| inventory | inventory, inventory_transaction | inventory | ✅ (transaction included in inventory.py) |
| loyalty | 5 models | 5 schemas | ✅ |
| marketplace | 5 models | 4 schemas | ✅ (translation in product schema) |
| messaging | admin_notification, message | message, notification | ✅ |
| orders | order, order_item, invoice | order, invoice, order_item_exception | ✅ |
| payments | - | payment | Schema-only (external APIs) |
| analytics | - | stats | Schema-only (aggregation views) |
**Models:**
- `ContentPage` - CMS content pages
- `MediaFile` - File storage and management
- `VendorTheme` - Theme customization
**Schemas:**
- `content_page.py` - Content page schemas
- `media.py` - Media upload/response schemas
- `image.py` - Image handling schemas
- `vendor_theme.py` - Theme configuration schemas
### Messaging Module (`app/modules/messaging/`)
**Models:**
- `Email` - Email records
- `VendorEmailSettings` - Email configuration
- `VendorEmailTemplate` - Email templates
- `Message` - Internal messages
- `AdminNotification` - Admin notifications
**Schemas:**
- `email.py` - Email template schemas
- `message.py` - Message schemas
- `notification.py` - Notification schemas
### Core Module (`app/modules/core/`)
**Models:**
- `AdminMenuConfig` - Menu visibility configuration
**Schemas:** (inline in route files)
---
@@ -244,16 +269,14 @@ Not every database model needs a dedicated schema file. Here's the current align
### Database Model Checklist
1. **Determine location:**
- Cross-module use → `models/database/`
- Module-specific → `app/modules/<module>/models/`
- All domain models → `app/modules/<module>/models/`
2. **Create the model file:**
```python
# app/modules/mymodule/models/my_entity.py
from sqlalchemy import Column, Integer, String, ForeignKey
from sqlalchemy.orm import relationship
from app.core.database import Base
from models.database.base import TimestampMixin
from models.database import Base, TimestampMixin
class MyEntity(Base, TimestampMixin):
__tablename__ = "my_entities"
@@ -299,7 +322,7 @@ Not every database model needs a dedicated schema file. Here's the current align
3. **Or use inline schema:**
```python
# app/api/v1/vendor/my_entity.py
# app/modules/mymodule/routes/api/vendor.py
from pydantic import BaseModel
class MyEntityResponse(BaseModel):
@@ -320,8 +343,8 @@ Not every database model needs a dedicated schema file. Here's the current align
|-----------|----------------|
| Services access DB directly | `from app.modules.X.models import Model` |
| APIs validate with schemas | Request/response Pydantic models |
| Reusable schemas | Dedicated files in `schemas/` |
| Reusable schemas | Dedicated files in `app/modules/<module>/schemas/` |
| Endpoint-specific schemas | Inline in route files |
| Internal models | No schema needed |
| CORE models | `models/database/` |
| Module models | `app/modules/<module>/models/` |
| All domain models | `app/modules/<module>/models/` |
| Infrastructure only | `models/database/` (Base, TimestampMixin only) |