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:
2026-01-18 19:32:30 +01:00
parent 013d8e3d10
commit 4c9b3c4e4b
3 changed files with 1396 additions and 0 deletions

View 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.*

View File

@@ -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).

View 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.*