Files
orion/docs/proposals/multi-platform-cms-architecture-implementation-plan.md
Samir Boulahtit 4c9b3c4e4b 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>
2026-01-18 19:32:30 +01:00

80 KiB

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
  1. Three-tier resolution:
  • Create vendor override → shows override
  • Delete override → shows platform default
  • Delete default → shows 404
  1. 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).