The emailTemplatesPage() Alpine.js component was missing the ...data()
extension from init-alpine.js, causing JavaScript errors. Added the
base layout inheritance and currentPage for proper navigation state.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add server-side translation for menu labels using user's preferred_language
- Replace hardcoded sidebar template with dynamic rendering from menu API
- Remove hardcoded section/page mappings in favor of menu discovery
- Fix locale file structure (move menu keys to top level to avoid double-nesting)
- Sidebar now fully driven by /admin/menu-config/render/admin API endpoint
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Change section ID from 'settingsSection' to 'settings' to match
the core module definition. This restores visibility of settings
and my-menu items in the admin sidebar.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Change from /admin/background-tasks/tasks/* to /admin/tasks/*
to match the actual monitoring module API routes.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Fix self-referencing documentation examples in storefront macros
that incorrectly used shared/macros/shop/ instead of storefront/.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Replace shared/macros/shop/ with shared/macros/storefront/ across
all 16 occurrences in the UI components documentation page.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Change from 'shared/macros/shop/' to 'shared/macros/storefront/'
to match actual file location.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Use module-specific static route helpers to generate correct paths for
JS files across dev_tools, marketplace, and tenancy templates.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Convert core→optional imports to lazy imports with try/except fallbacks
- cms/media_service: use TYPE_CHECKING for ProductMedia type hints
- customers/customer_service: wrap Order imports in try/except
- tenancy/admin_platform_users: wrap stats_service import in try/except
- Enhance validate_architecture.py to recognize lazy import patterns
- Add module_dependency_graph.py script for dependency visualization
The lazy import pattern allows optional modules to be truly optional while
maintaining type safety through TYPE_CHECKING blocks.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add IMPORT-001 and IMPORT-002 rules to enforce module separation:
- IMPORT-001 (ERROR): Core module imports from optional module
- IMPORT-002 (WARNING): Optional module imports without declared dependency
The validator now:
- Detects imports from optional modules in core modules (contracts, core,
tenancy, cms, customers, billing, payments, messaging)
- Detects imports between optional modules without dependency declaration
- Skips TYPE_CHECKING blocks (valid for type hints)
- Skips docstring examples (false positive prevention)
- Suggests using provider patterns (MetricsProvider, WidgetProvider)
This enforces the architectural rule: "Core modules NEVER import from
optional modules" as documented in cross-module-import-rules.md.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add protocol-based widget system following the MetricsProvider pattern:
- Create DashboardWidgetProviderProtocol in contracts/widgets.py
- Add WidgetAggregatorService in core to discover and aggregate widgets
- Implement MarketplaceWidgetProvider for recent_imports widget
- Implement TenancyWidgetProvider for recent_vendors widget
- Update admin dashboard to use widget_aggregator
- Add widget_provider field to ModuleDefinition
Architecture documentation:
- Add widget-provider-pattern.md with implementation guide
- Add cross-module-import-rules.md enforcing core/optional separation
- Update module-system.md with widget_provider and import rules
This enables modules to provide rich dashboard widgets without core modules
importing from optional modules, maintaining true module independence.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit introduces a protocol-based metrics architecture that allows
each module to provide its own statistics for dashboards without creating
cross-module dependencies.
Key changes:
- Add MetricsProviderProtocol and MetricValue dataclass in contracts module
- Add StatsAggregatorService in core module that discovers and aggregates
metrics from all enabled modules
- Implement metrics providers for all modules:
- tenancy: vendor/user counts, team members, domains
- customers: customer counts
- cms: pages, media files
- catalog: products
- inventory: stock levels
- orders: order counts, revenue
- marketplace: import jobs, staging products
- Update dashboard routes to use StatsAggregator instead of direct imports
- Fix VendorPlatform junction table usage (Vendor.platform_id doesn't exist)
- Add comprehensive documentation for the pattern
This architecture ensures:
- Dashboards always work (aggregator in core)
- Each module owns its metrics (no cross-module coupling)
- Optional modules are truly optional (can be removed without breaking app)
- Multi-platform vendors are properly supported via VendorPlatform table
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Major architecture change to unify frontend detection:
## Problem Solved
- Eliminated code duplication across 3 middleware files
- Fixed incomplete path detection (now detects /api/v1/admin/*)
- Unified on FrontendType enum (deprecates RequestContext)
- Added request.state.frontend_type for all requests
## New Components
- app/core/frontend_detector.py: Centralized FrontendDetector class
- middleware/frontend_type.py: FrontendTypeMiddleware (replaces ContextMiddleware)
- docs/architecture/frontend-detection.md: Complete architecture documentation
## Changes
- main.py: Use FrontendTypeMiddleware instead of ContextMiddleware
- middleware/context.py: Deprecated (kept for backwards compatibility)
- middleware/platform_context.py: Use FrontendDetector.is_admin()
- middleware/vendor_context.py: Use FrontendDetector.is_admin()
- middleware/language.py: Use FrontendType instead of context_value
- app/exceptions/handler.py: Use FrontendType.STOREFRONT
- app/exceptions/error_renderer.py: Use FrontendType
- Customer routes: Cookie path changed from /shop to /storefront
## Documentation
- docs/architecture/frontend-detection.md: New comprehensive docs
- docs/architecture/middleware.md: Updated for new system
- docs/architecture/request-flow.md: Updated for FrontendType
- docs/backend/middleware-reference.md: Updated API reference
## Tests
- tests/unit/core/test_frontend_detector.py: 37 new tests
- tests/unit/middleware/test_frontend_type.py: 11 new tests
- tests/unit/middleware/test_context.py: Updated for compatibility
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Documentation:
- docs/architecture/user-context-pattern.md: Comprehensive guide on
UserContext vs User model, JWT token mapping, common mistakes
Architecture Rules (auth.yaml):
- AUTH-005: Routes must use UserContext, not User model attributes
- AUTH-006: JWT token context fields must be defined in UserContext
- AUTH-007: Response models must match available UserContext data
Architecture Rules (module.yaml):
- MOD-024: Module static file mount order - specific paths first
These rules prevent issues like:
- Accessing SQLAlchemy relationships on Pydantic schemas
- Missing token fields causing fallback warnings
- Response model validation errors from missing timestamps
- 404 errors for module locale files due to mount order
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Issues fixed:
- Platform selection returned LoginResponse requiring user timestamps,
but UserContext doesn't have created_at/updated_at. Created dedicated
PlatformSelectResponse that returns only token and platform info.
- UserContext was missing platform context fields (token_platform_id,
token_platform_code). JWT token included them but they weren't
extracted into UserContext, causing fallback warnings.
- admin_menu_config.py accessed admin_platforms (SQLAlchemy relationship)
on UserContext (Pydantic schema). Changed to use accessible_platform_ids.
- Static file mount order in main.py caused 404 for locale files.
More specific paths (/static/modules/X/locales) must be mounted
before less specific paths (/static/modules/X).
Changes:
- models/schema/auth.py: Add PlatformSelectResponse, token_platform_id,
token_platform_code, can_access_platform(), get_accessible_platform_ids()
- admin_auth.py: Use PlatformSelectResponse for select-platform endpoint
- admin_platform_service.py: Accept User | UserContext in validation
- admin_menu_config.py: Use accessible_platform_ids instead of admin_platforms
- main.py: Mount locales before static for correct path priority
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The require_module_access dependency was using path-based detection to
determine admin vs vendor authentication, which failed for API routes
(/api/v1/admin/*) because it only checked for /admin/*.
Changes:
- Make frontend_type parameter mandatory (was optional with fallback)
- Remove path-based detection logic from require_module_access
- Update all 33 module route files to pass explicit FrontendType:
- 15 admin routes use FrontendType.ADMIN
- 18 vendor routes use FrontendType.VENDOR
This ensures authentication method is explicitly declared at route
definition time, making it independent of URL structure and future-proof
for API version changes.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The get_admin_context function signature changed to require db as
the second argument, but many admin route handlers were still using
the old signature (request, current_user).
Updated all occurrences across modules:
- core, catalog, dev_tools, inventory, customers, messaging
- billing, tenancy, monitoring, analytics, orders, marketplace
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1. Fix monthly/annual toggle:
- Price suffix now changes between /month and /year using Alpine.js
- Added € currency symbol to prices
2. Fix language translations:
- Section title/subtitle now fall back to locale files when CMS
content doesn't have translations for the selected language
- Uses cms.platform.pricing.title and .subtitle from locale files
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The pricing section template was using short keys like 'pricing.monthly'
but the CMS locale files use the full path 'cms.platform.pricing.monthly'.
Updated all translation keys in _pricing.html to use correct paths:
- pricing.monthly → cms.platform.pricing.monthly
- pricing.annual → cms.platform.pricing.annual
- pricing.save_months → cms.platform.pricing.save_months
- pricing.most_popular → cms.platform.pricing.most_popular
- pricing.month → cms.platform.pricing.per_month
- pricing.get_started → cms.platform.pricing.start_trial
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The language set endpoint was being called at /api/v1/language/set but
the route is actually registered under the platform prefix at
/api/v1/platform/language/set.
Updated all frontend code calling this endpoint:
- app/templates/platform/base.html
- app/templates/vendor/partials/header.html
- app/modules/core/static/storefront/js/storefront-layout.js
- app/modules/core/static/vendor/js/init-alpine.js
- app/modules/core/static/admin/js/init-alpine.js
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Change startup/shutdown log messages from "ecommerce API" to
"Wizamart multi-tenant platform" to better reflect the current
architecture.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add INFO-level logging to help diagnose module loading issues:
- discovery.py: Log summary of discovered modules by tier (core/optional/internal)
- service.py: Log which modules are enabled for each platform (DEBUG level)
- page_context.py: Log context building with platform info and which
modules contributed context with key counts
Example log output:
[MODULES] Auto-discovered 18 modules: 5 core, 11 optional, 2 internal
[CONTEXT] Building PLATFORM context for platform 'main' with 5 enabled modules
[CONTEXT] Context providers called: cms(3 keys), billing(3 keys)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Update import paths in homepage-default.html to use the correct CMS module
namespace (cms/platform/sections/*) instead of the incorrect platform namespace.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Introduces a module-driven context provider system that allows modules to
dynamically contribute template context variables without hardcoding imports.
Key changes:
- Add context_providers field to ModuleDefinition in app/modules/base.py
- Create unified get_context_for_frontend() that queries enabled modules only
- Add context providers to CMS module (PLATFORM, STOREFRONT)
- Add context providers to billing module (PLATFORM)
- Fix SQLAlchemy cross-module relationship resolution (Order, AdminMenuConfig,
MarketplaceImportJob) by ensuring models are imported before referencing
- Document the entire system in docs/architecture/module-system.md
Benefits:
- Zero coupling: adding/removing modules requires no route handler changes
- Lazy loading: module code only imported when that module is enabled
- Per-platform customization: each platform loads only what it needs
- Graceful degradation: one failing module doesn't break entire page
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Complete the public -> platform naming migration across the codebase.
This aligns with the naming convention where "platform" refers to
the marketing/public-facing pages of the platform itself.
Changes:
- Update all imports from public to platform modules
- Update template references from public/ to platform/
- Update route registrations to use platform prefix
- Update documentation to reflect new naming
- Update test files for platform API endpoints
Files affected:
- app/api/main.py - router imports
- app/modules/*/routes/*/platform.py - route definitions
- app/modules/*/templates/*/platform/ - template files
- app/modules/routes.py - route discovery
- docs/* - documentation updates
- tests/integration/api/v1/platform/ - test files
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add new validation rules MOD-020 to MOD-023 for module definition
completeness and standardize permissions across all modules.
Changes:
- Add MOD-020: Module definitions must have required attributes
- Add MOD-021: Modules with menus should have features
- Add MOD-022: Feature modules should have permissions
- Add MOD-023: Modules with routers should use get_*_with_routers pattern
Module permissions added:
- analytics: view, export, manage_dashboards
- billing: view_tiers, manage_tiers, view_subscriptions, manage_subscriptions, view_invoices
- cart: view, manage
- checkout: view_settings, manage_settings
- cms: view_pages, manage_pages, view_media, manage_media, manage_themes
- loyalty: view_programs, manage_programs, view_rewards, manage_rewards
- marketplace: view_integration, manage_integration, sync_products
- messaging: view_messages, send_messages, manage_templates
- payments: view_gateways, manage_gateways, view_transactions
Module improvements:
- Complete cart module with features and permissions
- Complete checkout module with features and permissions
- Add features to catalog module
- Add version to cms module
- Fix loyalty platform_router attachment
- Add path definitions to payments module
- Remove empty scheduled_tasks from dev_tools module
Documentation:
- Update module-system.md with new validation rules
- Update architecture-rules.md with MOD-020 to MOD-023
Tests:
- Add unit tests for module definition completeness
- Add tests for permission structure validation
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Delete app/core/permissions.py (VendorPermissions enum, PermissionGroups)
- Update all code to use permission_discovery_service directly:
- app/api/deps.py: get_user_permissions() uses discovery service
- app/modules/tenancy/models/vendor.py: get_all_permissions() uses discovery
- app/modules/tenancy/routes/api/vendor_team.py: use string literals
- app/modules/tenancy/services/vendor_team_service.py: use discovery service
- scripts/init_production.py: use discovery service for presets
Permissions are now fully module-driven:
- Each module defines permissions in definition.py
- PermissionDiscoveryService aggregates all permissions
- Role presets reference permission IDs directly
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
File Relocations:
- Delete app/config/ folder (empty after menu_registry removal)
- Move feature_gate.py → app/modules/billing/dependencies/
- Move theme_presets.py → app/modules/cms/services/
Module-Driven Permissions System:
- Add PermissionDefinition dataclass to app/modules/base.py
- Create PermissionDiscoveryService in tenancy module
- Update module definitions to declare their own permissions:
- core: dashboard.view, settings.*
- catalog: products.*
- orders: orders.*
- inventory: stock.*
- customers: customers.*
- tenancy: team.*
- Update app/core/permissions.py to use discovery service
- Role presets (owner, manager, staff, etc.) now use module permissions
This follows the same pattern as module-driven menus:
- Each module defines its permissions in definition.py
- PermissionDiscoveryService aggregates all permissions at runtime
- Tenancy module handles role-to-permission assignment
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Delete app/config/menu_registry.py (centralized menu definitions)
- Update app/config/__init__.py to remove menu_registry exports
- Migrate menu_service.py to use menu_discovery_service exclusively
- Add helper methods to menu_discovery_service.py:
- get_all_menu_item_ids() - get all item IDs for a frontend type
- get_menu_item() - get specific menu item by ID
- is_super_admin_only_item() - check if item is super-admin only
- get_menu_item_module() - get module code for a menu item
Menu items are now defined in each module's definition.py file and
aggregated by MenuDiscoveryService at runtime, enabling true
module-driven architecture.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
JavaScript improvements:
- Add try/catch error handling to all async init() functions
- Move initialization guards before try/catch blocks (JS-005)
- Use centralized logger in i18n.js with silent fallback (JS-001)
- Add loading state to icons-page.js (JS-007)
Payments module structure:
- Add templates/, static/, and locales/ directories (MOD-005)
- Add locale files for en, de, fr, lb (MOD-006)
Architecture validation now passes with 0 errors, 0 warnings, 0 info.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
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>
Mark documentation consolidation plan as mostly complete:
- All session notes archived
- All implementation plans archived
- Only future feature proposals remain in proposals/
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The legacy route files were migrated to modules. The directory only
contained an empty __init__.py. Updated docs to reflect new location.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The circular import occurred because:
1. app.modules.base imported FrontendType from models.database.admin_menu_config
2. This triggered models/database/__init__.py which runs model discovery
3. Model discovery imported module definitions
4. Module definitions imported from app.modules.base (still initializing)
Solution: Move FrontendType and MANDATORY_MENU_ITEMS to a new
app/modules/enums.py file. The models file re-exports them for
backward compatibility with existing imports.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The dev_tools API routes were moved to the monitoring module, but several
files still tried to import the non-existent admin_router. This caused
warnings during app startup.
Changes:
- Remove _get_admin_router() from definition.py
- Clear routes/__init__.py and routes/api/__init__.py of broken imports
- Update exceptions.py to import from monitoring.exceptions
- Update code_quality_service.py to import from monitoring.exceptions
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
MIGRATION:
- Move app/api/v1/vendor/info.py to app/modules/tenancy/routes/api/vendor.py
- Change endpoint path from GET /{vendor_code} to GET /info/{vendor_code}
- Remove catch-all route ordering dependency
TENANCY MODULE SETUP:
- Mark tenancy module as is_self_contained=True
- Add routes/api/vendor.py with vendor_router
- Add exceptions.py with TenancyException hierarchy
- Add placeholder __init__.py files for services, models, schemas
FRONTEND UPDATES:
- Update static/vendor/js/login.js to use new /vendor/info/{vendor_code} path
- Update static/vendor/js/init-alpine.js to use new /vendor/info/{vendor_code} path
The new path is more explicit and eliminates the need for catch-all route
ordering in the vendor router aggregation.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
MIGRATION:
- Delete app/api/v1/vendor/analytics.py (duplicate - analytics module already auto-discovered)
- Move usage routes from app/api/v1/vendor/usage.py to billing module
- Move onboarding routes from app/api/v1/vendor/onboarding.py to marketplace module
- Move features routes to billing module (admin + vendor)
- Move inventory routes to inventory module (admin + vendor)
- Move marketplace/letzshop routes to marketplace module
- Move orders routes to orders module
- Delete legacy letzshop service files (moved to marketplace module)
DOCUMENTATION:
- Add docs/development/migration/module-autodiscovery-migration.md with full migration history
- Update docs/architecture/module-system.md with Entity Auto-Discovery Reference section
- Add detailed sections for each entity type: routes, services, models, schemas, tasks,
exceptions, templates, static files, locales, configuration
ARCHITECTURE VALIDATION:
- Add MOD-016: Routes must be in modules, not app/api/v1/
- Add MOD-017: Services must be in modules, not app/services/
- Add MOD-018: Tasks must be in modules, not app/tasks/
- Add MOD-019: Schemas must be in modules, not models/schema/
- Update scripts/validate_architecture.py with _validate_legacy_locations method
- Update .architecture-rules/module.yaml with legacy location rules
These rules enforce that all entities must be in self-contained modules.
Legacy locations now trigger ERROR severity violations.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Move admin/products.py to marketplace module as admin_products.py
(marketplace product catalog browsing)
- Move admin/vendor_products.py to catalog module as admin.py
(vendor catalog management)
- Move vendor/products.py to catalog module as vendor.py
(vendor's own product catalog)
- Update marketplace admin router to include products routes
- Update catalog module routes/api/__init__.py with lazy imports
- Remove legacy imports from admin and vendor API init files
All product routes now auto-discovered via module system.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Enhanced route discovery system with ROUTE_CONFIG support for custom
prefix, tags, and priority
- Added get_admin_api_routes() and get_vendor_api_routes() helpers that
return routes sorted by priority
- Added fallback discovery for routes/{frontend}.py when routes/api/
doesn't exist
- Updated CMS module with ROUTE_CONFIG (prefix: /content-pages,
priority: 100) to register last for catch-all routes
- Moved customers routes from routes/ to routes/api/ directory
- Updated orders module to aggregate exception routers into main routers
- Removed manual module router imports from admin and vendor API init
files, replaced with auto-discovery loop
Modules now auto-discovered: billing, inventory, orders, marketplace,
cms, customers, analytics, loyalty, messaging, monitoring, dev-tools
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>