docs: add multi-platform CMS architecture proposals
- Add loyalty program analysis document - Add multi-platform CMS architecture proposal - Document three-tier content hierarchy - Include URL/access patterns for all personas - Define migration strategy and implementation phases Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
387
docs/proposals/loyalty-program-analysis.md
Normal file
387
docs/proposals/loyalty-program-analysis.md
Normal file
@@ -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.*
|
||||||
@@ -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).
|
||||||
603
docs/proposals/multi-platform-cms-architecture.md
Normal file
603
docs/proposals/multi-platform-cms-architecture.md
Normal file
@@ -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.*
|
||||||
Reference in New Issue
Block a user