# Multi-Platform CMS Architecture

## Overview

The Multi-Platform CMS enables Orion to serve multiple business offerings (OMS, Loyalty, Site Builder) from a single codebase, each with its own marketing site and store 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, store_id=NULL                               │
│  NOT inherited by stores                                            │
└─────────────────────────────────────────────────────────────────────┘
                                   │
                                   ▼
┌─────────────────────────────────────────────────────────────────────┐
│                     TIER 2: Store Defaults                          │
│  Default pages all stores inherit (about, terms, privacy)           │
│  is_platform_page=FALSE, store_id=NULL                              │
│  Inherited by ALL stores on the platform                            │
└─────────────────────────────────────────────────────────────────────┘
                                   │
                                   ▼
┌─────────────────────────────────────────────────────────────────────┐
│                     TIER 3: Store Overrides                         │
│  Custom pages created by individual stores                          │
│  is_platform_page=FALSE, store_id=<store_id>                       │
│  Overrides store defaults for specific store                       │
└─────────────────────────────────────────────────────────────────────┘
```

## Content Resolution Flow

When a customer visits a store page (e.g., `/stores/shopname/about`):

```
Customer visits: /platforms/oms/storefront/shopname/about
                         │
                         ▼
┌─────────────────────────────────────────────────────────────────────┐
│ Step 1: Check Store Override                                        │
│ SELECT * FROM content_pages                                          │
│ WHERE platform_id=:platform_id AND store_id=123 AND slug='about'    │
│ Found? → Return store's custom "About" page                         │
└─────────────────────────────────────────────────────────────────────┘
                         │ Not found
                         ▼
┌─────────────────────────────────────────────────────────────────────┐
│ Step 2: Check Store Default                                         │
│ SELECT * FROM content_pages                                          │
│ WHERE platform_id=:platform_id AND store_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.orion.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()
);
```

### store_platforms (Junction Table)

```sql
CREATE TABLE store_platforms (
    store_id INTEGER REFERENCES stores(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 (store_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, store_id=NULL
-- Store defaults: is_platform_page=FALSE, store_id=NULL
-- Store overrides: is_platform_page=FALSE, store_id=<id>
```

## Request Flow

### URL Routing Structure

The system uses different URL patterns for development vs production:

**Development (localhost):**
- Main marketing site: `localhost:9999/` (no prefix) → `main` platform
- Platform sites: `localhost:9999/platforms/{code}/` → specific platform

**Production (custom domains):**
- Main marketing site: `orion.lu/` → `main` platform
- Platform sites: `omsflow.lu/`, `rewardflow.lu/` → specific platform

### Request Processing

```
Request: GET /platforms/oms/stores/shopname/about
              │
              ▼
┌─────────────────────────────────────────────────────────────────────┐
│ PlatformContextMiddleware                                            │
│ - Detects platform from /platforms/{code}/ prefix or domain          │
│ - Rewrites path: /platforms/oms/stores/shopname/about               │
│                  → /stores/shopname/about                           │
│ - Sets request.state.platform = Platform(code='oms')                 │
│ - Sets request.state.platform_clean_path = /stores/shopname/about   │
└─────────────────────────────────────────────────────────────────────┘
              │
              ▼
┌─────────────────────────────────────────────────────────────────────┐
│ StoreContextMiddleware                                              │
│ - Uses rewritten path for store detection                           │
│ - Sets request.state.store = Store(subdomain='shopname')           │
└─────────────────────────────────────────────────────────────────────┘
              │
              ▼
┌─────────────────────────────────────────────────────────────────────┐
│ Route Handler (shop_pages.py)                                        │
│ - Gets platform_id from request.state.platform                       │
│ - Calls content_page_service.get_page_for_store(                    │
│       platform_id=platform.id, store_id=123, slug='about'           │
│   )                                                                  │
│ - Service handles three-tier resolution                              │
└─────────────────────────────────────────────────────────────────────┘
```

### Main Marketing Site (No Platform Prefix)

For requests without the `/platforms/` prefix (e.g., `localhost:9999/about`):

```
Request: GET /about
              │
              ▼
┌─────────────────────────────────────────────────────────────────────┐
│ PlatformContextMiddleware                                            │
│ - No /platforms/ prefix detected                                     │
│ - Uses MAIN_PLATFORM_CODE = 'main'                                   │
│ - Sets request.state.platform = Platform(code='main')                │
│ - Path unchanged: /about                                             │
└─────────────────────────────────────────────────────────────────────┘
              │
              ▼
┌─────────────────────────────────────────────────────────────────────┐
│ Route Handler (platform_pages.py)                                    │
│ - Gets platform_id from request.state.platform (main)                │
│ - Loads CMS content for main marketing site                          │
└─────────────────────────────────────────────────────────────────────┘
```

## Admin Interface

### Platform Management (`/admin/platforms`)

- Lists all platforms with statistics
- Shows store count, marketing pages, store 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)
  - **Store Defaults**: Inherited by stores (is_platform_page=FALSE, store_id=NULL)
  - **Store Overrides**: Store-specific (store_id set)
- Color-coded tier badges:
  - Blue: Platform Marketing
  - Teal: Store Default
  - Purple: Store 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/store` | Create store page |

## Key Files

### Models
- `models/database/platform.py` - Platform model
- `models/database/store_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` - Store 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, domain, path_prefix)
   VALUES ('loyalty', 'Loyalty Program', 'Customer loyalty and rewards', 'rewardflow.lu', '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', '<h1>Welcome</h1>', TRUE);
   ```

3. Configure routing:
   - **Development:** Access at `localhost:9999/platforms/loyalty/`
   - **Production:** Access at `rewardflow.lu/`
   - Platform detected automatically by `PlatformContextMiddleware`
   - No additional route configuration needed

4. Assign stores to platform:
   ```sql
   INSERT INTO store_platforms (store_id, platform_id)
   VALUES (1, 2);
   ```

### Platform URL Summary

| Platform | Code | Dev URL | Prod URL |
|----------|------|---------|----------|
| Main Marketing | `main` | `localhost:9999/` | `orion.lu/` |
| OMS | `oms` | `localhost:9999/platforms/oms/` | `omsflow.lu/` |
| Loyalty | `loyalty` | `localhost:9999/platforms/loyalty/` | `rewardflow.lu/` |
