Add comprehensive email template management for both admin and vendors:
Admin Features:
- Email templates management page at /admin/email-templates
- Edit platform templates with language support (en, fr, de, lb)
- Preview templates with sample variables
- Send test emails
- View email logs per template
Vendor Features:
- Email templates customization page at /vendor/{code}/email-templates
- Override platform templates with vendor-specific versions
- Preview and test customized templates
- Revert to platform defaults
Technical Changes:
- Migration for vendor_email_templates table
- VendorEmailTemplate model with override management
- Enhanced EmailService with language resolution chain
(customer preferred -> vendor preferred -> platform default)
- Branding resolution (Wizamart default, removed for whitelabel)
- Platform-only template protection (billing templates)
- Admin and vendor API endpoints with full CRUD
- Updated seed script with billing and team templates
Files: 22 changed, ~3,900 lines added
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add slide-over panel for assigning features to subscription tiers
- Features grouped by category with select all/deselect all
- Add puzzle-piece icon button in tier table actions
- Add feature management methods to subscription-tiers.js
- Fix JS-006 by adding try/catch to init function
Documentation:
- Update feature-gating-system.md with Admin Tier Management UI section
- Update subscription-billing.md with tier management overview
- Add new admin user guide: subscription-tier-management.md
- Add guide to mkdocs.yml navigation
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Users are now redirected to their last visited page after logging in,
instead of always going to the dashboard.
Implementation:
- Track current page in localStorage on every page load
- Exclude login, logout, onboarding, and error pages from tracking
- On login success, redirect to last visited page if valid
- Clear last visited page on logout
Admin:
- static/admin/js/init-alpine.js: Save page to admin_last_visited_page
- static/admin/js/login.js: Redirect to last page after login
- app/templates/admin/partials/header.html: Clear on logout
Vendor:
- static/vendor/js/init-alpine.js: Save page to vendor_last_visited_page
- static/vendor/js/login.js: Redirect to last page (validates vendor code)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add loading: false to 5 components for JS-007 compliance
- Add try/catch to async init() functions for JS-006 compliance
- Remove noqa comments from company-edit, vendor-edit, user-edit
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add POST /admin/content-pages/vendor endpoint for vendor overrides
- Update JS to use /vendor or /platform endpoint based on vendor selection
- Platform endpoint forces vendor_id=None, vendor endpoint requires vendor_id
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Escape hyphen in regex pattern to fix Firefox regexp validation error
- Fix vendor API response parsing (use data.vendors instead of data.items)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Load vendors dynamically in content page editor dropdown
- Add show_in_legal field to default content pages seed script
- Set privacy and terms pages to show_in_legal=true, show_in_footer=false
- Update page creation in seed script to use show_in_legal
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add "Show in Legal" checkbox to content page editor UI
- Update API schemas (ContentPageCreate, ContentPageUpdate, ContentPageResponse)
- Add show_in_legal parameter to service methods (create_page, update_page, etc.)
- Fix ContentPageNotFoundException to pass identifier correctly
- Fix UnauthorizedContentPageAccessException to use correct AuthorizationException API
- Add comprehensive unit tests for ContentPageService (35 tests)
- Add content page fixtures for testing
- Update CMS documentation with navigation categories diagram
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Phase 6 - Database-driven tiers:
- Update subscription_service to query database first with legacy fallback
- Add get_tier_info() db parameter and _get_tier_from_legacy() method
Phase 7 - Platform health integration:
- Add get_subscription_capacity() for theoretical vs actual capacity
- Include subscription capacity in full health report
Phase 8 - Background subscription tasks:
- Add reset_period_counters() for billing period resets
- Add check_trial_expirations() for trial management
- Add sync_stripe_status() for Stripe synchronization
- Add cleanup_stale_subscriptions() for maintenance
- Add capture_capacity_snapshot() for daily metrics
Phase 10 - Capacity planning & forecasting:
- Add CapacitySnapshot model for historical tracking
- Create capacity_forecast_service with growth trends
- Add /subscription-capacity, /trends, /recommendations endpoints
- Add /snapshot endpoint for manual captures
Also includes billing API enhancements from phase 4:
- Add upcoming-invoice, change-tier, addon purchase/cancel endpoints
- Add UsageSummary schema for billing page
- Enhance billing.js with addon management functions
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Update th_sortable macro to call handleSort(key) instead of inline logic
- Add handleSort method to subscriptions.js, subscription-tiers.js, billing-history.js
- Add sort_by and sort_order params to API calls in all three files
- Reset to page 1 when sort changes
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add translations support with language tabs (EN, FR, DE, LU)
- Add product identifiers: vendor SKU with auto-generate, brand, GTIN, GTIN type
- Add pricing fields: price (incl. VAT), sale price, currency, VAT rate
- Add primary image field with preview
- Add product status (active, featured) checkboxes
- Add optional supplier info section
- Pre-populate form with existing product data from API
- Add form validation (isFormValid method)
- Make is_digital read-only (derived from marketplace product)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add warehouse and bin_location columns to Inventory model
- Create inventory_import_service for bulk TSV/CSV import
- Add POST /api/v1/admin/inventory/import endpoint
- Add Import button and modal to inventory admin page
- Support both single-unit rows and explicit QUANTITY column
File format: BIN, EAN, PRODUCT (optional), QUANTITY (optional)
Products matched by GTIN/EAN, unmatched items reported.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add "Create Product" button in header
- Update actions column to View, Edit, Delete
- Add create/edit pages with forms and vendor selector
- Add POST/PATCH API endpoints for vendor products
- Add create_product and update_product service methods
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Consolidate all tab-specific pagination into a unified pagination object
and use the shared pagination macro for consistent look and feel across
Orders, Products, Jobs, and Exceptions tabs.
🤖 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 /admin/letzshop/jobs API endpoint for all jobs across vendors
- Update list_letzshop_jobs service to support optional vendor_id
- Remove x-if condition from Jobs tab button and panel
- Update JS to use global or vendor-specific endpoint based on selection
- Update jobs table subtitle to show context
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add 'ban' icon to icons.js for empty state displays
- Fix products tab to load when no vendor filter is selected
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Update loadProducts() to show all Letzshop marketplace products when
no vendor is selected, filtered by vendor when one is selected
- Add vendor column to products table (shown when no vendor filter)
- Update header to show context-aware subtitle
- Hide Import/Export buttons when no vendor selected
- Remove "Marketplace Products" from sidebar menu (accessible via
Marketplace > Letzshop > Products tab)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add scanDropdownOpen to code-quality-dashboard.js
- Add error variable to notifications.js
These variables are required by templates but were missing from JS.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- messages.js: Add missing `error` property required by error_state macro
- platform-homepage.html: Use `<template x-if>` instead of `x-show` to
prevent Alpine from evaluating `page.template` when `page` is null
🤖 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>
- Create action_dropdown macro in dropdowns.html supporting:
- Loading/disabled state via loading_var parameter
- Custom loading label
- Icon support
- Primary/secondary variants
- Update code quality dashboard to use new macro
- Add Dropdowns section to components page with examples:
- Basic dropdown
- Action dropdown with loading state
- Context menu (3-dot)
- Variant showcase (primary, secondary, ghost)
Architecture validation now passes with 0 errors and 0 warnings.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add validator_type field to scans and violations (architecture,
security, performance)
- Create security validator with SEC-xxx rules
- Create performance validator with PERF-xxx rules
- Add base validator class for shared functionality
- Add validate_all.py script to run all validators
- Update code quality service with validator type filtering
- Add validator type tabs to dashboard UI
- Add validator type filter to violations list
- Update stats response with per-validator breakdown
- Add security and performance rules documentation
- Add chat-bubble icons to icon library
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add status fields to ArchitectureScan model (status, started_at,
completed_at, error_message, progress_message)
- Create database migration for new status fields
- Create background task function execute_code_quality_scan()
- Update API to return 202 with job IDs and support polling
- Add code quality scans to unified BackgroundTasksService
- Integrate scans into background tasks API and page
- Implement frontend polling with 3-second interval
- Add progress banner showing scan status
- Users can navigate away while scans run in background
- Document the implementation in architecture docs
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add job cancellation and retry functionality
- Improve jobs table with better status display
- Add background task improvements
- Update Letzshop order service
- Update documentation
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add admin customers API endpoints
- Add AdminCustomerService for customer operations
- Enhance customers.html template with management features
- Add customers.js Alpine component
- Add customer list schemas
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Replace browser alert with proper modal for job details view
- Show job info, status, records, timestamps in modal
- Display export file details (languages, file sizes) for export jobs
- Include error_details in API response for export and order_sync jobs
- Add selectedJobDetails state and showJobDetailsModal flag
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1. Products tab now shows Letzshop marketplace products instead of vendor products
- Uses /admin/products endpoint with marketplace=Letzshop filter
- Fixed field names (image_link, price_numeric, sku vs vendor_sku)
- Search now works with title, GTIN, SKU, brand
2. Jobs section moved to a separate tab
- New "Jobs" tab between Exceptions and Settings
- Tab watcher reloads data when switching tabs
- Updated filter dropdown (removed export, added historical_import)
3. Product stats endpoint now accepts marketplace and vendor_name filters
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Products Tab Changes:
- Converted to product listing page similar to /admin/marketplace-products
- Added Import/Export buttons in header
- Added product stats cards (total, active, inactive, last sync)
- Added search and filter functionality
- Added product table with pagination
- Import modal for single URL or all languages
Settings Tab Changes:
- Moved batch size setting from products tab
- Moved include inactive checkbox from products tab
- Added export behavior info box
Export Changes:
- New POST endpoint exports all languages (FR, DE, EN)
- CSV files written to exports/letzshop/{vendor_code}/ for scheduler pickup
- Letzshop scheduler can fetch files from this location
API Changes:
- Added vendor_id filter to /admin/vendor-products/stats endpoint
- Added POST /admin/vendors/{id}/export/letzshop for folder export
🤖 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>
Adds a new "Exceptions" tab to the Letzshop marketplace page for managing
unmatched product exceptions from order imports.
Features:
- Exception list with search and status filtering
- Stats cards showing pending/resolved/ignored counts
- Resolve modal with product search
- Bulk resolve option for same GTIN
- Ignore functionality
Files:
- New: letzshop-exceptions-tab.html partial template
- Updated: marketplace-letzshop.html (tab button, panel, resolve modal)
- Updated: marketplace-letzshop.js (exception state, methods)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Update all frontend templates and JavaScript to use new unified Order model:
- Orders tab: use status field, processing/cancelled values, items array
- Order detail: use snapshot fields, items array, tracking_provider
- JavaScript: update API params (status vs sync_status), orderStats fields
- Tracking modal: use tracking_provider instead of tracking_carrier
- Order items modal: use items array with item_state field
All status mappings:
- pending → pending (unconfirmed)
- processing → confirmed (at least one item available)
- cancelled → declined (all items unavailable)
- shipped → shipped (with tracking)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add Letzshop order detail page template
- Update orders list template
- Update Letzshop orders tab with improved UI
- Add JavaScript for order confirmation flow
Note: Frontend needs alignment with new unified order schema.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Per Letzshop API, each inventory unit must be confirmed/declined individually.
This enables partial confirmation (some items confirmed, others declined).
Admin API endpoints:
- POST /vendors/{id}/orders/{id}/confirm - confirm all items
- POST /vendors/{id}/orders/{id}/reject - decline all items
- POST /vendors/{id}/orders/{id}/items/{id}/confirm - confirm single item
- POST /vendors/{id}/orders/{id}/items/{id}/decline - decline single item
Order detail modal now shows:
- Product name, EAN, SKU, MPN, price per item
- Per-item state badge (unconfirmed/confirmed/declined)
- Per-item confirm/decline buttons for pending items
- Bulk confirm/decline all buttons
Order status logic:
- If all items declined -> order is "declined"
- If any item confirmed -> order is "confirmed"
- Partial confirmation supported
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Change UI labels to use 'Declined' (matching Letzshop terminology)
- Rename rejectOrder() to declineOrder() in JavaScript
- Add Declined stats card to orders dashboard
- Keep internal sync_status value as 'rejected' for backwards compatibility
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Historical import now fetches:
- state=confirmed -> sync_status='confirmed'
- state=declined -> sync_status='rejected'
Stats are combined from both API calls.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Fix historical import to also update sync_status when it's out of
sync with letzshop_state (e.g., confirmed orders showing as pending)
- Fix frontend to read stats from response.statistics nested object
- Orders with matching letzshop_state but wrong sync_status now get fixed
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add admin API endpoints for order management
- Add orders page with vendor selector and filtering
- Add order schemas for admin operations
- Support order status tracking and management
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add admin API endpoints for inventory management
- Add inventory page with vendor selector and filtering
- Add admin schemas for cross-vendor inventory operations
- Support digital products with unlimited inventory
- Add integration tests for admin inventory API
- Add inventory management guide documentation
Mirrors vendor inventory functionality with admin-level access.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add historical order import with pagination support
- Add customer_locale, shipping_country_iso, billing_country_iso columns
- Add gtin/gtin_type columns to Product table for EAN matching
- Fix order stats to count all orders server-side (not just visible page)
- Add GraphQL introspection script with tracking workaround tests
- Enrich inventory units with EAN, MPN, SKU, product name
- Add LetzshopOrderStats schema for proper status counts
Migrations:
- a9a86cef6cca: Add locale and country fields to letzshop_orders
- cb88bc9b5f86: Add gtin columns to products table
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add Notifications tab to Settings > General page
- Include email, in-app, and critical-only notification toggles
- Add link to full Notifications page in Platform Monitoring
- Add notificationSettings state and saveNotificationSettings method
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>