diff --git a/docs/proposals/loyalty-program-analysis.md b/docs/proposals/loyalty-program-analysis.md new file mode 100644 index 00000000..6e63bcc0 --- /dev/null +++ b/docs/proposals/loyalty-program-analysis.md @@ -0,0 +1,387 @@ +# Loyalty Program Platform - Business Analysis + +**Session Date:** 2026-01-13 +**Status:** Initial Analysis - Pending Discussion +**Next Steps:** Resume discussion to clarify requirements + +--- + +## Executive Summary + +Multiple retailers have expressed interest in a loyalty program application. This document analyzes how the current OMS platform could be leveraged to provide a loyalty program offering as a new product line. + +--- + +## Business Proposal Overview + +### Concept +- **Multi-platform offering**: Different platform tiers (A, B, C) with varying feature sets +- **Target clients**: Companies (retailers) with one or multiple shops +- **Core functionality**: + - Customer email collection + - Promotions and campaigns + - Discounts and rewards + - Points accumulation + +### Platform Architecture Vision + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ PLATFORM LEVEL │ +│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ +│ │ Platform A │ │ Platform B │ │ Platform C │ ... │ +│ │ (Loyalty+) │ │ (Basic) │ │ (Enterprise) │ │ +│ └──────────────┘ └──────────────┘ └──────────────┘ │ +└─────────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────┐ +│ CLIENT LEVEL (Company) │ +│ ┌──────────────────────────────────────────────────────────┐ │ +│ │ Retailer X (e.g., Bakery Chain) │ │ +│ │ ├── Shop 1 (Luxembourg City) │ │ +│ │ ├── Shop 2 (Esch) │ │ +│ │ └── Shop 3 (Differdange) │ │ +│ └──────────────────────────────────────────────────────────┘ │ +└─────────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────┐ +│ CUSTOMER LEVEL │ +│ • Email collection • Points accumulation │ +│ • Promotions/Offers • Discounts/Rewards │ +│ • Purchase history • Tier status │ +└─────────────────────────────────────────────────────────────────┘ +``` + +--- + +## Current OMS Architecture Leverage + +The existing platform has several components that map directly to loyalty program needs: + +| Current OMS Component | Loyalty Program Use | +|-----------------------|---------------------| +| `Company` model | Client (retailer chain) | +| `Vendor` model | Individual shop/location | +| `Customer` model | Loyalty member base | +| `Order` model | Transaction for points calculation | +| `User` (vendor role) | Shop staff for check-in/redemption | +| Multi-tenant auth | Per-client data isolation | +| Admin dashboard | Retailer management interface | +| Vendor dashboard | Shop-level operations | +| API infrastructure | Integration capabilities | + +### Existing Infrastructure Benefits +- Authentication & authorization system +- Multi-tenant data isolation +- Company → Vendor hierarchy +- Customer management +- Email/notification system (if exists) +- Celery background tasks +- API patterns established + +--- + +## New Components Required + +### 1. Core Loyalty Models + +```python +# New database models needed + +LoyaltyProgram + - id + - company_id (FK) + - name + - points_per_euro (Decimal) + - points_expiry_days (Integer, nullable) + - is_active (Boolean) + - settings (JSON) - flexible configuration + +LoyaltyMember + - id + - customer_id (FK to existing Customer) + - loyalty_program_id (FK) + - points_balance (Integer) + - lifetime_points (Integer) + - tier_id (FK) + - enrolled_at (DateTime) + - last_activity_at (DateTime) + +LoyaltyTier + - id + - loyalty_program_id (FK) + - name (e.g., "Bronze", "Silver", "Gold") + - min_points_required (Integer) + - benefits (JSON) + - sort_order (Integer) + +LoyaltyTransaction + - id + - member_id (FK) + - vendor_id (FK) - which shop + - transaction_type (ENUM: earn, redeem, expire, adjust) + - points (Integer, positive or negative) + - reference_type (e.g., "order", "promotion", "manual") + - reference_id (Integer, nullable) + - description (String) + - created_at (DateTime) + - created_by_user_id (FK, nullable) + +Promotion + - id + - loyalty_program_id (FK) + - name + - description + - promotion_type (ENUM: bonus_points, discount_percent, discount_fixed, free_item) + - value (Decimal) + - conditions (JSON) - min spend, specific products, etc. + - start_date (DateTime) + - end_date (DateTime) + - max_redemptions (Integer, nullable) + - is_active (Boolean) + +PromotionRedemption + - id + - promotion_id (FK) + - member_id (FK) + - vendor_id (FK) + - redeemed_at (DateTime) + - order_id (FK, nullable) + +Reward + - id + - loyalty_program_id (FK) + - name + - description + - points_cost (Integer) + - reward_type (ENUM: discount, free_product, voucher) + - value (Decimal or JSON) + - is_active (Boolean) + - stock (Integer, nullable) - for limited rewards +``` + +### 2. Platform Offering Tiers + +```python +# Platform-level configuration + +class PlatformOffering(Enum): + BASIC = "basic" + PLUS = "plus" + ENTERPRISE = "enterprise" + +# Feature matrix per offering +OFFERING_FEATURES = { + "basic": { + "max_shops": 1, + "points_earning": True, + "basic_promotions": True, + "tiers": False, + "custom_rewards": False, + "api_access": False, + "white_label": False, + "analytics": "basic", + }, + "plus": { + "max_shops": 10, + "points_earning": True, + "basic_promotions": True, + "tiers": True, + "custom_rewards": True, + "api_access": False, + "white_label": False, + "analytics": "advanced", + }, + "enterprise": { + "max_shops": None, # Unlimited + "points_earning": True, + "basic_promotions": True, + "tiers": True, + "custom_rewards": True, + "api_access": True, + "white_label": True, + "analytics": "full", + }, +} +``` + +### 3. Feature Matrix + +| Feature | Basic | Plus | Enterprise | +|---------|:-----:|:----:|:----------:| +| Customer email collection | ✓ | ✓ | ✓ | +| Points earning | ✓ | ✓ | ✓ | +| Basic promotions | ✓ | ✓ | ✓ | +| Multi-shop support | 1 shop | Up to 10 | Unlimited | +| Tier system (Bronze/Silver/Gold) | - | ✓ | ✓ | +| Custom rewards catalog | - | ✓ | ✓ | +| API access | - | - | ✓ | +| White-label branding | - | - | ✓ | +| Analytics dashboard | Basic | Advanced | Full | +| Customer segmentation | - | ✓ | ✓ | +| Email campaigns | - | ✓ | ✓ | +| Dedicated support | - | - | ✓ | + +--- + +## Implementation Options + +### Option A: Standalone Application +- Separate codebase +- Shares database patterns but independent deployment +- **Pros**: Clean separation, can scale independently +- **Cons**: Duplication of auth, admin patterns; more maintenance + +### Option B: Module in Current OMS (Recommended) +- Add loyalty as a feature module within existing platform +- Leverages existing infrastructure + +**Proposed directory structure:** +``` +letzshop-product-import/ +├── app/ +│ ├── api/v1/ +│ │ ├── loyalty/ # NEW +│ │ │ ├── __init__.py +│ │ │ ├── programs.py # Program CRUD +│ │ │ ├── members.py # Member management +│ │ │ ├── transactions.py # Points transactions +│ │ │ ├── promotions.py # Promotion management +│ │ │ ├── rewards.py # Rewards catalog +│ │ │ └── public.py # Customer-facing endpoints +│ │ │ +│ ├── services/ +│ │ ├── loyalty/ # NEW +│ │ │ ├── __init__.py +│ │ │ ├── points_service.py # Points calculation logic +│ │ │ ├── tier_service.py # Tier management +│ │ │ ├── promotion_service.py # Promotion rules engine +│ │ │ └── reward_service.py # Reward redemption +│ │ │ +│ ├── templates/ +│ │ ├── loyalty/ # NEW - if web UI needed +│ │ │ ├── admin/ # Platform admin views +│ │ │ ├── retailer/ # Retailer dashboard +│ │ │ └── member/ # Customer-facing portal +│ │ │ +├── models/ +│ ├── database/ +│ │ ├── loyalty.py # NEW - All loyalty models +│ ├── schema/ +│ │ ├── loyalty.py # NEW - Pydantic schemas +``` + +--- + +## Open Questions (To Discuss) + +### 1. Points Model +- **Q1.1**: Fixed points per euro spent? (e.g., 1 point = €0.10 spent) +- **Q1.2**: Variable points by product category? (e.g., 2x points on bakery items) +- **Q1.3**: Bonus points for specific actions? (e.g., sign-up bonus, birthday bonus) +- **Q1.4**: Points expiration policy? (e.g., expire after 12 months of inactivity) + +### 2. Redemption Methods +- **Q2.1**: In-store redemption only? (requires POS integration or staff app) +- **Q2.2**: Online shop redemption? +- **Q2.3**: Both in-store and online? +- **Q2.4**: What POS systems do target retailers use? + +### 3. Customer Identification +- **Q3.1**: Email only? +- **Q3.2**: Phone number as alternative? +- **Q3.3**: Physical loyalty card with barcode/QR? +- **Q3.4**: Mobile app with digital card? +- **Q3.5**: Integration with existing customer accounts? + +### 4. Multi-Platform Architecture +- **Q4.1**: Different domains per offering tier? + - e.g., loyalty-basic.lu, loyalty-pro.lu, loyalty-enterprise.lu +- **Q4.2**: Same domain with feature flags based on subscription? +- **Q4.3**: White-label with custom domains for enterprise clients? + +### 5. Data & Privacy +- **Q5.1**: Can retailers see each other's customers? (Assumed: No) +- **Q5.2**: Can a customer be enrolled in multiple loyalty programs? (Different retailers) +- **Q5.3**: GDPR considerations for customer data? +- **Q5.4**: Data export/portability requirements? + +### 6. Business Model +- **Q6.1**: Pricing model? (Monthly subscription, per-transaction fee, hybrid?) +- **Q6.2**: Free trial period? +- **Q6.3**: Upgrade/downgrade path between tiers? + +### 7. Integration Requirements +- **Q7.1**: POS system integrations needed? +- **Q7.2**: Email marketing platform integration? (Mailchimp, SendGrid, etc.) +- **Q7.3**: SMS notifications? +- **Q7.4**: Accounting/invoicing integration? + +### 8. MVP Scope +- **Q8.1**: What is the minimum viable feature set for first launch? +- **Q8.2**: Which offering tier to build first? +- **Q8.3**: Target timeline? +- **Q8.4**: Pilot retailers identified? + +--- + +## Potential User Flows + +### Retailer Onboarding Flow +1. Retailer signs up on platform +2. Selects offering tier (Basic/Plus/Enterprise) +3. Configures loyalty program (name, points ratio, branding) +4. Adds shop locations +5. Invites staff members +6. Sets up initial promotions +7. Goes live + +### Customer Enrollment Flow +1. Customer visits shop or website +2. Provides email (and optionally phone) +3. Receives welcome email with member ID/card +4. Starts earning points on purchases + +### Points Earning Flow (In-Store) +1. Customer makes purchase +2. Staff asks for loyalty member ID (email, phone, or card scan) +3. System calculates points based on purchase amount +4. Points credited to member account +5. Receipt shows points earned and balance + +### Reward Redemption Flow +1. Customer views available rewards (app/web/in-store) +2. Selects reward to redeem +3. System validates sufficient points +4. Generates redemption code/voucher +5. Customer uses at checkout +6. Points deducted from balance + +--- + +## Next Steps + +1. **Clarify requirements** - Answer open questions above +2. **Define MVP scope** - What's the minimum for first launch? +3. **Technical design** - Database schema, API design +4. **UI/UX design** - Retailer dashboard, customer portal +5. **Implementation plan** - Phased approach +6. **Pilot program** - Identify first retailers for beta + +--- + +## Session Notes + +### 2026-01-13 +- Initial business proposal discussion +- Analyzed current OMS architecture fit +- Identified reusable components +- Outlined new models needed +- Documented open questions +- **Action**: Resume discussion to clarify requirements + +--- + +*Document created for session continuity. Update as discussions progress.* diff --git a/docs/proposals/multi-platform-cms-architecture-implementation-plan.md b/docs/proposals/multi-platform-cms-architecture-implementation-plan.md new file mode 100644 index 00000000..d3c1d81f --- /dev/null +++ b/docs/proposals/multi-platform-cms-architecture-implementation-plan.md @@ -0,0 +1,406 @@ + Multi-Platform CMS Architecture Implementation Plan + + Summary + + Transform the single-platform OMS into a multi-platform system supporting independent business offerings (OMS, Loyalty, Site Builder), each with its own CMS, + vendor defaults, and marketing pages. + + --- + URL/Access Pattern Matrix + + Production Environment + ┌─────────────┬──────────┬───────────────────────────────────────────┬────────────────────────────────────────┐ + │ Persona │ Platform │ URL │ Purpose │ + ├─────────────┼──────────┼───────────────────────────────────────────┼────────────────────────────────────────┤ + │ Super Admin │ Global │ admin.wizamart.lu/ │ Global admin dashboard │ + ├─────────────┼──────────┼───────────────────────────────────────────┼────────────────────────────────────────┤ + │ │ │ admin.wizamart.lu/platforms │ Manage all platforms │ + ├─────────────┼──────────┼───────────────────────────────────────────┼────────────────────────────────────────┤ + │ │ │ admin.wizamart.lu/platforms/oms/pages │ OMS platform marketing pages │ + ├─────────────┼──────────┼───────────────────────────────────────────┼────────────────────────────────────────┤ + │ │ │ admin.wizamart.lu/platforms/oms/defaults │ OMS vendor default pages │ + ├─────────────┼──────────┼───────────────────────────────────────────┼────────────────────────────────────────┤ + │ │ │ admin.wizamart.lu/platforms/loyalty/pages │ Loyalty platform pages │ + ├─────────────┼──────────┼───────────────────────────────────────────┼────────────────────────────────────────┤ + │ Vendor │ OMS │ oms.lu/vendor/{code}/login │ Vendor login │ + ├─────────────┼──────────┼───────────────────────────────────────────┼────────────────────────────────────────┤ + │ │ │ oms.lu/vendor/{code}/dashboard │ Vendor dashboard │ + ├─────────────┼──────────┼───────────────────────────────────────────┼────────────────────────────────────────┤ + │ │ │ oms.lu/vendor/{code}/content-pages │ Manage CMS pages │ + ├─────────────┼──────────┼───────────────────────────────────────────┼────────────────────────────────────────┤ + │ │ Loyalty │ loyalty.lu/vendor/{code}/login │ Loyalty vendor login │ + ├─────────────┼──────────┼───────────────────────────────────────────┼────────────────────────────────────────┤ + │ Customer │ OMS │ {vendor}.oms.lu/ │ Vendor storefront (subdomain) │ + ├─────────────┼──────────┼───────────────────────────────────────────┼────────────────────────────────────────┤ + │ │ │ {vendor}.oms.lu/shop/ │ Shop pages │ + ├─────────────┼──────────┼───────────────────────────────────────────┼────────────────────────────────────────┤ + │ │ │ {vendor}.oms.lu/about │ Content page (3-tier fallback) │ + ├─────────────┼──────────┼───────────────────────────────────────────┼────────────────────────────────────────┤ + │ │ │ {customdomain}.com/ │ Custom domain storefront │ + ├─────────────┼──────────┼───────────────────────────────────────────┼────────────────────────────────────────┤ + │ Public │ OMS │ oms.lu/ │ Platform homepage │ + ├─────────────┼──────────┼───────────────────────────────────────────┼────────────────────────────────────────┤ + │ │ │ oms.lu/pricing │ Platform pricing page │ + ├─────────────┼──────────┼───────────────────────────────────────────┼────────────────────────────────────────┤ + │ │ │ oms.lu/about │ Platform about (is_platform_page=True) │ + ├─────────────┼──────────┼───────────────────────────────────────────┼────────────────────────────────────────┤ + │ │ Loyalty │ loyalty.lu/ │ Loyalty platform homepage │ + └─────────────┴──────────┴───────────────────────────────────────────┴────────────────────────────────────────┘ + Development Environment (localhost:9999) + ┌─────────────┬──────────┬────────────────────────────────────────────┬───────────────────────────┐ + │ Persona │ Platform │ URL │ Purpose │ + ├─────────────┼──────────┼────────────────────────────────────────────┼───────────────────────────┤ + │ Super Admin │ Global │ localhost:9999/admin/ │ Global admin │ + ├─────────────┼──────────┼────────────────────────────────────────────┼───────────────────────────┤ + │ │ │ localhost:9999/admin/platforms │ Platform management │ + ├─────────────┼──────────┼────────────────────────────────────────────┼───────────────────────────┤ + │ │ │ localhost:9999/admin/platforms/oms/pages │ OMS platform pages │ + ├─────────────┼──────────┼────────────────────────────────────────────┼───────────────────────────┤ + │ Vendor │ OMS │ localhost:9999/oms/vendor/{code}/login │ OMS vendor login │ + ├─────────────┼──────────┼────────────────────────────────────────────┼───────────────────────────┤ + │ │ │ localhost:9999/oms/vendor/{code}/dashboard │ OMS vendor dashboard │ + ├─────────────┼──────────┼────────────────────────────────────────────┼───────────────────────────┤ + │ │ Loyalty │ localhost:9999/loyalty/vendor/{code}/login │ Loyalty vendor login │ + ├─────────────┼──────────┼────────────────────────────────────────────┼───────────────────────────┤ + │ Customer │ OMS │ localhost:9999/oms/vendors/{code}/ │ Vendor root │ + ├─────────────┼──────────┼────────────────────────────────────────────┼───────────────────────────┤ + │ │ │ localhost:9999/oms/vendors/{code}/shop/ │ Vendor shop │ + ├─────────────┼──────────┼────────────────────────────────────────────┼───────────────────────────┤ + │ │ │ localhost:9999/oms/vendors/{code}/about │ Content page │ + ├─────────────┼──────────┼────────────────────────────────────────────┼───────────────────────────┤ + │ │ Loyalty │ localhost:9999/loyalty/vendors/{code}/ │ Loyalty vendor storefront │ + ├─────────────┼──────────┼────────────────────────────────────────────┼───────────────────────────┤ + │ Public │ OMS │ localhost:9999/oms/ │ OMS platform homepage │ + ├─────────────┼──────────┼────────────────────────────────────────────┼───────────────────────────┤ + │ │ │ localhost:9999/oms/pricing │ OMS pricing │ + ├─────────────┼──────────┼────────────────────────────────────────────┼───────────────────────────┤ + │ │ Loyalty │ localhost:9999/loyalty/ │ Loyalty platform homepage │ + └─────────────┴──────────┴────────────────────────────────────────────┴───────────────────────────┘ + --- + Three-Tier Content Resolution + + Customer visits: oms.lu/vendors/wizamart/about + │ + ▼ + ┌─────────────────────────────────────────────────────────────┐ + │ Tier 1: Vendor Override │ + │ SELECT * FROM content_pages │ + │ WHERE platform_id = 1 AND vendor_id = 123 AND slug = 'about' │ + │ │ + │ Found? → Return vendor's custom page │ + └─────────────────────────────────────────────────────────────┘ + │ Not found + ▼ + ┌─────────────────────────────────────────────────────────────┐ + │ Tier 2: Platform Vendor Default │ + │ SELECT * FROM content_pages │ + │ WHERE platform_id = 1 AND vendor_id IS NULL │ + │ AND is_platform_page = FALSE AND slug = 'about' │ + │ │ + │ Found? → Return platform default │ + └─────────────────────────────────────────────────────────────┘ + │ Not found + ▼ + Return 404 + + --- + Data Models + + New: Platform Model + + File: models/database/platform.py + + class Platform(Base): + id: Integer (PK) + code: String(50) unique # "oms", "loyalty", "sites" + name: String(100) # "Wizamart OMS" + domain: String(255) # "oms.lu" (production) + path_prefix: String(50) # "oms" (for localhost:9999/oms/*) + logo: String(500) + theme_config: JSON + is_active: Boolean + default_language: String(5) + supported_languages: JSON + + New: VendorPlatform Junction Table + + File: models/database/vendor_platform.py + + class VendorPlatform(Base): + id: Integer (PK) + vendor_id: FK → vendors.id + platform_id: FK → platforms.id + tier_id: FK → platform_subscription_tiers.id + is_active: Boolean + is_primary: Boolean # Vendor's primary platform + custom_subdomain: String(100) + settings: JSON + joined_at: DateTime + + # Constraints + UniqueConstraint(vendor_id, platform_id) + + Updated: SubscriptionTier Model (Extend Existing) + + File: models/database/subscription.py + + Add fields to existing model: + platform_id: FK → platforms.id (nullable for global tiers, set for platform-specific) + cms_pages_limit: Integer (nullable) # NULL = unlimited + cms_custom_pages_limit: Integer (nullable) + + Update constraint: + UniqueConstraint(platform_id, code) # Allow same tier code per platform + + Updated: ContentPage Model + + File: models/database/content_page.py + + Add fields: + platform_id: FK → platforms.id (NOT NULL) + is_platform_page: Boolean (default=False) + # True = Platform marketing page (homepage, pricing) + # False = Vendor default OR vendor override/custom + + Update constraint: + UniqueConstraint(platform_id, vendor_id, slug) + + New CMS Feature Codes + + File: models/database/feature.py + + CMS_BASIC = "cms_basic" + CMS_CUSTOM_PAGES = "cms_custom_pages" + CMS_UNLIMITED_PAGES = "cms_unlimited_pages" + CMS_TEMPLATES = "cms_templates" + CMS_SEO = "cms_seo" + + --- + New Middleware: PlatformContextMiddleware + + File: middleware/platform_context.py + + Runs BEFORE VendorContextMiddleware. + + Detection Priority: + 1. Path-based (dev): localhost:9999/oms/* → platform_code = "oms" + 2. Domain-based (prod): oms.lu → platform_code = "oms" + 3. Default: localhost → platform_code = "oms" (backwards compatibility) + + Sets: + - request.state.platform → Platform object + - request.state.platform_context → Detection metadata + - request.state.platform_clean_path → Path without platform prefix + + --- + Folder Organization + + Platform-Specific Folders (NEW) + + app/ + ├── platforms/ # NEW - Platform-specific code + │ ├── oms/ # OMS-specific + │ │ ├── routes/ # OMS-specific routes + │ │ ├── templates/ # OMS templates (homepage, etc.) + │ │ └── config.py # OMS configuration + │ ├── loyalty/ # Loyalty-specific + │ │ ├── routes/ + │ │ ├── templates/ + │ │ └── config.py + │ └── shared/ # Shared across platforms + │ └── base_platform.py + ├── services/ # Shared services (extended) + │ ├── content_page_service.py # Add platform_id support + │ ├── feature_service.py # Extend with platform awareness + │ └── subscription_service.py # Extend with platform awareness + ├── templates/ + │ └── platform/ # Keep existing, used by platform router + └── middleware/ + └── platform_context.py # NEW - Platform detection + + Shared vs Platform-Specific + ┌────────────────────┬─────────────────────────────────┬─────────────────────────────────────┐ + │ Type │ Location │ Example │ + ├────────────────────┼─────────────────────────────────┼─────────────────────────────────────┤ + │ Shared models │ models/database/ │ Platform, ContentPage, Vendor │ + ├────────────────────┼─────────────────────────────────┼─────────────────────────────────────┤ + │ Shared services │ app/services/ │ FeatureService, SubscriptionService │ + ├────────────────────┼─────────────────────────────────┼─────────────────────────────────────┤ + │ Shared middleware │ middleware/ │ PlatformContextMiddleware │ + ├────────────────────┼─────────────────────────────────┼─────────────────────────────────────┤ + │ Platform routes │ app/platforms/{code}/routes/ │ OMS homepage, Loyalty dashboard │ + ├────────────────────┼─────────────────────────────────┼─────────────────────────────────────┤ + │ Platform templates │ app/platforms/{code}/templates/ │ OMS-specific homepage │ + ├────────────────────┼─────────────────────────────────┼─────────────────────────────────────┤ + │ Platform config │ app/platforms/{code}/config.py │ Domain, features, defaults │ + └────────────────────┴─────────────────────────────────┴─────────────────────────────────────┘ + --- + Critical Files to Modify + ┌──────────────────────────────────────┬───────────────────────────────────────────────────────────────┐ + │ File │ Changes │ + ├──────────────────────────────────────┼───────────────────────────────────────────────────────────────┤ + │ models/database/platform.py │ NEW - Platform model │ + ├──────────────────────────────────────┼───────────────────────────────────────────────────────────────┤ + │ models/database/vendor_platform.py │ NEW - Junction table │ + ├──────────────────────────────────────┼───────────────────────────────────────────────────────────────┤ + │ models/database/subscription.py │ Add platform_id, cms_pages_limit to existing SubscriptionTier │ + ├──────────────────────────────────────┼───────────────────────────────────────────────────────────────┤ + │ models/database/content_page.py │ Add platform_id, is_platform_page │ + ├──────────────────────────────────────┼───────────────────────────────────────────────────────────────┤ + │ models/database/feature.py │ Add CMS feature codes │ + ├──────────────────────────────────────┼───────────────────────────────────────────────────────────────┤ + │ middleware/platform_context.py │ NEW - Platform detection middleware │ + ├──────────────────────────────────────┼───────────────────────────────────────────────────────────────┤ + │ middleware/vendor_context.py │ Update to use platform_clean_path │ + ├──────────────────────────────────────┼───────────────────────────────────────────────────────────────┤ + │ app/services/content_page_service.py │ Add platform_id to all methods │ + ├──────────────────────────────────────┼───────────────────────────────────────────────────────────────┤ + │ app/services/feature_service.py │ Extend has_feature() with platform context │ + ├──────────────────────────────────────┼───────────────────────────────────────────────────────────────┤ + │ app/services/subscription_service.py │ Extend tier lookup with platform context │ + ├──────────────────────────────────────┼───────────────────────────────────────────────────────────────┤ + │ app/platforms/oms/ │ NEW - OMS-specific code │ + ├──────────────────────────────────────┼───────────────────────────────────────────────────────────────┤ + │ app/platforms/loyalty/ │ NEW - Loyalty-specific code │ + ├──────────────────────────────────────┼───────────────────────────────────────────────────────────────┤ + │ main.py │ Register PlatformContextMiddleware, platform-prefixed routes │ + └──────────────────────────────────────┴───────────────────────────────────────────────────────────────┘ + --- + Migration Strategy + + Pre-Migration + + # 1. Create git tag + git add -A && git commit -m "chore: prepare for multi-platform migration" + git tag -a v1.0.0-pre-multiplatform -m "Before multi-platform CMS migration" + git push origin v1.0.0-pre-multiplatform + + # 2. Backup database + pg_dump wizamart > wizamart_backup_$(date +%Y%m%d).sql + + Migration Steps + + 1. Create platforms table with default "oms" platform + 2. Create vendor_platforms junction table + 3. Add platform_id, cms_pages_limit, cms_custom_pages_limit to existing subscription_tiers + 4. Add platform_id and is_platform_page to content_pages + 5. Backfill: Set all subscription_tiers.platform_id = OMS platform ID + 6. Backfill: Set all content_pages.platform_id = OMS platform ID + 7. Backfill: Set is_platform_page=True for extended slugs (homepage, pricing, about, contact, faq, terms, privacy, features, integrations) + 8. Create vendor_platforms entries for all existing vendors → OMS + 9. Update unique constraint on content_pages and subscription_tiers + + --- + Implementation Phases + + Phase 1: Database & Models + + - Create Platform model + - Create VendorPlatform junction table + - Create PlatformSubscriptionTier model + - Update ContentPage with platform_id, is_platform_page + - Add CMS feature codes + - Write Alembic migration + - Test migration on dev database + + Phase 2: Middleware & Services + + - Create PlatformContextMiddleware + - Update VendorContextMiddleware + - Update ContentPageService with three-tier resolution + - Create CMSLimitService + - Update middleware registration order in main.py + + Phase 3: Admin Interface + + - Platform management UI (/admin/platforms) + - Platform pages editor + - Vendor defaults editor + - Update content-pages list + + Phase 4: Vendor Dashboard + + - Show page source (Default/Override/Custom) + - "Override" action for defaults + - "Revert to Default" action + - Page limit indicators + + Phase 5: Routes & Templates + + - Register platform-prefixed routes (dev mode) + - Fix platform homepage to use CMS + - Update shop routes with platform context + - Test all URL patterns + + Phase 6: Loyalty Platform Setup + + - Create "loyalty" platform record + - Create loyalty platform pages + - Create loyalty vendor defaults + - Test full flow + + --- + Verification Steps + + 1. Git tag created: git tag -l | grep pre-multiplatform + 2. Migration successful: + SELECT * FROM platforms; + SELECT COUNT(*) FROM vendor_platforms; + SELECT platform_id, is_platform_page, COUNT(*) FROM content_pages GROUP BY 1, 2; + 3. Dev URLs work: + - localhost:9999/oms/ → OMS homepage + - localhost:9999/loyalty/ → Loyalty homepage + - localhost:9999/oms/vendor/wizamart/dashboard → Vendor dashboard + 4. Three-tier resolution: + - Create vendor override → shows override + - Delete override → shows platform default + - Delete default → shows 404 + 5. Page limits: Create pages until limit → shows upgrade prompt + + --- + Open Questions Resolved + ┌───────────────────────┬─────────────────────────────────────────────────────────────────────────────────────────┐ + │ Question │ Answer │ + ├───────────────────────┼─────────────────────────────────────────────────────────────────────────────────────────┤ + │ Domain routing │ Prod: separate domains / Dev: path-based │ + ├───────────────────────┼─────────────────────────────────────────────────────────────────────────────────────────┤ + │ Vendor multi-platform │ Yes, junction table │ + ├───────────────────────┼─────────────────────────────────────────────────────────────────────────────────────────┤ + │ Tier CMS restrictions │ Yes, integrate with existing feature system │ + ├───────────────────────┼─────────────────────────────────────────────────────────────────────────────────────────┤ + │ MVP scope │ OMS + Loyalty, git tag first │ + ├───────────────────────┼─────────────────────────────────────────────────────────────────────────────────────────┤ + │ Admin structure │ Global super admin only (/admin/*) │ + ├───────────────────────┼─────────────────────────────────────────────────────────────────────────────────────────┤ + │ CMS page limits │ Essential: 3, Pro: 10, Business: 30, Enterprise: unlimited │ + ├───────────────────────┼─────────────────────────────────────────────────────────────────────────────────────────┤ + │ Platform page slugs │ platform_homepage, pricing, about, contact, faq, terms, privacy, features, integrations │ + └───────────────────────┴─────────────────────────────────────────────────────────────────────────────────────────┘ + --- + CMS Tier Limits (Final) + ┌──────────────┬─────────────┬──────────────┬─────────────────────────────────────────────────────┐ + │ Tier │ Total Pages │ Custom Pages │ Features │ + ├──────────────┼─────────────┼──────────────┼─────────────────────────────────────────────────────┤ + │ Essential │ 3 │ 0 │ cms_basic │ + ├──────────────┼─────────────┼──────────────┼─────────────────────────────────────────────────────┤ + │ Professional │ 10 │ 5 │ cms_basic, cms_custom_pages, cms_seo │ + ├──────────────┼─────────────┼──────────────┼─────────────────────────────────────────────────────┤ + │ Business │ 30 │ 20 │ cms_basic, cms_custom_pages, cms_seo, cms_templates │ + ├──────────────┼─────────────┼──────────────┼─────────────────────────────────────────────────────┤ + │ Enterprise │ Unlimited │ Unlimited │ cms_unlimited_pages, cms_scheduling │ + └──────────────┴─────────────┴──────────────┴─────────────────────────────────────────────────────┘ + --- + Platform Marketing Page Slugs (is_platform_page=True) + + These slugs will be marked as platform marketing pages during migration: + - platform_homepage (or home) + - pricing + - about + - contact + - faq + - terms + - privacy + - features + - integrations + + All other vendor_id=NULL pages become vendor defaults (is_platform_page=False). \ No newline at end of file diff --git a/docs/proposals/multi-platform-cms-architecture.md b/docs/proposals/multi-platform-cms-architecture.md new file mode 100644 index 00000000..162c360d --- /dev/null +++ b/docs/proposals/multi-platform-cms-architecture.md @@ -0,0 +1,603 @@ +# Multi-Platform CMS Architecture + +**Session Date:** 2026-01-18 +**Status:** Initial Analysis - Requirements Captured +**Related:** [Loyalty Program Analysis](./loyalty-program-analysis.md) + +--- + +## Executive Summary + +The platform is evolving from a single OMS product to a **multi-platform business** where each platform represents a distinct business offering (OMS, Loyalty Program, Website Builder, etc.). Each platform requires its own independent CMS with a three-tier content hierarchy: + +1. **Platform Pages** - Marketing site for the platform itself +2. **Vendor Default Pages** - Fallback content for vendor storefronts +3. **Vendor Override/Custom Pages** - Vendor-specific content + +--- + +## Current State Analysis + +### Problems Identified + +| Issue | Description | +|-------|-------------| +| **Conflated page types** | Platform pages and vendor defaults share `vendor_id = NULL`, making them indistinguishable | +| **Hardcoded homepage** | Platform homepage uses `homepage-wizamart.html` directly, ignoring CMS | +| **Non-functional admin UI** | `/admin/platform-homepage` saves to CMS but route doesn't use it | +| **Single platform assumption** | Architecture assumes one platform, can't scale to multiple offerings | +| **No platform isolation** | No way to have separate About/FAQ/Pricing pages per platform | + +### Current Architecture (Broken) + +``` +ContentPage (vendor_id = NULL) + ↓ used by both (conflated) + ├── Platform Homepage (/about, /pricing) ← Should be Platform A specific + └── Vendor Default Fallback ← Should be generic storefront pages +``` + +--- + +## Proposed Architecture + +### Multi-Platform Hierarchy + +``` +┌─────────────────────────────────────────────────────────────────────────────┐ +│ PLATFORM LEVEL │ +│ ┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐ │ +│ │ Platform A │ │ Platform B │ │ Platform C │ │ +│ │ (Wizamart OMS) │ │ (Loyalty+) │ │ (Site Builder) │ │ +│ │ │ │ │ │ │ │ +│ │ • Homepage │ │ • Homepage │ │ • Homepage │ │ +│ │ • About │ │ • About │ │ • About │ │ +│ │ • Pricing │ │ • Pricing │ │ • Pricing │ │ +│ │ • FAQ │ │ • FAQ │ │ • FAQ │ │ +│ │ • Contact │ │ • Contact │ │ • Contact │ │ +│ └──────────────────┘ └──────────────────┘ └──────────────────┘ │ +└─────────────────────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────────────────┐ +│ VENDOR DEFAULT LEVEL (per platform) │ +│ ┌──────────────────────────────────────────────────────────────────────┐ │ +│ │ Platform A Defaults │ │ +│ │ • About Us (generic store template) │ │ +│ │ • Shipping Policy │ │ +│ │ • Return Policy │ │ +│ │ • Privacy Policy │ │ +│ │ • Terms of Service │ │ +│ │ • FAQ (e-commerce focused) │ │ +│ └──────────────────────────────────────────────────────────────────────┘ │ +└─────────────────────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────────────────┐ +│ VENDOR LEVEL (isolated) │ +│ ┌─────────────────────────┐ ┌─────────────────────────┐ │ +│ │ Vendor 1 (WizaMart) │ │ Vendor 2 (TechStore) │ │ +│ │ Platform A, Tier: Pro │ │ Platform A, Tier: Basic │ │ +│ │ │ │ │ │ +│ │ Override Pages: │ │ Override Pages: │ │ +│ │ • About (custom) │ │ • (none - uses defaults)│ │ +│ │ • Shipping (custom) │ │ │ │ +│ │ │ │ Custom Pages: │ │ +│ │ Custom Pages: │ │ • Size Guide │ │ +│ │ • Our Story │ │ │ │ +│ │ • Store Locations │ │ │ │ +│ └─────────────────────────┘ └─────────────────────────┘ │ +└─────────────────────────────────────────────────────────────────────────────┘ +``` + +### Content Resolution Flow + +When a customer visits `vendor1.example.com/about`: + +``` +1. Identify vendor context (Vendor 1) +2. Identify platform context (Platform A) +3. Check: Does Vendor 1 have custom "about" page? + ├── YES → Return vendor's custom page + └── NO → Check: Does Platform A have default "about" page? + ├── YES → Return platform default + └── NO → Return 404 +``` + +--- + +## Data Model Changes + +### New: Platform Model + +```python +class Platform(Base): + """ + Represents a business offering/product line. + Examples: Wizamart OMS, Loyalty+, Site Builder + """ + __tablename__ = "platforms" + + id = Column(Integer, primary_key=True) + code = Column(String(50), unique=True, nullable=False) # "oms", "loyalty", "sites" + name = Column(String(100), nullable=False) # "Wizamart OMS" + domain = Column(String(255), nullable=True) # "wizamart.lu" + + # Branding + logo = Column(String(500), nullable=True) + theme_config = Column(JSON, nullable=True) # Colors, fonts, etc. + + # Status + is_active = Column(Boolean, default=True) + + # Timestamps + created_at = Column(DateTime, default=func.now()) + updated_at = Column(DateTime, default=func.now(), onupdate=func.now()) + + # Relationships + content_pages = relationship("ContentPage", back_populates="platform") + subscription_tiers = relationship("SubscriptionTier", back_populates="platform") + vendors = relationship("Vendor", back_populates="platform") +``` + +### Updated: ContentPage Model + +```python +class ContentPage(Base): + """ + CMS content page with three-tier hierarchy: + 1. Platform pages (platform_id set, vendor_id NULL, is_platform_page=True) + 2. Vendor defaults (platform_id set, vendor_id NULL, is_platform_page=False) + 3. Vendor overrides (platform_id set, vendor_id set) + """ + __tablename__ = "content_pages" + + id = Column(Integer, primary_key=True) + + # NEW: Platform association (required) + platform_id = Column(Integer, ForeignKey("platforms.id"), nullable=False) + + # Existing: Vendor association (NULL for platform pages and defaults) + vendor_id = Column(Integer, ForeignKey("vendors.id"), nullable=True) + + # NEW: Distinguish platform marketing pages from vendor defaults + is_platform_page = Column(Boolean, default=False, nullable=False) + # True = Platform's own page (homepage, pricing, platform about) + # False = Vendor default template (when vendor_id is NULL) + # N/A = Vendor override (when vendor_id is set) + + # Existing fields... + slug = Column(String(100), nullable=False) + title = Column(String(200), nullable=False) + content = Column(Text, nullable=False) + content_format = Column(String(20), default="html") + template = Column(String(50), default="default") + + # SEO + meta_description = Column(String(300), nullable=True) + meta_keywords = Column(String(300), nullable=True) + + # Publishing + is_published = Column(Boolean, default=False) + published_at = Column(DateTime, nullable=True) + + # Navigation + display_order = Column(Integer, default=0) + show_in_header = Column(Boolean, default=False) + show_in_footer = Column(Boolean, default=True) + show_in_legal = Column(Boolean, default=False) + + # Timestamps & audit + created_at = Column(DateTime, default=func.now()) + updated_at = Column(DateTime, default=func.now(), onupdate=func.now()) + created_by = Column(Integer, ForeignKey("users.id"), nullable=True) + updated_by = Column(Integer, ForeignKey("users.id"), nullable=True) + + # Constraints + __table_args__ = ( + UniqueConstraint("platform_id", "vendor_id", "slug", name="uq_platform_vendor_slug"), + Index("idx_platform_vendor_published", "platform_id", "vendor_id", "is_published"), + ) +``` + +### Updated: Vendor Model + +```python +class Vendor(Base): + # Existing fields... + + # NEW: Platform association + platform_id = Column(Integer, ForeignKey("platforms.id"), nullable=False) + platform = relationship("Platform", back_populates="vendors") +``` + +--- + +## Page Type Matrix + +| Page Type | platform_id | vendor_id | is_platform_page | Example | +|-----------|:-----------:|:---------:|:----------------:|---------| +| Platform Marketing Page | ✓ | NULL | TRUE | Platform A's homepage, pricing | +| Vendor Default Page | ✓ | NULL | FALSE | Generic "About Our Store" template | +| Vendor Override Page | ✓ | ✓ | FALSE | WizaMart's custom About page | +| Vendor Custom Page | ✓ | ✓ | FALSE | WizaMart's "Store Locations" page | + +--- + +## User Journeys + +### Journey 1: Platform Admin Sets Up New Platform + +**Actor:** Super Admin +**Goal:** Create a new business platform with its marketing pages + +``` +1. Admin navigates to /admin/platforms +2. Admin clicks "Create Platform" +3. Admin fills in: + - Code: "loyalty" + - Name: "Loyalty+" + - Domain: "loyalty.wizamart.lu" + - Logo, theme colors +4. Admin saves platform +5. System creates platform record +6. Admin navigates to /admin/platforms/loyalty/pages +7. Admin creates platform pages: + - Homepage (is_platform_page=True) + - About Us (is_platform_page=True) + - Pricing (is_platform_page=True) + - FAQ (is_platform_page=True) + - Contact (is_platform_page=True) +8. Each page can use different templates (modern, minimal, etc.) +9. Admin publishes pages +10. Platform marketing site is now live at loyalty.wizamart.lu +``` + +### Journey 2: Platform Admin Creates Vendor Defaults + +**Actor:** Platform Admin +**Goal:** Set up default storefront pages for all vendors on Platform A + +``` +1. Admin navigates to /admin/platforms/oms/vendor-defaults +2. Admin sees list of vendor default pages +3. Admin creates default pages: + - About Us (generic store template) + Content: "Welcome to our store. We're dedicated to..." + - Shipping Policy + Content: "We offer fast and reliable shipping..." + - Return Policy + Content: "30-day return policy on all items..." + - Privacy Policy + Content: "Your privacy is important to us..." + - Terms of Service + Content: "By using our store, you agree to..." +4. All pages have is_platform_page=False, vendor_id=NULL +5. These pages are now available to ALL vendors on Platform A +6. Vendors who don't customize will see these defaults +``` + +### Journey 3: Vendor Subscribes and Views Default Pages + +**Actor:** New Vendor (TechStore) +**Goal:** Start using the platform and see what pages are available + +``` +1. Vendor signs up for Platform A (OMS), selects "Basic" tier +2. Vendor completes onboarding +3. Vendor logs into dashboard +4. Vendor navigates to "Content Pages" section +5. Vendor sees list of pages: + ┌─────────────────────────────────────────────────────────┐ + │ Content Pages │ + ├─────────────────────────────────────────────────────────┤ + │ Page │ Source │ Status │ Actions │ + ├───────────────┼──────────────────┼───────────┼─────────┤ + │ About Us │ Platform Default │ Published │ Override│ + │ Shipping │ Platform Default │ Published │ Override│ + │ Returns │ Platform Default │ Published │ Override│ + │ Privacy │ Platform Default │ Published │ Override│ + │ Terms │ Platform Default │ Published │ Override│ + └─────────────────────────────────────────────────────────┘ + + [+ Create Custom Page] + +6. Vendor previews storefront at techstore.example.com/about +7. Sees platform default "About Us" content +``` + +### Journey 4: Vendor Overrides a Default Page + +**Actor:** Vendor (WizaMart) +**Goal:** Customize the About page with store-specific content + +``` +1. Vendor logs into dashboard +2. Navigates to Content Pages +3. Sees "About Us" with source "Platform Default" +4. Clicks "Override" button +5. System creates a copy with vendor_id set +6. Vendor edits content: + - Title: "About WizaMart" + - Content: "WizaMart was founded in 2020 in Luxembourg..." + - Adds store images +7. Vendor saves and publishes +8. Page list now shows: + ┌─────────────────────────────────────────────────────────┐ + │ About Us │ Custom Override │ Published │ Edit │ + └─────────────────────────────────────────────────────────┘ +9. Customer visits wizamart.example.com/about +10. Sees WizaMart's custom About page +``` + +### Journey 5: Vendor Creates a Custom Page + +**Actor:** Vendor (WizaMart) +**Goal:** Add a new page that doesn't exist in defaults + +``` +1. Vendor logs into dashboard +2. Navigates to Content Pages +3. Clicks "+ Create Custom Page" +4. Fills in: + - Slug: "store-locations" + - Title: "Our Store Locations" + - Content: Map and addresses of physical stores + - Show in footer: Yes +5. Vendor saves and publishes +6. Page appears in storefront footer navigation +7. Accessible at wizamart.example.com/store-locations +``` + +### Journey 6: Vendor Reverts Override to Default + +**Actor:** Vendor (WizaMart) +**Goal:** Remove customization and use platform default again + +``` +1. Vendor navigates to Content Pages +2. Sees "Shipping" with source "Custom Override" +3. Clicks "Revert to Default" +4. System shows confirmation: + "This will delete your custom Shipping page and show + the platform default instead. This cannot be undone." +5. Vendor confirms +6. System deletes vendor's custom page +7. Storefront now shows platform default Shipping page +``` + +### Journey 7: Customer Browses Vendor Storefront + +**Actor:** Customer +**Goal:** Read store policies before purchasing + +``` +1. Customer visits wizamart.example.com +2. Browses products, adds to cart +3. Wants to check return policy +4. Clicks "Returns" in footer +5. System resolves page: + - Check: WizaMart override? NO + - Check: Platform A default? YES + - Serve: Platform A default "Return Policy" page +6. Customer reads return policy +7. Customer clicks "About Us" in footer +8. System resolves page: + - Check: WizaMart override? YES + - Serve: WizaMart's custom "About WizaMart" page +9. Customer sees store-specific About page +``` + +--- + +## Workflow Diagrams + +### Content Resolution Algorithm + +``` +resolve_page(vendor, slug): + │ + ├─► Get vendor's platform_id + │ + ├─► Query: ContentPage WHERE + │ platform_id = vendor.platform_id + │ AND vendor_id = vendor.id + │ AND slug = slug + │ AND is_published = True + │ + ├─► Found? ──YES──► Return vendor's page + │ │ + │ NO + │ ▼ + ├─► Query: ContentPage WHERE + │ platform_id = vendor.platform_id + │ AND vendor_id IS NULL + │ AND is_platform_page = False ← Important: exclude platform pages + │ AND slug = slug + │ AND is_published = True + │ + ├─► Found? ──YES──► Return platform default + │ │ + │ NO + │ ▼ + └─► Return 404 +``` + +### Platform Page Resolution (Marketing Site) + +``` +resolve_platform_page(platform, slug): + │ + ├─► Query: ContentPage WHERE + │ platform_id = platform.id + │ AND vendor_id IS NULL + │ AND is_platform_page = True ← Only platform marketing pages + │ AND slug = slug + │ AND is_published = True + │ + ├─► Found? ──YES──► Return platform page + │ │ + │ NO + │ ▼ + └─► Return 404 +``` + +--- + +## API Endpoints + +### Platform Admin API + +``` +# Platform Management +GET /api/v1/admin/platforms # List all platforms +POST /api/v1/admin/platforms # Create platform +GET /api/v1/admin/platforms/{code} # Get platform +PUT /api/v1/admin/platforms/{code} # Update platform +DELETE /api/v1/admin/platforms/{code} # Delete platform + +# Platform Pages (Marketing) +GET /api/v1/admin/platforms/{code}/pages # List platform pages +POST /api/v1/admin/platforms/{code}/pages # Create platform page +PUT /api/v1/admin/platforms/{code}/pages/{id} # Update platform page +DELETE /api/v1/admin/platforms/{code}/pages/{id} # Delete platform page + +# Vendor Defaults +GET /api/v1/admin/platforms/{code}/defaults # List vendor defaults +POST /api/v1/admin/platforms/{code}/defaults # Create vendor default +PUT /api/v1/admin/platforms/{code}/defaults/{id}# Update vendor default +DELETE /api/v1/admin/platforms/{code}/defaults/{id}# Delete vendor default +``` + +### Vendor API + +``` +# View All Pages (defaults + overrides + custom) +GET /api/v1/vendor/{code}/content-pages # List all pages + +# Override/Custom Page Management +POST /api/v1/vendor/{code}/content-pages # Create override/custom +PUT /api/v1/vendor/{code}/content-pages/{id} # Update page +DELETE /api/v1/vendor/{code}/content-pages/{id} # Delete/revert page + +# Page Preview +GET /api/v1/vendor/{code}/content-pages/{slug}/preview # Preview with fallback +``` + +### Public API + +``` +# Storefront Pages (with fallback resolution) +GET /api/v1/shop/content-pages/{slug} # Get page (vendor context from middleware) +GET /api/v1/shop/content-pages/navigation # Get nav pages + +# Platform Marketing Pages +GET /api/v1/platform/{code}/pages/{slug} # Get platform page +GET /api/v1/platform/{code}/pages/navigation # Get platform nav +``` + +--- + +## Implementation Phases + +### Phase 1: Database & Model Updates +- [ ] Create `Platform` model +- [ ] Add `platform_id` to `ContentPage` +- [ ] Add `is_platform_page` to `ContentPage` +- [ ] Add `platform_id` to `Vendor` +- [ ] Create migration scripts +- [ ] Create default "oms" platform for existing data + +### Phase 2: Service Layer +- [ ] Update `ContentPageService` with three-tier resolution +- [ ] Add `PlatformService` for platform CRUD +- [ ] Update page listing to show source (Platform/Default/Override) + +### Phase 3: Admin Interface +- [ ] Platform management UI (`/admin/platforms`) +- [ ] Platform pages editor (`/admin/platforms/{code}/pages`) +- [ ] Vendor defaults editor (`/admin/platforms/{code}/defaults`) +- [ ] Fix platform homepage to use CMS + +### Phase 4: Vendor Dashboard +- [ ] Update content pages list to show page source +- [ ] Add "Override" action for default pages +- [ ] Add "Revert to Default" action for overrides +- [ ] Visual indicator for inherited vs custom pages + +### Phase 5: Public Routes +- [ ] Update shop routes with three-tier resolution +- [ ] Update platform routes to use CMS +- [ ] Ensure proper navigation loading per context + +--- + +## Migration Strategy + +### Existing Data Handling + +```sql +-- 1. Create default platform +INSERT INTO platforms (code, name, domain, is_active) +VALUES ('oms', 'Wizamart OMS', 'localhost:8000', true); + +-- 2. Update all existing content_pages +UPDATE content_pages +SET platform_id = (SELECT id FROM platforms WHERE code = 'oms'); + +-- 3. Mark platform marketing pages +UPDATE content_pages +SET is_platform_page = true +WHERE vendor_id IS NULL + AND slug IN ('platform_homepage', 'pricing'); + +-- 4. Remaining NULL vendor pages become vendor defaults +UPDATE content_pages +SET is_platform_page = false +WHERE vendor_id IS NULL + AND is_platform_page IS NULL; + +-- 5. Update all vendors +UPDATE vendors +SET platform_id = (SELECT id FROM platforms WHERE code = 'oms'); +``` + +--- + +## Open Questions + +1. **Domain routing**: How to route requests to correct platform? + - Option A: Separate domains (oms.wizamart.lu, loyalty.wizamart.lu) + - Option B: Path-based (/oms/*, /loyalty/*) + - Option C: Subdomain detection + +2. **Shared vendors**: Can a vendor belong to multiple platforms? + - Current assumption: NO, one vendor per platform + - If YES: Need junction table + +3. **Tier restrictions**: Can page creation be restricted by tier? + - e.g., Basic tier: max 5 custom pages + - e.g., Pro tier: unlimited pages + +4. **Template inheritance**: Should vendor defaults have template selection? + - Or always use a standard template? + +--- + +## Session Notes + +### 2026-01-18 +- Analyzed current CMS architecture issues +- Identified homepage is hardcoded (not using CMS) +- Confirmed admin platform-homepage UI is non-functional +- Designed three-tier content hierarchy: + 1. Platform pages (marketing) + 2. Vendor defaults (fallback) + 3. Vendor overrides/custom +- Documented user journeys for all actors +- Outlined implementation phases +- **Next**: Review proposal, clarify open questions, begin implementation + +--- + +*Document created for session continuity. Update as discussions progress.*