Replace all ~1,086 occurrences of Wizamart/wizamart/WIZAMART/WizaMart with Orion/orion/ORION across 184 files. This includes database identifiers, email addresses, domain references, R2 bucket names, DNS prefixes, encryption salt, Celery app name, config defaults, Docker configs, CI configs, documentation, seed data, and templates. Renames homepage-wizamart.html template to homepage-orion.html. Fixes duplicate file_pattern key in api.yaml architecture rule. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
436 lines
15 KiB
Markdown
436 lines
15 KiB
Markdown
# 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 orion > orion_backup_$(date +%Y%m%d).sql
|
|
|
|
# 2. Run migration
|
|
alembic upgrade head
|
|
|
|
# 3. Verify migration
|
|
psql -d orion -c "SELECT * FROM platforms;"
|
|
psql -d orion -c "SELECT COUNT(*) FROM store_platforms;"
|
|
psql -d orion -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-orion.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-orion.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/` | `orion.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/orion/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 orion -c "SELECT code, name, domain FROM platforms;"
|
|
# Expected: main, oms, loyalty
|
|
|
|
# 2. Test main marketing site
|
|
curl -s localhost:9999/ | grep -o "<title>.*</title>"
|
|
# Expected: Main marketing site title
|
|
|
|
# 3. Test OMS platform
|
|
curl -s localhost:9999/platforms/oms/ | grep -o "<title>.*</title>"
|
|
# Expected: OMS platform title
|
|
|
|
# 4. Test Loyalty platform
|
|
curl -s localhost:9999/platforms/loyalty/ | grep -o "<title>.*</title>"
|
|
# 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)
|