Multi-line template literals in HTML attributes cause Alpine.js parsing
errors. Replaced @click="copyCode(...)" with static <pre><code> blocks.
Also simplified the x-text expression to use template literals.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Added {% raw %}{% endraw %} tags around the confirm_modal code snippets
to prevent Jinja2 from interpreting the {{ }} as template tags.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Added documentation and interactive examples for both confirm_modal
and confirm_modal_dynamic macros, showing danger, warning, info variants
and dynamic message capabilities.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Added a new macro that accepts an Alpine.js expression for the message,
allowing runtime data to be included in confirmation dialogs. Updated
admin-user-edit.html to use this macro for platform removal confirmation.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Changed from static confirm_modal macro to custom modal with Alpine.js
binding to display the platform name dynamically in the confirmation
message.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Replaced the native browser confirm() dialog with the styled confirm_modal
macro for a consistent UI experience when removing platform assignments
from admin users.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The admin user edit page now uses a dedicated template and JS file
that properly matches the /admin/admin-users/{id}/edit URL pattern.
The page allows super admins to:
- Toggle super admin status
- Toggle active status
- Manage platform assignments for platform admins
- Delete admin users
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add /admin/admin-users routes for managing admin users (super admin only)
- Remove vendor role from user creation form (vendors created via company hierarchy)
- Add admin-users.html and admin-user-detail.html templates
- Add admin-users.js and admin-user-detail.js for frontend logic
- Move database operations to admin_platform_service (list, get, create, delete, toggle status)
- Update sidebar to show Admin Users section only for super admins
- Add isSuperAdmin computed property to init-alpine.js
- Fix /api/v1 prefix issues in JS files (apiClient already adds prefix)
- Update architecture rule JS-012 to catch more variable patterns (url, endpoint, path)
- Replace inline SVGs with $icon() helper in select-platform.html
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
User create page:
- When role=admin, show super admin toggle
- If not super admin, show platform multi-select
- Admin users created via /api/v1/admin/admin-users endpoint
- Vendor users created via existing /admin/users endpoint
Vendor create page:
- Add platform selection section
- Vendors can be assigned to multiple platforms on creation
- Update VendorCreate schema to accept platform_ids
- Update AdminService.create_vendor() to create VendorPlatform records
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Frontend implementation of platform admin flow:
- Update login.js to check for platform selection after login
- Add platform selection page (/admin/select-platform)
- Add platform context indicator in admin header
- Add is_super_admin to UserResponse schema
- Show "Super Admin" badge or platform name with switch option
Platform admins now:
1. Login normally at /admin/login
2. Get redirected to /admin/select-platform if they have multiple platforms
3. See current platform in header with option to switch
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add structured JSON sections to ContentPage for multi-language homepage editing:
Database:
- Add `sections` JSON column to content_pages table
- Migration z8i9j0k1l2m3 adds the column
Schema:
- New models/schema/homepage_sections.py with Pydantic schemas
- TranslatableText for language-keyed translations
- HeroSection, FeaturesSection, PricingSection, CTASection
Templates:
- New section partials in app/templates/platform/sections/
- Updated homepage-default.html to render sections dynamically
- Fallback to placeholder content when sections not configured
Service:
- update_homepage_sections() - validate and save all sections
- update_single_section() - update individual section
- get_default_sections() - empty structure for new homepages
API:
- GET /{page_id}/sections - get sections with platform languages
- PUT /{page_id}/sections - update all sections
- PUT /{page_id}/sections/{section_name} - update single section
Admin UI:
- Section editor appears when editing homepage (slug='home')
- Language tabs from platform.supported_languages
- Accordion sections for Hero, Features, Pricing, CTA
- Button/feature card repeaters with add/remove
Also fixes broken line 181 in z4e5f6a7b8c9 migration.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Phase 2 - OMS Migration & Integration:
- Fix platform_pages.py to use get_platform_page for marketing pages
- Fix shop_pages.py to pass platform_id to content page service calls
Phase 3 - Admin Interface:
- Add platform management API (app/api/v1/admin/platforms.py)
- Add platforms admin page with stats cards
- Add Platforms menu item to admin sidebar
- Update content pages admin with platform filter and four-tab tier system
Phase 4 - Documentation:
- Add comprehensive architecture docs (docs/architecture/multi-platform-cms.md)
- Update implementation plan with completion status
Phase 5 - Vendor Dashboard:
- Add CMS usage API endpoint with tier limits
- Add usage progress bar to vendor content pages
- Add platform-default/{slug} API for preview
- Add View Default button and modal in page editor
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Rename static/shared/js/vendor/ to static/shared/js/lib/ to avoid
confusion with the app's "vendor" (seller) dashboard code in
static/vendor/js/.
- Rename directory: vendor/ → lib/
- Update all template references to use new path
- Update CDN fallback documentation
- Fix .gitignore to use /lib/ (root only) instead of lib/ (everywhere)
Third-party libraries:
- alpine.min.js
- chart.umd.min.js
- flatpickr.min.js
- quill.js
- tom-select.complete.min.js
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add LetzshopVendorCache model to store cached vendor data from Letzshop API
- Create LetzshopVendorSyncService for syncing vendor directory
- Add Celery task for background vendor sync
- Create admin page at /admin/letzshop/vendor-directory with:
- Stats dashboard (total, claimed, unclaimed vendors)
- Searchable/filterable vendor list
- "Sync Now" button to trigger sync
- Ability to create platform vendors from Letzshop cache
- Add API endpoints for vendor directory management
- Add Pydantic schemas for API responses
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Migrate background tasks from FastAPI BackgroundTasks to Celery with Redis
for persistent task queuing, retries, and scheduled jobs.
Key changes:
- Add Celery configuration with Redis broker/backend
- Create task dispatcher with USE_CELERY feature flag for gradual rollout
- Add Celery task wrappers for all background operations:
- Marketplace imports
- Letzshop historical imports
- Product exports
- Code quality scans
- Test runs
- Subscription scheduled tasks (via Celery Beat)
- Add celery_task_id column to job tables for Flower integration
- Add Flower dashboard link to admin background tasks page
- Update docker-compose.yml with worker, beat, and flower services
- Add Makefile targets: celery-worker, celery-beat, celery-dev, flower
When USE_CELERY=false (default), system falls back to FastAPI BackgroundTasks
for development without Redis dependency.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The media library returns relative paths like /uploads/... which
don't pass HTML5 url validation. Changed to type="text" to accept
both full URLs and relative paths from the media library.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add admin media API endpoints for vendor media management
- Create reusable media_picker_modal macro in modals.html
- Create mediaPickerMixin Alpine.js helper for media selection
- Update product create/edit forms with media picker UI
- Support main image + additional images selection
- Add upload functionality within the picker modal
- Update vendor_product_service to handle additional_images
- Add additional_images field to Pydantic schemas
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The override concept is no longer relevant with the independent copy
architecture. Products are fully independent entities, not inherited
from marketplace products. Removed all Override badges and updated
the info banner text to reflect the new architecture.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add is_digital and product_type columns to Product model
- Remove is_digital/product_type properties that derived from MarketplaceProduct
- Update Create form with translation tabs, GTIN type, sale price, VAT rate, image
- Update Edit form to allow editing is_digital (remove disabled state)
- Add Availability field to Edit form
- Fix Detail page for directly created products (no marketplace source)
- Update vendor_product_service to handle new fields in create/update
- Add VendorProductCreate/Update schema fields for translations and is_digital
- Add unit tests for is_digital column and direct product creation
- Add integration tests for create/update API with new fields
- Create product-architecture.md documenting the independent copy pattern
- Add migration y3d4e5f6g7h8 for is_digital and product_type columns
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
SMTP connections with no timeout were causing indefinite hangs when
connecting to invalid hosts. Also improved error display template.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Error and success messages were only shown at page top, not visible
when scrolled to Email tab. Now shows feedback directly below button.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Change icon from 'envelope' to 'mail' (envelope not in icons.js)
- Add default query param to GET /admin/settings/{key} endpoint
- Return AdminSettingDefaultResponse instead of 404 when default provided
- Update loadShippingSettings() to use default param for carrier settings
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
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>
The last visited page should persist across logout/login cycles so users
return to where they were. Only auth tokens should be cleared on logout.
🤖 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>
- 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>
Changed escaped double quotes to single quotes inside Jinja template
strings to prevent Alpine.js parsing error "Unexpected end of input".
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The script was being loaded twice - once from base.html and again from
vendor-themes.html, causing "vendorSelectorLog has already been declared".
🤖 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>
- Add chevron-double-left and chevron-double-right icons to icons.js
- Switch subscriptions page from pagination_full to pagination macro
(pagination_full expects flat variables but component uses nested pagination object)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The x-text expression had escaped quotes (\") which broke Alpine.js
parsing: 'Click \"Import Orders\" to fetch...'
Removed the quotes around "Import Orders" to fix the syntax error.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Replace window.apiClient with apiClient in feature-store.js (JS-002)
- Replace window.apiClient with apiClient in upgrade-prompts.js (JS-002)
- Replace inline SVGs with $icon() helper in features.html (FE-002)
- Add check-circle-filled icon to icons.js
Architecture validation now passes with 0 errors, 0 warnings.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implement database-driven feature gating with contextual upgrade prompts:
- Add Feature model with 30 features across 8 categories
- Create FeatureService with caching for tier-based feature checking
- Add @require_feature decorator and RequireFeature dependency for backend enforcement
- Create vendor features API (6 endpoints) and admin features API
- Add Alpine.js feature store and upgrade prompts store for frontend
- Create Jinja macros: feature_gate, feature_locked, limit_warning, usage_bar
- Add usage API for tracking orders/products/team limits with upgrade info
- Fix Stripe webhook to create VendorAddOn records on addon purchase
- Integrate upgrade prompts into vendor dashboard with tier badge and usage bars
🤖 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>
- Change rounded to rounded-full for pill appearance
- Add font-medium for better readability
- Improve dark mode colors with semi-transparent backgrounds
- Use lighter text colors in dark mode for better contrast
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add amber-colored "Legal" badge in the Navigation column to show pages
marked with show_in_legal=true alongside existing Header and Footer badges.
🤖 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>
- Fix admin header.html logout to not use localStorage.clear()
which was clearing vendor/customer tokens too
- Add tests for signup access_token generation
- Test that token is returned in response
- Test that token can authenticate API calls
- Test that vendor_token cookie is set
🤖 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>
The subscription templates were importing th_sortable but the macro
didn't exist. Added the macro to tables.html with:
- Clickable header with sort indicator arrows
- Alpine.js integration for sorting state
- Visual feedback for current sort column and direction
Also removed unused empty_state import from subscription-tiers.html.
🤖 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>