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,7 +2,7 @@
{# Standalone Pricing Page #}
{% extends "public/base.html" %}
{% block title %}{{ _("platform.pricing.title") }} - Wizamart{% endblock %}
{% block title %}{{ _("cms.platform.pricing.title") }} - Wizamart{% endblock %}
{% block content %}
<div x-data="{ annual: false }" class="py-16 lg:py-24">
@@ -10,15 +10,15 @@
{# Header #}
<div class="text-center mb-12">
<h1 class="text-4xl md:text-5xl font-bold text-gray-900 dark:text-white mb-4">
{{ _("platform.pricing.title") }}
{{ _("cms.platform.pricing.title") }}
</h1>
<p class="text-xl text-gray-600 dark:text-gray-400 max-w-2xl mx-auto">
{{ _("platform.pricing.trial_note", trial_days=trial_days) }}
{{ _("cms.platform.pricing.trial_note", trial_days=trial_days) }}
</p>
{# Billing Toggle #}
<div class="flex items-center justify-center mt-8 space-x-4">
<span class="text-gray-700 dark:text-gray-300" :class="{ 'font-semibold': !annual }">{{ _("platform.pricing.monthly") }}</span>
<span class="text-gray-700 dark:text-gray-300" :class="{ 'font-semibold': !annual }">{{ _("cms.platform.pricing.monthly") }}</span>
<button @click="annual = !annual"
class="relative w-14 h-7 rounded-full transition-colors"
:class="annual ? 'bg-indigo-600' : 'bg-gray-300 dark:bg-gray-600'">
@@ -26,8 +26,8 @@
:class="annual ? 'translate-x-7' : ''"></span>
</button>
<span class="text-gray-700 dark:text-gray-300" :class="{ 'font-semibold': annual }">
{{ _("platform.pricing.annual") }}
<span class="text-green-600 text-sm font-medium ml-1">{{ _("platform.pricing.save_months") }}</span>
{{ _("cms.platform.pricing.annual") }}
<span class="text-green-600 text-sm font-medium ml-1">{{ _("cms.platform.pricing.save_months") }}</span>
</span>
</div>
</div>
@@ -40,7 +40,7 @@
{% if tier.is_popular %}
<div class="absolute -top-3 left-1/2 -translate-x-1/2">
<span class="bg-indigo-600 text-white text-xs font-bold px-3 py-1 rounded-full">{{ _("platform.pricing.recommended") }}</span>
<span class="bg-indigo-600 text-white text-xs font-bold px-3 py-1 rounded-full">{{ _("cms.platform.pricing.recommended") }}</span>
</div>
{% endif %}
@@ -50,17 +50,17 @@
<template x-if="!annual">
<div>
<span class="text-4xl font-extrabold text-gray-900 dark:text-white">{{ tier.price_monthly }}</span>
<span class="text-gray-500">{{ _("platform.pricing.per_month") }}</span>
<span class="text-gray-500">{{ _("cms.platform.pricing.per_month") }}</span>
</div>
</template>
<template x-if="annual">
<div>
{% if tier.price_annual %}
<span class="text-4xl font-extrabold text-gray-900 dark:text-white">{{ (tier.price_annual / 12)|round(0)|int }}</span>
<span class="text-gray-500">{{ _("platform.pricing.per_month") }}</span>
<div class="text-sm text-gray-500">{{ tier.price_annual }}{{ _("platform.pricing.per_year") }}</div>
<span class="text-gray-500">{{ _("cms.platform.pricing.per_month") }}</span>
<div class="text-sm text-gray-500">{{ tier.price_annual }}{{ _("cms.platform.pricing.per_year") }}</div>
{% else %}
<span class="text-2xl font-bold text-gray-900 dark:text-white">{{ _("platform.pricing.custom") }}</span>
<span class="text-2xl font-bold text-gray-900 dark:text-white">{{ _("cms.platform.pricing.custom") }}</span>
{% endif %}
</div>
</template>
@@ -71,37 +71,37 @@
<svg class="w-4 h-4 text-green-500 mr-2" fill="currentColor" viewBox="0 0 20 20">
<path fill-rule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clip-rule="evenodd"/>
</svg>
{% if tier.orders_per_month %}{{ _("platform.pricing.orders_per_month", count=tier.orders_per_month) }}{% else %}{{ _("platform.pricing.unlimited_orders") }}{% endif %}
{% if tier.orders_per_month %}{{ _("cms.platform.pricing.orders_per_month", count=tier.orders_per_month) }}{% else %}{{ _("cms.platform.pricing.unlimited_orders") }}{% endif %}
</li>
<li class="flex items-center text-gray-700 dark:text-gray-300">
<svg class="w-4 h-4 text-green-500 mr-2" fill="currentColor" viewBox="0 0 20 20">
<path fill-rule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clip-rule="evenodd"/>
</svg>
{% if tier.products_limit %}{{ _("platform.pricing.products_limit", count=tier.products_limit) }}{% else %}{{ _("platform.pricing.unlimited_products") }}{% endif %}
{% if tier.products_limit %}{{ _("cms.platform.pricing.products_limit", count=tier.products_limit) }}{% else %}{{ _("cms.platform.pricing.unlimited_products") }}{% endif %}
</li>
<li class="flex items-center text-gray-700 dark:text-gray-300">
<svg class="w-4 h-4 text-green-500 mr-2" fill="currentColor" viewBox="0 0 20 20">
<path fill-rule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clip-rule="evenodd"/>
</svg>
{% if tier.team_members %}{{ _("platform.pricing.team_members", count=tier.team_members) }}{% else %}{{ _("platform.pricing.unlimited_team") }}{% endif %}
{% if tier.team_members %}{{ _("cms.platform.pricing.team_members", count=tier.team_members) }}{% else %}{{ _("cms.platform.pricing.unlimited_team") }}{% endif %}
</li>
<li class="flex items-center text-gray-700 dark:text-gray-300">
<svg class="w-4 h-4 text-green-500 mr-2" fill="currentColor" viewBox="0 0 20 20">
<path fill-rule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clip-rule="evenodd"/>
</svg>
{{ _("platform.pricing.letzshop_sync") }}
{{ _("cms.platform.pricing.letzshop_sync") }}
</li>
</ul>
{% if tier.is_enterprise %}
<a href="/contact" class="block w-full py-3 bg-gray-200 dark:bg-gray-700 text-gray-900 dark:text-white font-semibold rounded-xl text-center hover:bg-gray-300 transition-colors">
{{ _("platform.pricing.contact_sales") }}
{{ _("cms.platform.pricing.contact_sales") }}
</a>
{% else %}
<a :href="'/signup?tier={{ tier.code }}&annual=' + annual"
class="block w-full py-3 font-semibold rounded-xl text-center transition-colors
{% if tier.is_popular %}bg-indigo-600 hover:bg-indigo-700 text-white{% else %}bg-indigo-100 text-indigo-700 hover:bg-indigo-200{% endif %}">
{{ _("platform.pricing.start_trial") }}
{{ _("cms.platform.pricing.start_trial") }}
</a>
{% endif %}
</div>
@@ -111,7 +111,7 @@
{# Back to Home #}
<div class="text-center mt-12">
<a href="/" class="text-indigo-600 dark:text-indigo-400 hover:underline">
&larr; {{ _("platform.pricing.back_home") }}
&larr; {{ _("cms.platform.pricing.back_home") }}
</a>
</div>
</div>

View File

@@ -2,7 +2,7 @@
{# Signup Success Page #}
{% extends "public/base.html" %}
{% block title %}{{ _("platform.success.title") }}{% endblock %}
{% block title %}{{ _("cms.platform.success.title") }}{% endblock %}
{% block content %}
<div class="min-h-screen py-16 bg-gray-50 dark:bg-gray-900 flex items-center justify-center">
@@ -17,23 +17,23 @@
{# Welcome Message #}
<h1 class="text-4xl font-bold text-gray-900 dark:text-white mb-4">
{{ _("platform.success.title") }}
{{ _("cms.platform.success.title") }}
</h1>
<p class="text-xl text-gray-600 dark:text-gray-400 mb-8">
{{ _("platform.success.subtitle", trial_days=trial_days) }}
{{ _("cms.platform.success.subtitle", trial_days=trial_days) }}
</p>
{# Next Steps #}
<div class="bg-white dark:bg-gray-800 rounded-2xl p-8 border border-gray-200 dark:border-gray-700 text-left mb-8">
<h2 class="text-lg font-semibold text-gray-900 dark:text-white mb-4">{{ _("platform.success.what_next") }}</h2>
<h2 class="text-lg font-semibold text-gray-900 dark:text-white mb-4">{{ _("cms.platform.success.what_next") }}</h2>
<ul class="space-y-4">
<li class="flex items-start">
<div class="w-6 h-6 bg-indigo-100 dark:bg-indigo-900/30 rounded-full flex items-center justify-center flex-shrink-0 mt-0.5">
<span class="text-indigo-600 dark:text-indigo-400 text-sm font-bold">1</span>
</div>
<span class="ml-3 text-gray-700 dark:text-gray-300">
<strong>{{ _("platform.success.step_connect") }}</strong> {{ _("platform.success.step_connect_desc") }}
<strong>{{ _("cms.platform.success.step_connect") }}</strong> {{ _("cms.platform.success.step_connect_desc") }}
</span>
</li>
<li class="flex items-start">
@@ -41,7 +41,7 @@
<span class="text-indigo-600 dark:text-indigo-400 text-sm font-bold">2</span>
</div>
<span class="ml-3 text-gray-700 dark:text-gray-300">
<strong>{{ _("platform.success.step_invoicing") }}</strong> {{ _("platform.success.step_invoicing_desc") }}
<strong>{{ _("cms.platform.success.step_invoicing") }}</strong> {{ _("cms.platform.success.step_invoicing_desc") }}
</span>
</li>
<li class="flex items-start">
@@ -49,7 +49,7 @@
<span class="text-indigo-600 dark:text-indigo-400 text-sm font-bold">3</span>
</div>
<span class="ml-3 text-gray-700 dark:text-gray-300">
<strong>{{ _("platform.success.step_products") }}</strong> {{ _("platform.success.step_products_desc") }}
<strong>{{ _("cms.platform.success.step_products") }}</strong> {{ _("cms.platform.success.step_products_desc") }}
</span>
</li>
</ul>
@@ -59,7 +59,7 @@
{% if vendor_code %}
<a href="/vendor/{{ vendor_code }}/dashboard"
class="inline-flex items-center px-8 py-4 bg-indigo-600 hover:bg-indigo-700 text-white font-semibold rounded-xl shadow-lg transition-all hover:scale-105">
{{ _("platform.success.go_to_dashboard") }}
{{ _("cms.platform.success.go_to_dashboard") }}
<svg class="w-5 h-5 ml-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 7l5 5m0 0l-5 5m5-5H6"/>
</svg>
@@ -67,14 +67,14 @@
{% else %}
<a href="/admin/login"
class="inline-flex items-center px-8 py-4 bg-indigo-600 hover:bg-indigo-700 text-white font-semibold rounded-xl shadow-lg transition-all">
{{ _("platform.success.login_dashboard") }}
{{ _("cms.platform.success.login_dashboard") }}
</a>
{% endif %}
{# Support Link #}
<p class="mt-8 text-gray-500 dark:text-gray-400">
{{ _("platform.success.need_help") }}
<a href="/contact" class="text-indigo-600 dark:text-indigo-400 hover:underline">{{ _("platform.success.contact_support") }}</a>
{{ _("cms.platform.success.need_help") }}
<a href="/contact" class="text-indigo-600 dark:text-indigo-400 hover:underline">{{ _("cms.platform.success.contact_support") }}</a>
</p>
</div>
</div>