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>
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>
Add architecture rule that detects when API routes import database
models directly, enforcing Routes → Services → Models pattern.
Changes:
- Add API-007 rule to .architecture-rules/api.yaml
- Add _check_no_model_imports() validation to validator script
- Update customer imports to use canonical module location
- Add storefront module restructure implementation plan
The validator now detects 81 violations across 67 API files where
database models are imported directly instead of going through
services. This is Phase 1 of the storefront restructure plan.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Fix FastAPI static mount order: module statics must come BEFORE main
/static mount, otherwise the more general mount catches all requests
- Update validate_architecture.py to check self-contained module paths:
- JS files in app/modules/*/static/{admin,vendor}/js/
- Templates in app/modules/*/templates/*/{admin,vendor}/
- TPL-010 now finds module JS files for Alpine variable checking
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Fix JS-008: Replace raw fetch() with apiClient in letzshop-vendor-directory.js
- Fix JS-005: Add init guard to letzshop-vendor-directory.js
- Fix JS-004: Increase search region in validator (800→2000 chars) to detect
currentPage in files with setup code before return statement
- Fix JS-001: Use centralized logger in media-picker.js
- Fix API-002: Move database query from onboarding.py to order_service.py
- Fix FE-001: Add noqa comment to search.html (shop uses custom themed pagination)
- Add audit validator to validate_all.py script
- Update frontend.yaml with vendor exclusion pattern
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Detects deprecated buttons=[] parameter usage in page_header macro.
Correct API:
- Single button: action_label, action_icon, action_onclick
- Multiple buttons: use page_header_flex with {% call %}
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Added TPL-013 and TPL-014 rules to detect deprecated macro usage:
TPL-013: Use new pagination macro API
- Detects old parameters: current_page, total_pages, page_numbers, etc.
- New API only accepts show_condition parameter
- Component must provide standardized Alpine.js properties
TPL-014: Use new modal_simple macro API with call block
- Detects {{ modal_simple( instead of {% call modal_simple( %}
- Detects deprecated parameters: icon, confirm_text, confirm_fn, etc.
- New API uses {% call %}...{% endcall %} with content in body
These rules will catch template issues at validation time rather than
at runtime, preventing the TypeError crashes we saw.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Vendor API endpoints use JWT authentication, not URL path parameters.
The vendorCode should only be used for page URLs (navigation), not API calls.
Fixed API paths in 10 vendor JS files:
- analytics.js, customers.js, inventory.js, notifications.js
- order-detail.js, orders.js, products.js, profile.js
- settings.js, team.js
Added architecture rule JS-014 to prevent this pattern from recurring.
Added validation check _check_vendor_api_paths to validate_architecture.py.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Fixed copyCode template literal by using single quotes for outer attribute
- Added TPL-012 architecture rule to detect double quotes inside multi-line
copyCode template literals that break HTML attribute parsing
- Pattern: @click="copyCode(`...`)" with inner double quotes breaks parsing
- Solution: Use @click='copyCode(`...`)' with single quotes for outer attribute
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add TPL-011 architecture rule to detect deprecated macros
- Add pagination_full to deprecated macros list (expects flat vars)
- Fix billing-history.html to use standard pagination macro
- Add deprecation notice to pagination_full macro in pagination.html
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Shop endpoints can use three valid vendor context patterns:
- require_vendor_context() dependency
- # public - for public endpoints
- # authenticated - for customer-authenticated endpoints
Customer auth (get_current_customer_api) includes vendor context
validation, so # authenticated is a valid marker.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The NAM-004 rule was incorrectly matching 'letzshop_id' because it
contains 'shop_id' as a substring. Added regex word boundary (\b)
to only match standalone 'shop_id' identifiers.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The rules JS-005 (init guard), JS-006 (async error handling), JS-007
(loading state), JS-008 (apiClient vs fetch), and JS-009 (Utils.showToast)
were defined in _validate_js_file() but never called. Added these checks
to the main JavaScript validation loop.
This reveals 89 existing violations that need to be addressed.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Extended TPL-009 architecture rule to check vendor templates for invalid
block names (was only checking admin templates)
- Fixed billing.js to inherit base Alpine data via ...data() spread,
resolving undefined errors for dark, isSideMenuOpen, vendorCode
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Include static/vendor/js and static/shared/js in JS validation
- Fix onboarding.js: use apiClient (not window.apiClient), use logger
- Fix onboarding.js: use relative paths (not /api/v1/ prefix)
- Add noqa comments for standalone pages (login, onboarding)
- Add ...data() to messages.js for layout inheritance
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The table_header() macro doesn't support caller() - it takes a columns list.
Using {% call table_header() %} caused a Jinja2 error:
"macro 'table_header' was invoked with two values for the special caller argument"
Changes:
- Add table_header_custom() macro that supports caller() for custom headers
- Update subscriptions.html, subscription-tiers.html, billing-history.html
- Add TPL-008 architecture rule to detect this pattern
- Renumber TPL-009 (block names) and TPL-010 (Alpine vars)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add noqa: NAM-002 check in validate_architecture.py
- Mark stripe_webhook_handler.py with noqa (it's a handler, not a service)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Load rows per page from PlatformSettings in init()
- Apply setting to ordersLimit, exceptionsLimit, productsLimit, jobsPagination
- Replace alert() with Utils.showToast() for error display
- Improve viewJobErrors to show errors in modal instead of alert
- Update architecture validator to catch non-standard pagination patterns
(jobsPagination, ordersLimit, etc.)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add new rule to detect when templates use Alpine variables
(e.g., from error_state or action_dropdown macros) that are not
defined in the corresponding JavaScript component.
The rule:
- Checks for error_state macro usage (requires 'error' variable)
- Checks for action_dropdown macro with custom open_var/loading_var
- Cross-references with the matching JS file
- Reports errors when variables are missing
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The JS-003 and JS-004 rules were only in single-file validation,
not in full project validation. Also fixed regex to match functions
with parameters (like adminMessages(initialId = null)).
Fixed:
- messages.js: Added ...data() and currentPage
- notifications.js: Added ...data() and currentPage
- logs.js: Added noqa (uses baseData pattern with safety check)
- settings.js: Added noqa (uses baseData pattern with safety check)
- login.js: Added noqa (standalone page, no sidebar)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The TPL-008 rule was only in the single-file validation path,
not in the full project validation. Added it to _validate_templates().
Fixed invalid block names:
- customers.html: page_scripts → extra_scripts
- notifications.html: page_scripts → extra_scripts
- test-vendors-users-migration.html: scripts → extra_scripts
- test-auth-flow.html: scripts → extra_scripts
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Fix messages.html: change {% block page_scripts %} to {% block extra_scripts %}
(page_scripts doesn't exist in admin/base.html, causing JS not to load)
- Add TPL-008 architecture rule to catch invalid template block names
This prevents silent failures where content in undefined blocks is ignored
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Money Handling Architecture:
- Store all monetary values as integer cents (€105.91 = 10591)
- Add app/utils/money.py with Money class and conversion helpers
- Add static/shared/js/money.js for frontend formatting
- Update all database models to use _cents columns (Product, Order, etc.)
- Update CSV processor to convert prices to cents on import
- Add Alembic migration for Float to Integer conversion
- Create .architecture-rules/money.yaml with 7 validation rules
- Add docs/architecture/money-handling.md documentation
Order Details Page Fixes:
- Fix customer name showing 'undefined undefined' - use flat field names
- Fix vendor info empty - add vendor_name/vendor_code to OrderDetailResponse
- Fix shipping address using wrong nested object structure
- Enrich order detail API response with vendor info
Vendor Filter Persistence Fixes:
- Fix orders.js: restoreSavedVendor now sets selectedVendor and filters
- Fix orders.js: init() only loads orders if no saved vendor to restore
- Fix marketplace-letzshop.js: restoreSavedVendor calls selectVendor()
- Fix marketplace-letzshop.js: clearVendorSelection clears TomSelect dropdown
- Align vendor selector placeholder text between pages
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The Jinja |tojson filter outputs JSON with double quotes. When used
inside a double-quoted HTML attribute, these quotes break the attribute
parsing causing "expected expression, got '}'" errors.
Solution: Use single quotes for x-data attributes so JSON double quotes
don't conflict:
<div x-data='languageSelector("fr", {{ langs|tojson }})'>
Updated:
- language_selector.html macro (all 3 variants)
- shop/base.html language selector
- LANG-002 and LANG-003 architecture rules documentation
- Validator to detect double-quoted x-data with tojson
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Remove |safe from |tojson in HTML attributes (x-data) - quotes must
become " for browsers to parse correctly
- Update LANG-002 and LANG-003 architecture rules to document correct
|tojson usage patterns:
- HTML attributes: |tojson (no |safe)
- Script blocks: |tojson|safe
- Fix validator to warn when |tojson|safe is used in x-data (breaks
HTML attribute parsing)
- Improve code quality across services, APIs, and tests
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Split the monolithic .architecture-rules.yaml (1700+ lines) into focused
domain-specific files in .architecture-rules/ directory:
- _main.yaml: Core config, principles, ignore patterns, severity levels
- api.yaml: API endpoint rules (API-001 to API-005)
- service.yaml: Service layer rules (SVC-001 to SVC-007)
- model.yaml: Model rules (MDL-001 to MDL-004)
- exception.yaml: Exception handling rules (EXC-001 to EXC-005)
- naming.yaml: Naming convention rules (NAM-001 to NAM-005)
- auth.yaml: Auth and multi-tenancy rules (AUTH-*, MT-*)
- middleware.yaml: Middleware rules (MDW-001 to MDW-002)
- frontend.yaml: Frontend rules (JS-*, TPL-*, FE-*, CSS-*)
- language.yaml: Language/i18n rules (LANG-001 to LANG-010)
- quality.yaml: Code quality rules (QUAL-001 to QUAL-003)
Also creates scripts/validators/ module with base classes for future
modular validator extraction.
The validate_architecture.py loader now auto-detects and merges split
YAML files while maintaining backward compatibility with single file mode.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Change the validation report output to show a breakdown by severity
(errors, warnings, info) instead of a confusing "Total violations"
count that included info-level items.
Before: "Total violations: 4" followed by "VALIDATION PASSED"
After: "Findings: 0 errors, 0 warnings, 4 info" with "VALIDATION PASSED"
Also improve the failure/warning messages to include counts.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Architecture rules added:
- FE-008: Use number_stepper macro for quantity inputs
- FE-009: Use product_card macro for product displays
- FE-010: Use product_grid macro for product listings
- FE-011: Use add_to_cart macros for cart interactions
- FE-012: Use mini_cart macro for cart dropdown
Documentation:
- Update ui-components-quick-reference.md with e-commerce section
- Add component-standards.md for standardization guidelines
- Add ecommerce-components-proposal.md with full 20-component roadmap
- Update validate_architecture.py with FE-008 detection
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Migrated templates to use shared pagination macro:
- companies.html, users.html, vendors.html, code-quality-violations.html
Added noqa comments for templates with custom pagination variables:
- marketplace.html (page/limit/totalJobs)
- imports.html (page/limit/totalJobs)
- logs.html (filters.skip/limit/totalLogs)
- login.html (inline spinner SVG for loading state)
Also updated validate_architecture.py to:
- Support noqa: FE-001 comments for custom pagination
- Support noqa: FE-002 comments for intentional inline SVGs
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The _validate_templates() function was only checking TPL-001 (extends base).
FE-001 (pagination macro) and FE-002 ($icon helper) checks were only run
in single-file mode via _validate_html_file().
Now bulk validation also catches:
- Inline pagination that should use shared/macros/pagination.html
- Inline SVGs that should use $icon() helper
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add rules to enforce consistent frontend component usage:
- FE-001 (warning): Use pagination macro instead of inline HTML
- FE-002 (warning): Use $icon() helper instead of inline SVGs
- FE-003 (info): Use table macros for consistent styling
- FE-004 (info): Use form macros for consistent styling
Update validate_architecture.py to check FE-001 and FE-002
anti-patterns in templates, with exceptions for macro definitions
and the components showcase page.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Update architecture rules to be stricter (API-003 now blocks ALL exception
raising in endpoints, not just HTTPException)
- Update get_current_vendor_api dependency to guarantee token_vendor_id presence
- Remove redundant _get_vendor_from_token helpers from all vendor API files
- Move vendor access validation to service layer methods
- Add Pydantic response models for media, notification, and payment endpoints
- Add get_active_vendor_by_code service method for public vendor lookup
- Add get_import_job_for_vendor service method with vendor validation
- Update validation script to detect exception raising patterns in endpoints
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
API-002 updated:
- Remove db.commit() from anti-patterns (allowed at endpoint level)
- Add db.delete() to anti-patterns (business logic)
- Clarify that transaction control != business logic
SVC-006 added (new rule):
- Services should NOT call db.commit()
- Transaction control belongs at endpoint level
- Exception: log_service.py for audit log commits
- Severity: warning (to allow gradual migration)
This aligns with industry standard:
- One request = one transaction
- Services do work, endpoints control commits
- Enables composing multiple service calls in single transaction
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Add -f/--file option to validate a single file
- Add -d/--folder option to validate a directory
- Add -o/--object option to validate all files related to an entity
(e.g., company, vendor, user) with automatic singular/plural handling
- Add summary table showing pass/fail status per file with error/warning counts
- Remove deprecated positional path argument
Usage examples:
python scripts/validate_architecture.py -f app/api/v1/vendors.py
python scripts/validate_architecture.py -d app/api/
python scripts/validate_architecture.py -o company
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Fixed broken conditional logic in JavaScript validation that was causing
false positives on every single line of JS files.
Problem:
- Malformed ternary expression with 'if' inside condition
- 'else True' caused every line WITHOUT 'window.apiClient' to trigger
- Result: 3,144 violations (mostly false positives)
Solution:
- Simplified conditional to check if 'window.apiClient' exists first
- Then check if it's not in a comment
- Clearer, more maintainable logic
Results:
- Before: 3,144 total violations (3,000+ false JS-001 violations)
- After: 184 total violations (all legitimate)
- JS-001 violations: 0 (correct - no actual window.apiClient usage)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Update .architecture-rules.yaml to ignore venv/.venv directories
- Improve _should_ignore_file() method to handle venv path exclusions
- Add explicit checks for .venv/ and venv/ in file paths
This prevents the architecture validator from scanning thousands of
files in virtual environment directories, reducing validation time
from scanning all dependency files to just project files.
Before: Scanned venv files (thousands of violations in dependencies)
After: Only scans project files (123 files checked)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Replace black, isort, and flake8 with Ruff (all-in-one linter and formatter)
- Add comprehensive pyproject.toml configuration
- Simplify Makefile code quality targets
- Configure exclusions for venv/.venv in pyproject.toml
- Auto-fix 1,359 linting issues across codebase
Benefits:
- Much faster builds (Ruff is written in Rust)
- Single tool replaces multiple tools
- More comprehensive rule set (UP, B, C4, SIM, PIE, RET, Q)
- All configuration centralized in pyproject.toml
- Better import sorting and formatting consistency
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Standardize quote style (single to double quotes)
- Reorder and group imports alphabetically
- Fix line breaks and indentation for consistency
- Apply PEP 8 formatting standards
Also updated Makefile to exclude both venv and .venv from code quality checks.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>