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