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:
@@ -12,8 +12,8 @@ Dev-Tools is an internal module providing:
|
||||
- Icon browser
|
||||
"""
|
||||
|
||||
from app.modules.base import ModuleDefinition
|
||||
from models.database.admin_menu_config import FrontendType
|
||||
from app.modules.base import MenuItemDefinition, MenuSectionDefinition, ModuleDefinition
|
||||
from app.modules.enums import FrontendType
|
||||
|
||||
|
||||
# Dev-Tools module definition
|
||||
@@ -46,6 +46,34 @@ dev_tools_module = ModuleDefinition(
|
||||
],
|
||||
FrontendType.VENDOR: [], # No vendor menu items - internal module
|
||||
},
|
||||
# New module-driven menu definitions
|
||||
menus={
|
||||
FrontendType.ADMIN: [
|
||||
MenuSectionDefinition(
|
||||
id="devTools",
|
||||
label_key="dev_tools.menu.developer_tools",
|
||||
icon="view-grid",
|
||||
order=85,
|
||||
is_super_admin_only=True,
|
||||
items=[
|
||||
MenuItemDefinition(
|
||||
id="components",
|
||||
label_key="dev_tools.menu.components",
|
||||
icon="view-grid",
|
||||
route="/admin/components",
|
||||
order=10,
|
||||
),
|
||||
MenuItemDefinition(
|
||||
id="icons",
|
||||
label_key="dev_tools.menu.icons",
|
||||
icon="photograph",
|
||||
route="/admin/icons",
|
||||
order=20,
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
},
|
||||
is_core=False,
|
||||
is_internal=True, # Internal module - admin-only, not customer-facing
|
||||
# =========================================================================
|
||||
|
||||
@@ -1 +1,12 @@
|
||||
{}
|
||||
{
|
||||
"messages": {
|
||||
"test_run_started": "Test run started...",
|
||||
"failed_to_copy_code": "Failed to copy code",
|
||||
"failed_to_copy_name": "Failed to copy name",
|
||||
"added_to_cart": "Added to cart!",
|
||||
"filters_applied": "Filters applied!",
|
||||
"review_submitted_successfully": "Review submitted successfully!",
|
||||
"thanks_for_your_feedback": "Thanks for your feedback!",
|
||||
"code_copied_to_clipboard": "Code copied to clipboard!"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1 +1,12 @@
|
||||
{}
|
||||
{
|
||||
"messages": {
|
||||
"test_run_started": "Test run started...",
|
||||
"failed_to_copy_code": "Failed to copy code",
|
||||
"failed_to_copy_name": "Failed to copy name",
|
||||
"added_to_cart": "Added to cart!",
|
||||
"filters_applied": "Filters applied!",
|
||||
"review_submitted_successfully": "Review submitted successfully!",
|
||||
"thanks_for_your_feedback": "Thanks for your feedback!",
|
||||
"code_copied_to_clipboard": "Code copied to clipboard!"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1 +1,12 @@
|
||||
{}
|
||||
{
|
||||
"messages": {
|
||||
"test_run_started": "Test run started...",
|
||||
"failed_to_copy_code": "Failed to copy code",
|
||||
"failed_to_copy_name": "Failed to copy name",
|
||||
"added_to_cart": "Added to cart!",
|
||||
"filters_applied": "Filters applied!",
|
||||
"review_submitted_successfully": "Review submitted successfully!",
|
||||
"thanks_for_your_feedback": "Thanks for your feedback!",
|
||||
"code_copied_to_clipboard": "Code copied to clipboard!"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1 +1,12 @@
|
||||
{}
|
||||
{
|
||||
"messages": {
|
||||
"test_run_started": "Test run started...",
|
||||
"failed_to_copy_code": "Failed to copy code",
|
||||
"failed_to_copy_name": "Failed to copy name",
|
||||
"added_to_cart": "Added to cart!",
|
||||
"filters_applied": "Filters applied!",
|
||||
"review_submitted_successfully": "Review submitted successfully!",
|
||||
"thanks_for_your_feedback": "Thanks for your feedback!",
|
||||
"code_copied_to_clipboard": "Code copied to clipboard!"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,8 +18,8 @@ from sqlalchemy.orm import Session
|
||||
from app.api.deps import get_db, require_menu_access
|
||||
from app.modules.core.utils.page_context import get_admin_context
|
||||
from app.templates_config import templates
|
||||
from models.database.admin_menu_config import FrontendType
|
||||
from models.database.user import User
|
||||
from app.modules.enums import FrontendType
|
||||
from app.modules.tenancy.models import User
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
@@ -132,7 +132,7 @@ function adminComponents() {
|
||||
this.addedToCart = true;
|
||||
setTimeout(() => { this.addedToCart = false; }, 2000);
|
||||
if (typeof Utils !== 'undefined' && Utils.showToast) {
|
||||
Utils.showToast('Added to cart!', 'success');
|
||||
Utils.showToast(I18n.t('dev_tools.messages.added_to_cart'), 'success');
|
||||
}
|
||||
}, 800);
|
||||
},
|
||||
@@ -320,7 +320,7 @@ function adminComponents() {
|
||||
demoFilterProducts() {
|
||||
componentsLog.debug('Filtering products with:', this.demoActiveFilters);
|
||||
if (typeof Utils !== 'undefined' && Utils.showToast) {
|
||||
Utils.showToast('Filters applied!', 'info');
|
||||
Utils.showToast(I18n.t('dev_tools.messages.filters_applied'), 'info');
|
||||
}
|
||||
},
|
||||
demoSortProducts() {
|
||||
@@ -391,7 +391,7 @@ function adminComponents() {
|
||||
this.showReviewForm = false;
|
||||
this.demoNewReview = { rating: 0, title: '', content: '', images: [] };
|
||||
if (typeof Utils !== 'undefined' && Utils.showToast) {
|
||||
Utils.showToast('Review submitted successfully!', 'success');
|
||||
Utils.showToast(I18n.t('dev_tools.messages.review_submitted_successfully'), 'success');
|
||||
}
|
||||
}, 1500);
|
||||
},
|
||||
@@ -401,7 +401,7 @@ function adminComponents() {
|
||||
review.helpful_count++;
|
||||
}
|
||||
if (typeof Utils !== 'undefined' && Utils.showToast) {
|
||||
Utils.showToast('Thanks for your feedback!', 'info');
|
||||
Utils.showToast(I18n.t('dev_tools.messages.thanks_for_your_feedback'), 'info');
|
||||
}
|
||||
},
|
||||
|
||||
@@ -468,6 +468,9 @@ function adminComponents() {
|
||||
|
||||
// ✅ CRITICAL: Proper initialization with guard
|
||||
async init() {
|
||||
// Load i18n translations
|
||||
await I18n.loadModule('dev_tools');
|
||||
|
||||
componentsLog.info('=== COMPONENTS PAGE INITIALIZING ===');
|
||||
|
||||
// Prevent multiple initializations
|
||||
@@ -534,7 +537,7 @@ function adminComponents() {
|
||||
await navigator.clipboard.writeText(code);
|
||||
// Use the global Utils.showToast function
|
||||
if (typeof Utils !== 'undefined' && Utils.showToast) {
|
||||
Utils.showToast('Code copied to clipboard!', 'success');
|
||||
Utils.showToast(I18n.t('dev_tools.messages.code_copied_to_clipboard'), 'success');
|
||||
} else {
|
||||
componentsLog.warn('Utils.showToast not available');
|
||||
}
|
||||
@@ -542,7 +545,7 @@ function adminComponents() {
|
||||
} catch (error) {
|
||||
window.LogConfig.logError(error, 'Copy Code');
|
||||
if (typeof Utils !== 'undefined' && Utils.showToast) {
|
||||
Utils.showToast('Failed to copy code', 'error');
|
||||
Utils.showToast(I18n.t('dev_tools.messages.failed_to_copy_code'), 'error');
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -45,6 +45,9 @@ function adminIcons() {
|
||||
|
||||
// ✅ CRITICAL: Proper initialization with guard
|
||||
async init() {
|
||||
// Load i18n translations
|
||||
await I18n.loadModule('dev_tools');
|
||||
|
||||
iconsLog.info('=== ICONS PAGE INITIALIZING ===');
|
||||
|
||||
// Prevent multiple initializations
|
||||
@@ -169,7 +172,7 @@ function adminIcons() {
|
||||
iconsLog.debug('Icon usage code copied:', iconName);
|
||||
} catch (error) {
|
||||
window.LogConfig.logError(error, 'Copy Icon Usage');
|
||||
Utils.showToast('Failed to copy code', 'error');
|
||||
Utils.showToast(I18n.t('dev_tools.messages.failed_to_copy_code'), 'error');
|
||||
}
|
||||
},
|
||||
|
||||
@@ -183,7 +186,7 @@ function adminIcons() {
|
||||
iconsLog.debug('Icon name copied:', iconName);
|
||||
} catch (error) {
|
||||
window.LogConfig.logError(error, 'Copy Icon Name');
|
||||
Utils.showToast('Failed to copy name', 'error');
|
||||
Utils.showToast(I18n.t('dev_tools.messages.failed_to_copy_name'), 'error');
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@@ -54,6 +54,9 @@ function testingDashboard() {
|
||||
runs: [],
|
||||
|
||||
async init() {
|
||||
// Load i18n translations
|
||||
await I18n.loadModule('dev_tools');
|
||||
|
||||
// Guard against multiple initialization
|
||||
if (window._adminTestingDashboardInitialized) return;
|
||||
window._adminTestingDashboardInitialized = true;
|
||||
@@ -148,7 +151,7 @@ function testingDashboard() {
|
||||
// Start polling for status
|
||||
this.pollInterval = setInterval(() => this.pollRunStatus(), 2000);
|
||||
|
||||
Utils.showToast('Test run started...', 'info');
|
||||
Utils.showToast(I18n.t('dev_tools.messages.test_run_started'), 'info');
|
||||
|
||||
} catch (err) {
|
||||
testingDashboardLog.error('Failed to start tests:', err);
|
||||
|
||||
Reference in New Issue
Block a user