refactor: rename Wizamart to Orion across entire codebase
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>
This commit is contained in:
@@ -99,7 +99,7 @@ Developers must remember:
|
||||
|
||||
### Broken Features
|
||||
|
||||
**Current Issue:** CMS pages not loading at `/stores/wizamart/about`
|
||||
**Current Issue:** CMS pages not loading at `/stores/orion/about`
|
||||
|
||||
**Root Cause:**
|
||||
- CMS API exists at `/api/v1/shop/content-pages/{slug}`
|
||||
|
||||
@@ -21,9 +21,9 @@ Updated `StoreContextMiddleware` to support shop API routes:
|
||||
- Shop API now receives store context from the page that made the API call
|
||||
|
||||
**How it works:**
|
||||
1. Browser JavaScript on `/stores/wizamart/shop/products` calls `/api/v1/shop/products`
|
||||
2. Browser automatically sends `Referer: http://localhost:8000/stores/wizamart/shop/products`
|
||||
3. Middleware extracts `wizamart` from Referer path
|
||||
1. Browser JavaScript on `/stores/orion/shop/products` calls `/api/v1/shop/products`
|
||||
2. Browser automatically sends `Referer: http://localhost:8000/stores/orion/shop/products`
|
||||
3. Middleware extracts `orion` from Referer path
|
||||
4. Queries database to get Store object
|
||||
5. Sets `request.state.store` for the API endpoint
|
||||
|
||||
|
||||
@@ -286,7 +286,7 @@ def get_products(
|
||||
"sub": "user_id",
|
||||
"username": "john.doe",
|
||||
"store_id": 123, ← Store context
|
||||
"store_code": "WIZAMART", ← Store code
|
||||
"store_code": "ORION", ← Store code
|
||||
"store_role": "Owner" ← Store role
|
||||
}
|
||||
```
|
||||
|
||||
@@ -6,7 +6,7 @@ This document defines the harmonized architecture for all background tasks in th
|
||||
|
||||
## Task Queue Infrastructure
|
||||
|
||||
Wizamart uses **Celery with Redis** for production-grade background task processing:
|
||||
Orion uses **Celery with Redis** for production-grade background task processing:
|
||||
|
||||
| Component | Purpose | Port |
|
||||
|-----------|---------|------|
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Capacity Planning & Infrastructure Sizing
|
||||
|
||||
This document provides comprehensive capacity planning guidelines for the Wizamart platform, including resource requirements, scaling thresholds, and monitoring recommendations.
|
||||
This document provides comprehensive capacity planning guidelines for the Orion platform, including resource requirements, scaling thresholds, and monitoring recommendations.
|
||||
|
||||
> **Related:** [Pricing Strategy](../marketing/pricing.md) for tier definitions and limits
|
||||
|
||||
|
||||
@@ -175,16 +175,16 @@ Customer → DNS → Server → Nginx → FastAPI
|
||||
|
||||
FastAPI Middleware:
|
||||
host = "store1.platform.com"
|
||||
|
||||
|
||||
Step 1: Custom domain? NO (ends with .platform.com)
|
||||
Step 2: Subdomain? YES
|
||||
Extract "store1"
|
||||
Query: SELECT * FROM stores
|
||||
Query: SELECT * FROM stores
|
||||
WHERE subdomain = 'store1'
|
||||
Result: Store 1
|
||||
|
||||
|
||||
request.state.store = Store 1
|
||||
|
||||
|
||||
Route → Render Store 1's shop
|
||||
```
|
||||
|
||||
@@ -195,18 +195,18 @@ Customer → localhost:8000/store/store1/
|
||||
FastAPI Middleware:
|
||||
host = "localhost:8000"
|
||||
path = "/store/store1/"
|
||||
|
||||
|
||||
Step 1: Custom domain? NO (localhost)
|
||||
Step 2: Subdomain? NO (localhost has no subdomain)
|
||||
Step 3: Path-based? YES
|
||||
Extract "store1" from path
|
||||
Query: SELECT * FROM stores
|
||||
Query: SELECT * FROM stores
|
||||
WHERE subdomain = 'store1'
|
||||
Result: Store 1
|
||||
|
||||
|
||||
request.state.store = Store 1
|
||||
request.state.clean_path = "/" (strip /store/store1)
|
||||
|
||||
|
||||
Route → Render Store 1's shop
|
||||
```
|
||||
|
||||
@@ -402,7 +402,7 @@ Value: 123.45.67.89
|
||||
TTL: 3600
|
||||
|
||||
Type: TXT
|
||||
Name: _wizamart-verify
|
||||
Name: _orion-verify
|
||||
Value: abc123xyz (verification token from your platform)
|
||||
TTL: 3600
|
||||
```
|
||||
|
||||
@@ -237,7 +237,7 @@
|
||||
│ Exception Handler │
|
||||
│ app/exceptions/handler.py │
|
||||
│ │
|
||||
│ @app.exception_handler(WizamartException) │
|
||||
│ @app.exception_handler(OrionException) │
|
||||
│ async def custom_exception_handler(...): │
|
||||
│ return JSONResponse( │
|
||||
│ status_code=exc.status_code, │
|
||||
@@ -331,7 +331,7 @@ Step 2: Get Instructions
|
||||
┌────────────────────────────────────┐
|
||||
│ System returns instructions: │
|
||||
│ "Add TXT record: │
|
||||
│ _wizamart-verify.myshop.com │
|
||||
│ _orion-verify.myshop.com │
|
||||
│ Value: abc123..." │
|
||||
└────────────────────────────────────┘
|
||||
|
||||
@@ -343,7 +343,7 @@ Step 3: Store Adds DNS Record
|
||||
▼
|
||||
┌────────────────────────────────────┐
|
||||
│ DNS Provider (GoDaddy/etc) │
|
||||
│ _wizamart-verify.myshop.com TXT │
|
||||
│ _orion-verify.myshop.com TXT │
|
||||
│ "abc123..." │
|
||||
└────────────────────────────────────┘
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ The application serves multiple frontends from a single codebase:
|
||||
|----------|-------------|--------------|
|
||||
| **ADMIN** | Platform administration | `/admin/*`, `/api/v1/admin/*`, `admin.oms.lu/*` |
|
||||
| **STORE** | Store dashboard | `/store/*`, `/api/v1/store/*` |
|
||||
| **STOREFRONT** | Customer-facing shop | `/storefront/*`, `/stores/*`, `wizamart.oms.lu/*` |
|
||||
| **STOREFRONT** | Customer-facing shop | `/storefront/*`, `/stores/*`, `orion.oms.lu/*` |
|
||||
| **PLATFORM** | Marketing pages | `/`, `/pricing`, `/about` |
|
||||
|
||||
The `FrontendDetector` class provides centralized, consistent detection of which frontend a request targets.
|
||||
@@ -70,7 +70,7 @@ The `FrontendDetector` uses the following priority order:
|
||||
- /store/* or /api/v1/store/* → STORE
|
||||
- /storefront/*, /shop/*, /stores/* → STOREFRONT
|
||||
- /api/v1/platform/* → PLATFORM
|
||||
3. Store subdomain (wizamart.oms.lu) → STOREFRONT
|
||||
3. Store subdomain (orion.oms.lu) → STOREFRONT
|
||||
4. Store context set by middleware → STOREFRONT
|
||||
5. Default → PLATFORM
|
||||
```
|
||||
@@ -133,7 +133,7 @@ from app.modules.enums import FrontendType
|
||||
|
||||
# Full detection
|
||||
frontend_type = FrontendDetector.detect(
|
||||
host="wizamart.oms.lu",
|
||||
host="orion.oms.lu",
|
||||
path="/products",
|
||||
has_store_context=True
|
||||
)
|
||||
@@ -160,7 +160,7 @@ if FrontendDetector.is_storefront(host, path, has_store_context=True):
|
||||
| Store dashboard | localhost | /store/settings | STORE |
|
||||
| Store API | localhost | /api/v1/store/products | STORE |
|
||||
| Storefront | localhost | /storefront/products | STOREFRONT |
|
||||
| Storefront (path-based) | localhost | /stores/wizamart/products | STOREFRONT |
|
||||
| Storefront (path-based) | localhost | /stores/orion/products | STOREFRONT |
|
||||
| Marketing | localhost | /pricing | PLATFORM |
|
||||
|
||||
### Production Mode (domains)
|
||||
@@ -168,7 +168,7 @@ if FrontendDetector.is_storefront(host, path, has_store_context=True):
|
||||
| Request | Host | Path | Frontend |
|
||||
|---------|------|------|----------|
|
||||
| Admin subdomain | admin.oms.lu | /dashboard | ADMIN |
|
||||
| Store subdomain | wizamart.oms.lu | /products | STOREFRONT |
|
||||
| Store subdomain | orion.oms.lu | /products | STOREFRONT |
|
||||
| Custom domain | mybakery.lu | /products | STOREFRONT |
|
||||
| Platform root | oms.lu | /pricing | PLATFORM |
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Language & Internationalization (i18n) Architecture
|
||||
|
||||
This document defines **strict rules** for implementing language support across the Wizamart platform.
|
||||
This document defines **strict rules** for implementing language support across the Orion platform.
|
||||
|
||||
> **IMPORTANT:** These rules are mandatory. Violations will cause runtime errors, inconsistent UX, or security issues.
|
||||
|
||||
@@ -49,7 +49,7 @@ language = "lux" # ❌ Use "lb"
|
||||
Language is resolved in this order (highest to lowest priority):
|
||||
|
||||
1. **URL parameter** (`?lang=fr`)
|
||||
2. **Cookie** (`wizamart_language`)
|
||||
2. **Cookie** (`orion_language`)
|
||||
3. **User preference** (database: `preferred_language`)
|
||||
4. **Store default** (database: `storefront_language` or `dashboard_language`)
|
||||
5. **Accept-Language header** (browser)
|
||||
@@ -270,7 +270,7 @@ async def set_language(request: LanguageSetRequest, response: Response):
|
||||
raise HTTPException(status_code=400, detail="Unsupported language")
|
||||
|
||||
response.set_cookie(
|
||||
key="wizamart_language",
|
||||
key="orion_language",
|
||||
value=request.language,
|
||||
max_age=365 * 24 * 60 * 60, # 1 year
|
||||
httponly=True,
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
## Executive Summary
|
||||
|
||||
This document defines the complete architecture for integrating Wizamart with multiple external marketplaces (Letzshop, Amazon, eBay) and digital product suppliers (CodesWholesale). The integration is **bidirectional**, supporting both inbound flows (products, orders) and outbound flows (inventory sync, fulfillment status).
|
||||
This document defines the complete architecture for integrating Orion with multiple external marketplaces (Letzshop, Amazon, eBay) and digital product suppliers (CodesWholesale). The integration is **bidirectional**, supporting both inbound flows (products, orders) and outbound flows (inventory sync, fulfillment status).
|
||||
|
||||
**Key Capabilities:**
|
||||
|
||||
@@ -26,7 +26,7 @@ graph TB
|
||||
AZ[Amazon<br/>API]
|
||||
EB[eBay<br/>API]
|
||||
CW[CodesWholesale<br/>Digital Supplier API]
|
||||
WS[Store Storefront<br/>Wizamart Shop]
|
||||
WS[Store Storefront<br/>Orion Shop]
|
||||
end
|
||||
|
||||
subgraph "Integration Layer"
|
||||
@@ -42,7 +42,7 @@ graph TB
|
||||
end
|
||||
end
|
||||
|
||||
subgraph "Wizamart Core"
|
||||
subgraph "Orion Core"
|
||||
MP[Marketplace Products]
|
||||
P[Store Products]
|
||||
O[Unified Orders]
|
||||
@@ -263,7 +263,7 @@ graph TB
|
||||
```python
|
||||
class OrderChannel(str, Enum):
|
||||
"""Order source channel."""
|
||||
STOREFRONT = "storefront" # Store's own Wizamart shop
|
||||
STOREFRONT = "storefront" # Store's own Orion shop
|
||||
LETZSHOP = "letzshop"
|
||||
AMAZON = "amazon"
|
||||
EBAY = "ebay"
|
||||
@@ -1325,7 +1325,7 @@ def map_codeswholesale_product(cw_product: dict) -> dict:
|
||||
|
||||
### Order Status Mapping
|
||||
|
||||
| Wizamart Status | Letzshop | Amazon | eBay |
|
||||
| Orion Status | Letzshop | Amazon | eBay |
|
||||
|-----------------|----------|--------|------|
|
||||
| PENDING | PENDING | Pending | - |
|
||||
| CONFIRMED | PAID | Unshipped | Paid |
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Menu Management Architecture
|
||||
|
||||
The Wizamart platform provides a **module-driven menu system** where each module defines its own menu items. The `MenuDiscoveryService` aggregates menus from all enabled modules, applying visibility configuration and permission filtering.
|
||||
The Orion platform provides a **module-driven menu system** where each module defines its own menu items. The `MenuDiscoveryService` aggregates menus from all enabled modules, applying visibility configuration and permission filtering.
|
||||
|
||||
## Overview
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
## Overview
|
||||
|
||||
The Wizamart platform implements a hierarchical multi-tenant architecture where **Merchants** are the primary business entities and **Stores** are storefronts/brands that operate under merchants.
|
||||
The Orion platform implements a hierarchical multi-tenant architecture where **Merchants** are the primary business entities and **Stores** are storefronts/brands that operate under merchants.
|
||||
|
||||
```
|
||||
Merchant (Business Entity)
|
||||
|
||||
@@ -103,11 +103,11 @@ INFO Response: 200 for GET /admin/dashboard (0.143s)
|
||||
|
||||
**Example**:
|
||||
```
|
||||
Request: https://wizamart.platform.com/shop/products
|
||||
Request: https://orion.platform.com/shop/products
|
||||
↓
|
||||
Middleware detects: store_code = "wizamart"
|
||||
Middleware detects: store_code = "orion"
|
||||
↓
|
||||
Queries database: SELECT * FROM stores WHERE code = 'wizamart'
|
||||
Queries database: SELECT * FROM stores WHERE code = 'orion'
|
||||
↓
|
||||
Injects: request.state.store = <Store object>
|
||||
request.state.store_id = 1
|
||||
@@ -141,7 +141,7 @@ Injects: request.state.store = <Store object>
|
||||
- /store/* or /api/v1/store/* → STORE
|
||||
- /storefront/*, /shop/*, /stores/* → STOREFRONT
|
||||
- /api/v1/platform/* → PLATFORM
|
||||
3. Store subdomain (wizamart.oms.lu) → STOREFRONT
|
||||
3. Store subdomain (orion.oms.lu) → STOREFRONT
|
||||
4. Store context set by middleware → STOREFRONT
|
||||
5. Default → PLATFORM
|
||||
```
|
||||
@@ -165,8 +165,8 @@ Injects: request.state.store = <Store object>
|
||||
{
|
||||
"primary_color": "#3B82F6",
|
||||
"secondary_color": "#10B981",
|
||||
"logo_url": "/static/stores/wizamart/logo.png",
|
||||
"favicon_url": "/static/stores/wizamart/favicon.ico",
|
||||
"logo_url": "/static/stores/orion/logo.png",
|
||||
"favicon_url": "/static/stores/orion/favicon.ico",
|
||||
"custom_css": "/* store-specific styles */"
|
||||
}
|
||||
```
|
||||
@@ -376,7 +376,7 @@ async def get_products(request: Request):
|
||||
|
||||
### Example: Shop Product Page Request
|
||||
|
||||
**URL**: `https://wizamart.myplatform.com/shop/products`
|
||||
**URL**: `https://orion.myplatform.com/shop/products`
|
||||
|
||||
**Middleware Processing**:
|
||||
|
||||
@@ -386,9 +386,9 @@ async def get_products(request: Request):
|
||||
↓ Logs: "Request: GET /shop/products from 192.168.1.100"
|
||||
|
||||
2. StoreContextMiddleware
|
||||
↓ Detects subdomain: "wizamart"
|
||||
↓ Queries DB: store = get_store_by_code("wizamart")
|
||||
↓ Sets: request.state.store = <Store: Wizamart>
|
||||
↓ Detects subdomain: "orion"
|
||||
↓ Queries DB: store = get_store_by_code("orion")
|
||||
↓ Sets: request.state.store = <Store: Orion>
|
||||
↓ Sets: request.state.store_id = 1
|
||||
↓ Sets: request.state.clean_path = "/shop/products"
|
||||
|
||||
@@ -496,13 +496,13 @@ from middleware.store_context import StoreContextManager
|
||||
|
||||
def test_store_detection_subdomain():
|
||||
# Mock request
|
||||
request = create_mock_request(host="wizamart.platform.com")
|
||||
request = create_mock_request(host="orion.platform.com")
|
||||
|
||||
# Test detection
|
||||
manager = StoreContextManager()
|
||||
store = manager.detect_store_from_subdomain(request)
|
||||
|
||||
assert store.code == "wizamart"
|
||||
assert store.code == "orion"
|
||||
```
|
||||
|
||||
### Integration Testing
|
||||
@@ -513,11 +513,11 @@ Test the full middleware stack:
|
||||
def test_shop_request_flow(client):
|
||||
response = client.get(
|
||||
"/shop/products",
|
||||
headers={"Host": "wizamart.platform.com"}
|
||||
headers={"Host": "orion.platform.com"}
|
||||
)
|
||||
|
||||
assert response.status_code == 200
|
||||
assert "Wizamart" in response.text
|
||||
assert "Orion" in response.text
|
||||
```
|
||||
|
||||
**See**: [Testing Guide](../testing/testing-guide.md)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Module System Architecture
|
||||
|
||||
The Wizamart platform uses a **plug-and-play modular architecture** where modules are fully self-contained and automatically discovered. Simply create a module directory with the required structure, and the framework handles registration, routing, and resource loading automatically.
|
||||
The Orion platform uses a **plug-and-play modular architecture** where modules are fully self-contained and automatically discovered. Simply create a module directory with the required structure, and the framework handles registration, routing, and resource loading automatically.
|
||||
|
||||
## Key Features
|
||||
|
||||
@@ -1029,11 +1029,11 @@ __all__ = ["process_import", "export_products"]
|
||||
|
||||
### Exceptions
|
||||
|
||||
Module-specific exceptions inherit from `WizamartException`.
|
||||
Module-specific exceptions inherit from `OrionException`.
|
||||
|
||||
| Location | Base Class | Usage |
|
||||
|----------|------------|-------|
|
||||
| `exceptions.py` | `WizamartException` | Domain errors |
|
||||
| `exceptions.py` | `OrionException` | Domain errors |
|
||||
|
||||
**Structure:**
|
||||
```
|
||||
@@ -1044,9 +1044,9 @@ app/modules/{module}/
|
||||
**Example:**
|
||||
```python
|
||||
# app/modules/orders/exceptions.py
|
||||
from app.exceptions import WizamartException
|
||||
from app.exceptions import OrionException
|
||||
|
||||
class OrderException(WizamartException):
|
||||
class OrderException(OrionException):
|
||||
"""Base exception for orders module."""
|
||||
pass
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
## 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 store ecosystem.
|
||||
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
|
||||
|
||||
@@ -71,7 +71,7 @@ CREATE TABLE platforms (
|
||||
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'
|
||||
domain VARCHAR(255), -- 'oms.orion.lu'
|
||||
path_prefix VARCHAR(50), -- '/oms'
|
||||
logo VARCHAR(255),
|
||||
logo_dark VARCHAR(255),
|
||||
@@ -122,7 +122,7 @@ The system uses different URL patterns for development vs production:
|
||||
- Platform sites: `localhost:9999/platforms/{code}/` → specific platform
|
||||
|
||||
**Production (custom domains):**
|
||||
- Main marketing site: `wizamart.lu/` → `main` platform
|
||||
- Main marketing site: `orion.lu/` → `main` platform
|
||||
- Platform sites: `oms.lu/`, `loyalty.lu/` → specific platform
|
||||
|
||||
### Request Processing
|
||||
@@ -284,6 +284,6 @@ Request: GET /about
|
||||
|
||||
| Platform | Code | Dev URL | Prod URL |
|
||||
|----------|------|---------|----------|
|
||||
| Main Marketing | `main` | `localhost:9999/` | `wizamart.lu/` |
|
||||
| Main Marketing | `main` | `localhost:9999/` | `orion.lu/` |
|
||||
| OMS | `oms` | `localhost:9999/platforms/oms/` | `oms.lu/` |
|
||||
| Loyalty | `loyalty` | `localhost:9999/platforms/loyalty/` | `loyalty.lu/` |
|
||||
|
||||
@@ -4,7 +4,7 @@ Complete guide to the multi-tenant architecture supporting custom domains, subdo
|
||||
|
||||
## Overview
|
||||
|
||||
The Wizamart platform supports **three deployment modes** for multi-tenancy, allowing each store to have their own isolated shop while sharing the same application instance and database.
|
||||
The Orion platform supports **three deployment modes** for multi-tenancy, allowing each store to have their own isolated shop while sharing the same application instance and database.
|
||||
|
||||
**Key Concept**: One application, multiple isolated store shops, each accessible via different URLs.
|
||||
|
||||
@@ -148,15 +148,15 @@ For path-based routing, clean paths are extracted:
|
||||
|
||||
**Path-Based Shop Routes** (Development):
|
||||
```
|
||||
Original: /stores/WIZAMART/shop/products
|
||||
Extracted: store_code = "WIZAMART"
|
||||
Original: /stores/ORION/shop/products
|
||||
Extracted: store_code = "ORION"
|
||||
Clean: /shop/products
|
||||
```
|
||||
|
||||
**Store Dashboard Routes** (All environments):
|
||||
```
|
||||
Original: /store/WIZAMART/dashboard
|
||||
Extracted: store_code = "WIZAMART"
|
||||
Original: /store/ORION/dashboard
|
||||
Extracted: store_code = "ORION"
|
||||
Clean: /dashboard
|
||||
```
|
||||
|
||||
@@ -197,13 +197,13 @@ CREATE TABLE store_domains (
|
||||
```sql
|
||||
-- Stores
|
||||
INSERT INTO stores (code, name) VALUES
|
||||
('wizamart', 'Wizamart Shop'),
|
||||
('orion', 'Orion Shop'),
|
||||
('techstore', 'Tech Store'),
|
||||
('fashionhub', 'Fashion Hub');
|
||||
|
||||
-- Custom Domains
|
||||
INSERT INTO store_domains (store_id, domain) VALUES
|
||||
(1, 'wizamart.com'),
|
||||
(1, 'orion.lu'),
|
||||
(2, 'mytechstore.net');
|
||||
```
|
||||
|
||||
@@ -421,16 +421,16 @@ Host: customdomain.com
|
||||
**Request**:
|
||||
```http
|
||||
GET /shop/products HTTP/1.1
|
||||
Host: wizamart.myplatform.com
|
||||
Host: orion.myplatform.com
|
||||
```
|
||||
|
||||
**Processing**:
|
||||
```
|
||||
1. StoreContextMiddleware
|
||||
- Checks: host != "myplatform.com"
|
||||
- Extracts: subdomain = "wizamart"
|
||||
- Queries: stores WHERE code = "wizamart"
|
||||
- Sets: request.state.store = <Store "wizamart">
|
||||
- Extracts: subdomain = "orion"
|
||||
- Queries: stores WHERE code = "orion"
|
||||
- Sets: request.state.store = <Store "orion">
|
||||
|
||||
2-4. Same as Example 1
|
||||
```
|
||||
@@ -439,7 +439,7 @@ Host: wizamart.myplatform.com
|
||||
|
||||
**Request**:
|
||||
```http
|
||||
GET /stores/WIZAMART/shop/products HTTP/1.1
|
||||
GET /stores/ORION/shop/products HTTP/1.1
|
||||
Host: myplatform.com
|
||||
```
|
||||
|
||||
@@ -447,15 +447,15 @@ Host: myplatform.com
|
||||
```
|
||||
1. StoreContextMiddleware
|
||||
- Checks: path starts with "/store/"
|
||||
- Extracts: code = "WIZAMART"
|
||||
- Queries: stores WHERE code = "WIZAMART"
|
||||
- Extracts: code = "ORION"
|
||||
- Queries: stores WHERE code = "ORION"
|
||||
- Sets: request.state.store = <Store>
|
||||
- Sets: request.state.clean_path = "/shop/products"
|
||||
|
||||
2. FastAPI Router
|
||||
- Routes registered with prefix: /stores/{store_code}/shop
|
||||
- Matches: /stores/WIZAMART/shop/products
|
||||
- store_code path parameter = "WIZAMART"
|
||||
- Matches: /stores/ORION/shop/products
|
||||
- store_code path parameter = "ORION"
|
||||
|
||||
3-4. Same as previous examples (Context, Theme middleware)
|
||||
```
|
||||
@@ -491,9 +491,9 @@ def test_shop_page_multi_tenant(client):
|
||||
# Test subdomain routing
|
||||
response = client.get(
|
||||
"/shop/products",
|
||||
headers={"Host": "wizamart.platform.com"}
|
||||
headers={"Host": "orion.platform.com"}
|
||||
)
|
||||
assert "Wizamart" in response.text
|
||||
assert "Orion" in response.text
|
||||
|
||||
# Test different store
|
||||
response = client.get(
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Observability Framework
|
||||
|
||||
The Wizamart platform includes a comprehensive observability framework for monitoring application health, collecting metrics, and tracking errors. This is part of the Framework Layer - infrastructure that modules depend on.
|
||||
The Orion platform includes a comprehensive observability framework for monitoring application health, collecting metrics, and tracking errors. This is part of the Framework Layer - infrastructure that modules depend on.
|
||||
|
||||
## Overview
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
# System Architecture
|
||||
|
||||
High-level overview of the Wizamart multi-tenant e-commerce platform architecture.
|
||||
High-level overview of the Orion multi-tenant e-commerce platform architecture.
|
||||
|
||||
## Overview
|
||||
|
||||
Wizamart is a **multi-tenant e-commerce platform** that supports three distinct interfaces:
|
||||
Orion is a **multi-tenant e-commerce platform** that supports three distinct interfaces:
|
||||
- **Admin** - Platform administration and store management
|
||||
- **Store** - Store dashboard for managing shops
|
||||
- **Shop** - Customer-facing storefronts
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Request Flow
|
||||
|
||||
Complete journey of a request through the Wizamart platform, from client to response.
|
||||
Complete journey of a request through the Orion platform, from client to response.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -42,8 +42,8 @@ graph TB
|
||||
|
||||
```http
|
||||
# Shop page request (subdomain mode)
|
||||
GET https://wizamart.platform.com/shop/products
|
||||
Host: wizamart.platform.com
|
||||
GET https://orion.platform.com/shop/products
|
||||
Host: orion.platform.com
|
||||
|
||||
# API request
|
||||
GET https://platform.com/api/v1/products?store_id=1
|
||||
@@ -86,13 +86,13 @@ logger.info(f"Request: GET /shop/products from 192.168.1.100")
|
||||
|
||||
```python
|
||||
# Input
|
||||
host = "wizamart.platform.com"
|
||||
host = "orion.platform.com"
|
||||
path = "/shop/products"
|
||||
|
||||
# Detection logic
|
||||
if host != settings.platform_domain:
|
||||
# Subdomain detected
|
||||
store_code = host.split('.')[0] # "wizamart"
|
||||
store_code = host.split('.')[0] # "orion"
|
||||
|
||||
# Query database
|
||||
store = db.query(Store).filter(
|
||||
@@ -107,7 +107,7 @@ if host != settings.platform_domain:
|
||||
|
||||
**Request State After**:
|
||||
```python
|
||||
request.state.store = <Store: Wizamart>
|
||||
request.state.store = <Store: Orion>
|
||||
request.state.store_id = 1
|
||||
request.state.clean_path = "/shop/products"
|
||||
```
|
||||
@@ -127,10 +127,10 @@ request.state.clean_path = "/shop/products"
|
||||
app.include_router(shop_pages.router, prefix="/shop")
|
||||
app.include_router(shop_pages.router, prefix="/stores/{store_code}/shop")
|
||||
|
||||
# Request: /stores/WIZAMART/shop/products
|
||||
# Request: /stores/ORION/shop/products
|
||||
# Matches: Second router (/stores/{store_code}/shop)
|
||||
# Route: @router.get("/products")
|
||||
# store_code available as path parameter = "WIZAMART"
|
||||
# store_code available as path parameter = "ORION"
|
||||
```
|
||||
|
||||
**Note:** Previous implementations used `PathRewriteMiddleware` to rewrite paths. This has been replaced with FastAPI's native routing via double router mounting.
|
||||
@@ -194,7 +194,7 @@ if hasattr(request.state, 'store_id'):
|
||||
request.state.theme = {
|
||||
"primary_color": "#3B82F6",
|
||||
"secondary_color": "#10B981",
|
||||
"logo_url": "/static/stores/wizamart/logo.png",
|
||||
"logo_url": "/static/stores/orion/logo.png",
|
||||
"custom_css": "..."
|
||||
}
|
||||
```
|
||||
@@ -289,7 +289,7 @@ async def shop_products_page(
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Wizamart - Products</title>
|
||||
<title>Orion - Products</title>
|
||||
<style>
|
||||
:root {
|
||||
--primary-color: #3B82F6;
|
||||
@@ -298,7 +298,7 @@ async def shop_products_page(
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Wizamart Shop</h1>
|
||||
<h1>Orion Shop</h1>
|
||||
<div class="products">
|
||||
<div class="product-card">
|
||||
<h2>Product 1</h2>
|
||||
@@ -412,7 +412,7 @@ sequenceDiagram
|
||||
Logging->>Store: Pass request
|
||||
Store->>DB: Query store by subdomain
|
||||
DB-->>Store: Store object
|
||||
Note over Store: Set store, store_id, clean_path
|
||||
Note over Store: Set store, store_id, clean_path
|
||||
Store->>Path: Pass request
|
||||
Note over Path: Path already clean
|
||||
Path->>Context: Pass request
|
||||
@@ -443,14 +443,14 @@ Initial State: {}
|
||||
store_id: 1,
|
||||
clean_path: "/shop/products"
|
||||
}
|
||||
|
||||
|
||||
After FrontendTypeMiddleware:
|
||||
{
|
||||
store: <Store: Orion>,
|
||||
store_id: 1,
|
||||
clean_path: "/shop/products",
|
||||
frontend_type: FrontendType.STOREFRONT
|
||||
}
|
||||
}
|
||||
|
||||
After ThemeContextMiddleware:
|
||||
{
|
||||
@@ -458,14 +458,14 @@ After FrontendTypeMiddleware:
|
||||
store_id: 1,
|
||||
clean_path: "/shop/products",
|
||||
frontend_type: FrontendType.STOREFRONT,
|
||||
theme: {
|
||||
theme: {
|
||||
primary_color: "#3B82F6",
|
||||
secondary_color: "#10B981",
|
||||
logo_url: "/static/stores/orion/logo.png",
|
||||
custom_css: "..."
|
||||
}
|
||||
}
|
||||
```
|
||||
```
|
||||
|
||||
## Performance Metrics
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# Wizamart Multi-Tenant URL Routing Guide
|
||||
# Orion Multi-Tenant URL Routing Guide
|
||||
|
||||
## Quick Answer
|
||||
|
||||
**How do customers access a store's storefront in Wizamart?**
|
||||
**How do customers access a store's storefront in Orion?**
|
||||
|
||||
There are three ways depending on the deployment mode:
|
||||
|
||||
@@ -13,8 +13,8 @@ There are three ways depending on the deployment mode:
|
||||
https://STORE_SUBDOMAIN.platform.com/storefront/products
|
||||
|
||||
Example:
|
||||
https://acme.wizamart.com/storefront/products
|
||||
https://techpro.wizamart.com/storefront/categories/electronics
|
||||
https://acme.orion.lu/storefront/products
|
||||
https://techpro.orion.lu/storefront/categories/electronics
|
||||
```
|
||||
|
||||
### 2. **CUSTOM DOMAIN MODE** (Production - Premium)
|
||||
@@ -39,7 +39,7 @@ http://localhost:8000/platforms/loyalty/stores/techpro/storefront/checkout
|
||||
|
||||
## Multi-Platform URL Routing
|
||||
|
||||
Wizamart supports multiple platforms (OMS, Loyalty, Site Builder), each with its own marketing site and store ecosystem.
|
||||
Orion supports multiple platforms (OMS, Loyalty, Site Builder), each with its own marketing site and store ecosystem.
|
||||
|
||||
### Platform URL Structure
|
||||
|
||||
@@ -61,8 +61,8 @@ Wizamart supports multiple platforms (OMS, Loyalty, Site Builder), each with its
|
||||
|
||||
| URL | What it serves |
|
||||
|-----|----------------|
|
||||
| `wizamart.lu/` | Main marketing site homepage |
|
||||
| `wizamart.lu/about` | Main marketing site about page |
|
||||
| `orion.lu/` | Main marketing site homepage |
|
||||
| `orion.lu/about` | Main marketing site about page |
|
||||
| `oms.lu/` | OMS platform homepage |
|
||||
| `oms.lu/pricing` | OMS platform pricing page |
|
||||
| `oms.lu/admin/` | Admin panel for OMS platform |
|
||||
@@ -138,7 +138,7 @@ Request arrives
|
||||
|
||||
| Platform | Code | Dev URL | Prod Domain |
|
||||
|----------|------|---------|-------------|
|
||||
| Main Marketing | `main` | `localhost:8000/` | `wizamart.lu` |
|
||||
| Main Marketing | `main` | `localhost:8000/` | `orion.lu` |
|
||||
| OMS | `oms` | `localhost:8000/platforms/oms/` | `oms.lu` |
|
||||
| Loyalty | `loyalty` | `localhost:8000/platforms/loyalty/` | `loyalty.lu` |
|
||||
| Site Builder | `site-builder` | `localhost:8000/platforms/site-builder/` | `sitebuilder.lu` |
|
||||
@@ -155,12 +155,12 @@ Request arrives
|
||||
|
||||
**Example:**
|
||||
- Store subdomain: `acme`
|
||||
- Platform domain: `wizamart.com`
|
||||
- Customer Storefront URL: `https://acme.wizamart.com/storefront/products`
|
||||
- Product Detail: `https://acme.wizamart.com/storefront/products/123`
|
||||
- Platform domain: `orion.lu`
|
||||
- Customer Storefront URL: `https://acme.orion.lu/storefront/products`
|
||||
- Product Detail: `https://acme.orion.lu/storefront/products/123`
|
||||
|
||||
**How It Works:**
|
||||
1. Customer visits `https://acme.wizamart.com/storefront/products`
|
||||
1. Customer visits `https://acme.orion.lu/storefront/products`
|
||||
2. `store_context_middleware` detects subdomain `"acme"`
|
||||
3. Queries: `SELECT * FROM stores WHERE subdomain = 'acme'`
|
||||
4. Finds Store with ID=1 (ACME Store)
|
||||
@@ -171,7 +171,7 @@ Request arrives
|
||||
9. Renders template with ACME's colors, logo, and products
|
||||
|
||||
**Advantages:**
|
||||
- Single SSL certificate for all stores (*.wizamart.com)
|
||||
- Single SSL certificate for all stores (*.orion.lu)
|
||||
- Easy to manage DNS (just add subdomains)
|
||||
- Customers don't need to bring their own domain
|
||||
|
||||
@@ -199,7 +199,7 @@ id | store_id | domain | is_active | is_verified
|
||||
|
||||
**How It Works:**
|
||||
1. Customer visits `https://store.acme-corp.com/storefront/products`
|
||||
2. `store_context_middleware` detects custom domain (not *.wizamart.com, not localhost)
|
||||
2. `store_context_middleware` detects custom domain (not *.orion.lu, not localhost)
|
||||
3. Normalizes domain to `"store.acme-corp.com"`
|
||||
4. Queries: `SELECT * FROM store_domains WHERE domain = 'store.acme-corp.com'`
|
||||
5. Finds `StoreDomain` with `store_id = 1`
|
||||
@@ -249,17 +249,17 @@ id | store_id | domain | is_active | is_verified
|
||||
|
||||
### Subdomain/Custom Domain (PRODUCTION)
|
||||
```
|
||||
https://acme.wizamart.com/storefront/ → Homepage
|
||||
https://acme.wizamart.com/storefront/products → Product Catalog
|
||||
https://acme.wizamart.com/storefront/products/123 → Product Detail
|
||||
https://acme.wizamart.com/storefront/categories/electronics → Category Page
|
||||
https://acme.wizamart.com/storefront/cart → Shopping Cart
|
||||
https://acme.wizamart.com/storefront/checkout → Checkout
|
||||
https://acme.wizamart.com/storefront/search?q=laptop → Search Results
|
||||
https://acme.wizamart.com/storefront/account/login → Customer Login
|
||||
https://acme.wizamart.com/storefront/account/dashboard → Account Dashboard (Auth Required)
|
||||
https://acme.wizamart.com/storefront/account/orders → Order History (Auth Required)
|
||||
https://acme.wizamart.com/storefront/account/profile → Profile (Auth Required)
|
||||
https://acme.orion.lu/storefront/ → Homepage
|
||||
https://acme.orion.lu/storefront/products → Product Catalog
|
||||
https://acme.orion.lu/storefront/products/123 → Product Detail
|
||||
https://acme.orion.lu/storefront/categories/electronics → Category Page
|
||||
https://acme.orion.lu/storefront/cart → Shopping Cart
|
||||
https://acme.orion.lu/storefront/checkout → Checkout
|
||||
https://acme.orion.lu/storefront/search?q=laptop → Search Results
|
||||
https://acme.orion.lu/storefront/account/login → Customer Login
|
||||
https://acme.orion.lu/storefront/account/dashboard → Account Dashboard (Auth Required)
|
||||
https://acme.orion.lu/storefront/account/orders → Order History (Auth Required)
|
||||
https://acme.orion.lu/storefront/account/profile → Profile (Auth Required)
|
||||
```
|
||||
|
||||
### Path-Based (DEVELOPMENT)
|
||||
@@ -304,7 +304,7 @@ POST /api/v1/storefront/stores/1/products/{id}/reviews → Add product review
|
||||
|
||||
### Example: No Cross-Store Leakage
|
||||
```python
|
||||
# Customer on acme.wizamart.com tries to access TechPro's products
|
||||
# Customer on acme.orion.lu tries to access TechPro's products
|
||||
# They make API call to /api/v1/storefront/stores/2/products
|
||||
|
||||
# Backend checks:
|
||||
@@ -317,14 +317,14 @@ if store.id != requested_store_id: # if 1 != 2
|
||||
|
||||
## Request Lifecycle: Complete Flow
|
||||
|
||||
### Scenario: Customer visits `https://acme.wizamart.com/storefront/products`
|
||||
### Scenario: Customer visits `https://acme.orion.lu/storefront/products`
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ 1. REQUEST ARRIVES │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
method: GET
|
||||
host: acme.wizamart.com
|
||||
host: acme.orion.lu
|
||||
path: /storefront/products
|
||||
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
@@ -332,7 +332,7 @@ if store.id != requested_store_id: # if 1 != 2
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
|
||||
A) store_context_middleware
|
||||
├─ Detects host: "acme.wizamart.com"
|
||||
├─ Detects host: "acme.orion.lu"
|
||||
├─ Extracts subdomain: "acme"
|
||||
├─ Queries: SELECT * FROM stores WHERE subdomain = 'acme'
|
||||
└─ Sets: request.state.store = Store(ACME Store)
|
||||
@@ -391,7 +391,7 @@ if store.id != requested_store_id: # if 1 != 2
|
||||
Each store's storefront is fully branded with their custom theme:
|
||||
|
||||
```python
|
||||
# Theme loaded for https://acme.wizamart.com
|
||||
# Theme loaded for https://acme.orion.lu
|
||||
request.state.theme = {
|
||||
"theme_name": "modern",
|
||||
"colors": {
|
||||
@@ -438,7 +438,7 @@ In Jinja2 template:
|
||||
- Each store looks completely separate and branded
|
||||
|
||||
### 2. Store Perspective
|
||||
- Stores can use a subdomain (free/standard): `acme.wizamart.com`
|
||||
- Stores can use a subdomain (free/standard): `acme.orion.lu`
|
||||
- Or their own custom domain (premium): `store.acme-corp.com`
|
||||
- Both routes go to the exact same backend code
|
||||
|
||||
@@ -471,7 +471,7 @@ app.include_router(storefront_pages.router, prefix="/stores/{store_code}/storefr
|
||||
**How This Works:**
|
||||
|
||||
1. **For Subdomain/Custom Domain Mode:**
|
||||
- URL: `https://acme.wizamart.com/storefront/products`
|
||||
- URL: `https://acme.orion.lu/storefront/products`
|
||||
- Matches: First router with `/storefront` prefix
|
||||
- Route: `@router.get("/products")` → Full path: `/storefront/products`
|
||||
|
||||
@@ -528,4 +528,4 @@ Set-Cookie: customer_token=eyJ...; Path=/storefront; HttpOnly; SameSite=Lax
|
||||
---
|
||||
|
||||
Generated: January 30, 2026
|
||||
Wizamart Version: Current Development
|
||||
Orion Version: Current Development
|
||||
|
||||
Reference in New Issue
Block a user