# Multi-Platform CMS Architecture - Implementation Plan > **Status:** All Phases Complete (1-7) > **Last Updated:** 2026-01-19 > **Commits:** > - `408019d` (Phase 1: Database & Models) > - `9680026` (Phases 2-5: Migration, Admin, Docs, Store Dashboard) > - `32bcbc8` (Phase 6: Loyalty Platform Setup) > - `a2407ae` (Phase 7: Platform URL Routing Strategy) --- ## Executive Summary Transform the single-platform OMS into a multi-platform system supporting independent business offerings (OMS, Loyalty, Site Builder), each with its own CMS, store defaults, and marketing pages. --- ## Phase 1: Database & Models ✅ COMPLETE ### Completed Work | Task | File | Status | |------|------|--------| | Platform model | `models/database/platform.py` | ✅ | | StorePlatform junction table | `models/database/store_platform.py` | ✅ | | SubscriptionTier updates | `models/database/subscription.py` | ✅ | | ContentPage updates | `models/database/content_page.py` | ✅ | | CMS feature codes | `models/database/feature.py` | ✅ | | Model exports | `models/database/__init__.py` | ✅ | | PlatformContextMiddleware | `middleware/platform_context.py` | ✅ | | Middleware exports | `middleware/__init__.py` | ✅ | | ContentPageService updates | `app/services/content_page_service.py` | ✅ | | Alembic migration | `alembic/versions/z4e5f6a7b8c9_...py` | ✅ | | Platform folder structure | `app/platforms/` | ✅ | --- ## Phase 2: OMS Migration & Integration ✅ COMPLETE ### 2.1 Run Database Migration ```bash # 1. Backup database first pg_dump wizamart > wizamart_backup_$(date +%Y%m%d).sql # 2. Run migration alembic upgrade head # 3. Verify migration psql -d wizamart -c "SELECT * FROM platforms;" psql -d wizamart -c "SELECT COUNT(*) FROM store_platforms;" psql -d wizamart -c "SELECT platform_id, is_platform_page, COUNT(*) FROM content_pages GROUP BY 1, 2;" ``` ### 2.2 Register PlatformContextMiddleware in main.py ```python # In main.py, add BEFORE StoreContextMiddleware from middleware import PlatformContextMiddleware # Order matters: Platform detection must run first app.add_middleware(StoreContextMiddleware) # Runs second (existing) app.add_middleware(PlatformContextMiddleware) # Runs first (NEW) ``` ### 2.3 Update StoreContextMiddleware ✅ COMPLETE File: `middleware/store_context.py` Changes completed: - [x] Use `request.state.platform_clean_path` instead of `request.url.path` for path-based store detection (line 52) - [x] Skip store detection if no platform found (platform marketing pages like /oms/pricing) - [x] Pass platform context to store lookup for multi-platform store support ### 2.4 Fix Platform Homepage Route File: `app/routes/platform/homepage.py` Current state (BROKEN): - Uses hardcoded `homepage-wizamart.html` template - Admin CMS changes are saved but ignored by route Fix required: ```python # Get platform from middleware platform = request.state.platform # Query CMS for platform homepage page = content_page_service.get_platform_page( db, platform_id=platform.id, slug="home" ) if page: # Render with selected template return templates.TemplateResponse( f"platform/homepage-{page.template}.html", {"request": request, "page": page} ) else: # Fallback to hardcoded (temporary) return templates.TemplateResponse("platform/homepage-wizamart.html", {...}) ``` ### 2.5 Update Content Page Routes Files to update: - [ ] `app/routes/platform/content_pages.py` - Add platform_id from request.state.platform - [ ] `app/routes/store/content_pages.py` - Add platform_id to queries - [ ] `app/routes/admin/content_pages.py` - Add platform filtering --- ## Phase 3: Admin Interface ✅ COMPLETE ### 3.1 Platform Management UI | Task | File | Status | |------|------|--------| | Platform list page route | `app/routes/admin_pages.py` | ✅ | | Platform detail/edit routes | `app/routes/admin_pages.py` | ✅ | | Platform API endpoints | `app/api/v1/admin/platforms.py` | ✅ | | Register API router | `app/api/v1/admin/__init__.py` | ✅ | | Platforms template | `app/templates/admin/platforms.html` | ✅ | | Platforms JS component | `static/admin/js/platforms.js` | ✅ | | Sidebar menu item | `app/templates/admin/partials/sidebar.html` | ✅ | ### 3.2 Update Content Pages Admin | Task | File | Status | |------|------|--------| | Platform dropdown filter | `app/templates/admin/content-pages.html` | ✅ | | Four-tab tier view | `app/templates/admin/content-pages.html` | ✅ | | Tier badges (Blue/Teal/Purple) | `static/admin/js/content-pages.js` | ✅ | | Platform filter in JS | `static/admin/js/content-pages.js` | ✅ | | API schema with platform fields | `app/api/v1/admin/content_pages.py` | ✅ | | Model to_dict with platform_name | `models/database/content_page.py` | ✅ | --- ## Phase 4: Store Dashboard ✅ COMPLETE ### 4.1 Content Pages List Updates | Task | File | Status | |------|------|--------| | Source indicators (Default/Override/Custom) | `app/templates/store/content-pages.html` | ✅ Already existed | | Override Default button | `app/templates/store/content-pages.html` | ✅ Already existed | | Revert to Default (delete override) | `static/store/js/content-pages.js` | ✅ Already existed | | CMS usage API endpoint | `app/api/v1/store/content_pages.py` | ✅ New | | CMS usage progress bar | `app/templates/store/content-pages.html` | ✅ New | | Upgrade prompt at 80% limit | `app/templates/store/content-pages.html` | ✅ New | | Load usage in JS | `static/store/js/content-pages.js` | ✅ New | ### 4.2 Page Editor Updates | Task | File | Status | |------|------|--------| | Override info banner | `app/templates/store/content-page-edit.html` | ✅ Already existed | | View Default button | `app/templates/store/content-page-edit.html` | ✅ New | | Default preview modal | `app/templates/store/content-page-edit.html` | ✅ New | | Platform default API | `app/api/v1/store/content_pages.py` | ✅ New | | Show default preview JS | `static/store/js/content-page-edit.js` | ✅ New | | Revert button (styled) | `app/templates/store/content-page-edit.html` | ✅ New | --- ## Phase 5: Routes & Templates ✅ COMPLETE ### 5.1 Platform-Prefixed Routes (Development) Register in `main.py`: ```python # Development mode: path-based routing if settings.environment == "development": app.mount("/oms", oms_router) app.mount("/loyalty", loyalty_router) ``` ### 5.2 Update Shop Routes ✅ COMPLETE - [x] Add platform context to shop routes (`shop_pages.py` line 117) - [x] Use `request.state.platform` for template selection - [x] Pass platform to content page lookups (`platform_id` used in CMS queries) ### 5.3 Test All URL Patterns ✅ COMPLETE Development (using /platforms/ prefix): - [x] `localhost:9999/platforms/oms/` → OMS homepage - [x] `localhost:9999/platforms/oms/pricing` → OMS pricing page - [x] `localhost:9999/platforms/oms/stores/{code}/` → Store storefront - [x] `localhost:9999/platforms/loyalty/` → Loyalty homepage --- ## Phase 6: Loyalty Platform Setup ✅ COMPLETE ### 6.1 Database Setup ✅ Migration: `alembic/versions/z5f6g7h8i9j0_add_loyalty_platform.py` Inserts Loyalty platform with: - code: `loyalty` - name: `Loyalty+` - domain: `loyalty.lu` - path_prefix: `loyalty` - theme_config: purple color scheme ### 6.2 Platform Marketing Pages ✅ | Page | Slug | Status | |------|------|--------| | Homepage | `home` | ✅ | | Pricing | `pricing` | ✅ | | Features | `features` | ✅ | | How It Works | `how-it-works` | ✅ | ### 6.3 Store Default Pages ✅ | Page | Slug | Status | |------|------|--------| | About | `about` | ✅ | | Rewards Catalog | `rewards-catalog` | ✅ | | Terms | `terms` | ✅ | | Privacy | `privacy` | ✅ | --- ## Phase 7: Platform URL Routing Strategy ✅ COMPLETE ### 7.1 URL Structure Changes **Previous approach (DEPRECATED):** - Development: `/oms/`, `/loyalty/` (first path segment = platform) - Ambiguity: `/faq` could be platform or page **New approach:** - Development: `/platforms/oms/`, `/platforms/loyalty/` (explicit prefix) - Main marketing site: `/` (no prefix) → `main` platform - Clear separation: `/faq` = main site, `/platforms/oms/faq` = OMS ### 7.2 Implementation Details | Task | File | Status | |------|------|--------| | Update middleware URL detection | `middleware/platform_context.py` | ✅ | | Change DEFAULT_PLATFORM_CODE | `middleware/platform_context.py` | ✅ | | Remove hardcoded /oms, /loyalty routes | `main.py` | ✅ | | Update platform_pages.py homepage | `app/routes/platform_pages.py` | ✅ | | Add 'main' platform migration | `alembic/versions/z6g7h8i9j0k1_...py` | ✅ | ### 7.3 URL Routing Summary | Platform | Code | Dev URL | Prod URL | |----------|------|---------|----------| | Main Marketing | `main` | `localhost:9999/` | `wizamart.lu/` | | OMS | `oms` | `localhost:9999/platforms/oms/` | `oms.lu/` | | Loyalty | `loyalty` | `localhost:9999/platforms/loyalty/` | `loyalty.lu/` | ### 7.4 Middleware Detection Logic ``` Request arrives │ ▼ ┌─────────────────────────────────────┐ │ Production domain? (oms.lu, etc.) │ └─────────────────────────────────────┘ │ YES → Route to that platform │ ▼ NO (localhost) ┌─────────────────────────────────────┐ │ Path starts with /platforms/{code}? │ └─────────────────────────────────────┘ │ YES → Strip prefix, route to platform │ /platforms/oms/pricing → /pricing │ ▼ NO ┌─────────────────────────────────────┐ │ Use 'main' platform (DEFAULT) │ │ /faq → Main site FAQ page │ └─────────────────────────────────────┘ ``` --- ## Documentation Requirements ✅ COMPLETE ### Architecture Documentation ✅ COMPLETE Updated documentation for Phase 7: - [x] `docs/architecture/url-routing/overview.md` - Multi-platform URL routing section - [x] `docs/architecture/multi-platform-cms.md` - Request flow with path rewriting - [x] `docs/architecture/middleware.md` - PlatformContextMiddleware documentation - [x] Three-tier content hierarchy explanation - [x] Platform vs Store Default vs Store Override - [x] Database schema diagrams - [x] Request flow diagrams - [x] API endpoints reference - [x] Key files reference - [x] Adding new platform guide with URL summary ### API Documentation OpenAPI specs auto-generated from FastAPI: - [x] Platform endpoints (`/api/v1/admin/platforms`) - [x] Content page endpoints with platform fields - [ ] Store platform membership endpoints (future) ### Developer Guide Included in `docs/architecture/multi-platform-cms.md`: - [x] Step-by-step platform creation - [x] Required database records - [x] Key files reference - [x] Platform URL summary table --- ## Quick Reference ### Three-Tier Content Resolution ``` Customer visits: oms.lu/stores/wizamart/about │ ▼ ┌─────────────────────────────────────────────────────────────┐ │ Tier 1: Store Override │ │ WHERE platform_id=1 AND store_id=123 AND slug='about' │ │ Found? → Return store's custom page │ └─────────────────────────────────────────────────────────────┘ │ Not found ▼ ┌─────────────────────────────────────────────────────────────┐ │ Tier 2: Store Default │ │ WHERE platform_id=1 AND store_id IS NULL │ │ AND is_platform_page=FALSE AND slug='about' │ │ Found? → Return platform default │ └─────────────────────────────────────────────────────────────┘ │ Not found ▼ Return 404 ``` ### CMS Tier Limits | Tier | Total Pages | Custom Pages | |------|-------------|--------------| | Essential | 3 | 0 | | Professional | 10 | 5 | | Business | 30 | 20 | | Enterprise | Unlimited | Unlimited | ### Platform Marketing Page Slugs `home`, `platform_homepage`, `pricing`, `about`, `contact`, `faq`, `terms`, `privacy`, `features`, `integrations` --- ## Verification Checklist All phases are complete. Use these commands to verify: ```bash # 1. Check platforms in database psql -d wizamart -c "SELECT code, name, domain FROM platforms;" # Expected: main, oms, loyalty # 2. Test main marketing site curl -s localhost:9999/ | grep -o ".*" # Expected: Main marketing site title # 3. Test OMS platform curl -s localhost:9999/platforms/oms/ | grep -o ".*" # Expected: OMS platform title # 4. Test Loyalty platform curl -s localhost:9999/platforms/loyalty/ | grep -o ".*" # Expected: Loyalty platform title # 5. Verify middleware detection python -c " from middleware.platform_context import PlatformContextMiddleware, DEFAULT_PLATFORM_CODE print(f'DEFAULT_PLATFORM_CODE: {DEFAULT_PLATFORM_CODE}') # Expected: main " ``` --- ## Files Created/Modified in Phase 1 ### New Files (17) ``` models/database/platform.py models/database/store_platform.py middleware/platform_context.py alembic/versions/z4e5f6a7b8c9_add_multi_platform_support.py app/platforms/__init__.py app/platforms/oms/__init__.py app/platforms/oms/config.py app/platforms/oms/routes/__init__.py app/platforms/oms/templates/__init__.py app/platforms/loyalty/__init__.py app/platforms/loyalty/config.py app/platforms/loyalty/routes/__init__.py app/platforms/loyalty/templates/__init__.py app/platforms/shared/__init__.py app/platforms/shared/base_platform.py app/platforms/shared/routes/__init__.py app/platforms/shared/templates/__init__.py ``` ### Modified Files (7) ``` models/database/__init__.py models/database/content_page.py models/database/subscription.py models/database/feature.py models/database/store.py middleware/__init__.py app/services/content_page_service.py ``` --- ## Notes - Git tag `v1.0.0-pre-multiplatform` was created before starting - All existing `content_pages` will be backfilled to OMS platform - All existing stores will be linked to OMS via `store_platforms` - Migration is reversible (see downgrade function in migration file)