# Multi-Platform CMS Architecture ## Overview The Multi-Platform CMS enables Wizamart to serve multiple business offerings (OMS, Loyalty, Site Builder) from a single codebase, each with its own marketing site and vendor ecosystem. ## Three-Tier Content Hierarchy Content pages follow a three-tier inheritance model: ``` ┌─────────────────────────────────────────────────────────────────────┐ │ TIER 1: Platform Marketing │ │ Public pages for the platform (homepage, pricing, features) │ │ is_platform_page=TRUE, vendor_id=NULL │ │ NOT inherited by vendors │ └─────────────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────────┐ │ TIER 2: Vendor Defaults │ │ Default pages all vendors inherit (about, terms, privacy) │ │ is_platform_page=FALSE, vendor_id=NULL │ │ Inherited by ALL vendors on the platform │ └─────────────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────────┐ │ TIER 3: Vendor Overrides │ │ Custom pages created by individual vendors │ │ is_platform_page=FALSE, vendor_id= │ │ Overrides vendor defaults for specific vendor │ └─────────────────────────────────────────────────────────────────────┘ ``` ## Content Resolution Flow When a customer visits a vendor page (e.g., `/vendors/shopname/about`): ``` Customer visits: /vendors/shopname/about │ ▼ ┌─────────────────────────────────────────────────────────────────────┐ │ Step 1: Check Vendor Override │ │ SELECT * FROM content_pages │ │ WHERE platform_id=1 AND vendor_id=123 AND slug='about' │ │ Found? → Return vendor's custom "About" page │ └─────────────────────────────────────────────────────────────────────┘ │ Not found ▼ ┌─────────────────────────────────────────────────────────────────────┐ │ Step 2: Check 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's default "About" template │ └─────────────────────────────────────────────────────────────────────┘ │ Not found ▼ Return 404 ``` ## Database Schema ### platforms ```sql CREATE TABLE platforms ( id SERIAL PRIMARY KEY, code VARCHAR(50) UNIQUE NOT NULL, -- 'oms', 'loyalty', 'sitebuilder' name VARCHAR(100) NOT NULL, -- 'Order Management System' description TEXT, domain VARCHAR(255), -- 'oms.wizamart.lu' path_prefix VARCHAR(50), -- '/oms' logo VARCHAR(255), logo_dark VARCHAR(255), favicon VARCHAR(255), theme_config JSONB DEFAULT '{}', default_language VARCHAR(10) DEFAULT 'fr', supported_languages JSONB DEFAULT '["fr", "de", "en"]', is_active BOOLEAN DEFAULT TRUE, is_public BOOLEAN DEFAULT TRUE, settings JSONB DEFAULT '{}', created_at TIMESTAMP DEFAULT NOW(), updated_at TIMESTAMP DEFAULT NOW() ); ``` ### vendor_platforms (Junction Table) ```sql CREATE TABLE vendor_platforms ( vendor_id INTEGER REFERENCES vendors(id) ON DELETE CASCADE, platform_id INTEGER REFERENCES platforms(id) ON DELETE CASCADE, joined_at TIMESTAMP DEFAULT NOW(), is_active BOOLEAN DEFAULT TRUE, settings JSONB DEFAULT '{}', PRIMARY KEY (vendor_id, platform_id) ); ``` ### content_pages (Extended) ```sql ALTER TABLE content_pages ADD COLUMN platform_id INTEGER REFERENCES platforms(id); ALTER TABLE content_pages ADD COLUMN is_platform_page BOOLEAN DEFAULT FALSE; -- Platform marketing pages: is_platform_page=TRUE, vendor_id=NULL -- Vendor defaults: is_platform_page=FALSE, vendor_id=NULL -- Vendor overrides: is_platform_page=FALSE, vendor_id= ``` ## Request Flow ``` Request: GET /oms/vendors/shopname/about │ ▼ ┌─────────────────────────────────────────────────────────────────────┐ │ PlatformContextMiddleware │ │ - Detects platform from path prefix (/oms) or domain │ │ - Sets request.state.platform = Platform(code='oms') │ │ - Sets request.state.platform_clean_path = /vendors/shopname/about │ └─────────────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────────┐ │ VendorContextMiddleware │ │ - Uses platform_clean_path for vendor detection │ │ - Sets request.state.vendor = Vendor(subdomain='shopname') │ └─────────────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────────┐ │ Route Handler (shop_pages.py) │ │ - Gets platform_id from request.state.platform │ │ - Calls content_page_service.get_page_for_vendor( │ │ platform_id=1, vendor_id=123, slug='about' │ │ ) │ │ - Service handles three-tier resolution │ └─────────────────────────────────────────────────────────────────────┘ ``` ## Admin Interface ### Platform Management (`/admin/platforms`) - Lists all platforms with statistics - Shows vendor count, marketing pages, vendor defaults - Links to platform detail and edit pages ### Content Pages (`/admin/content-pages`) - Platform filter dropdown - Four-tab view: - **All Pages**: Complete list - **Platform Marketing**: Public platform pages (is_platform_page=TRUE) - **Vendor Defaults**: Inherited by vendors (is_platform_page=FALSE, vendor_id=NULL) - **Vendor Overrides**: Vendor-specific (vendor_id set) - Color-coded tier badges: - Blue: Platform Marketing - Teal: Vendor Default - Purple: Vendor Override ## API Endpoints ### Platform Management | Method | Endpoint | Description | |--------|----------|-------------| | GET | `/api/v1/admin/platforms` | List all platforms | | GET | `/api/v1/admin/platforms/{code}` | Get platform details | | PUT | `/api/v1/admin/platforms/{code}` | Update platform | | GET | `/api/v1/admin/platforms/{code}/stats` | Platform statistics | ### Content Pages | Method | Endpoint | Description | |--------|----------|-------------| | GET | `/api/v1/admin/content-pages/` | List all pages (supports `platform` filter) | | GET | `/api/v1/admin/content-pages/platform` | Platform default pages only | | POST | `/api/v1/admin/content-pages/platform` | Create platform page | | POST | `/api/v1/admin/content-pages/vendor` | Create vendor page | ## Key Files ### Models - `models/database/platform.py` - Platform model - `models/database/vendor_platform.py` - Junction table - `models/database/content_page.py` - Extended with platform_id ### Middleware - `middleware/platform_context.py` - Platform detection and context ### Services - `app/services/content_page_service.py` - Three-tier content resolution ### Routes - `app/routes/platform_pages.py` - Platform marketing pages - `app/routes/shop_pages.py` - Vendor shop pages with inheritance ### Admin - `app/api/v1/admin/platforms.py` - Platform management API - `app/templates/admin/platforms.html` - Platform admin UI - `static/admin/js/platforms.js` - Alpine.js component ## CMS Tier Limits (Subscription-Based) | Tier | Total Pages | Custom Pages | |------|-------------|--------------| | Essential | 3 | 0 | | Professional | 10 | 5 | | Business | 30 | 20 | | Enterprise | Unlimited | Unlimited | ## Adding a New Platform 1. Insert platform record: ```sql INSERT INTO platforms (code, name, description, path_prefix) VALUES ('loyalty', 'Loyalty Program', 'Customer loyalty and rewards', '/loyalty'); ``` 2. Create platform-specific content pages: ```sql INSERT INTO content_pages (platform_id, slug, title, content, is_platform_page) VALUES (2, 'home', 'Loyalty Program', '

Welcome

', TRUE); ``` 3. Configure routing (if using path prefix): - Platform detected by `PlatformContextMiddleware` - No additional route configuration needed 4. Assign vendors to platform: ```sql INSERT INTO vendor_platforms (vendor_id, platform_id) VALUES (1, 2); ```