docs: add consolidated dev URL reference and migrate /shop to /storefront
Some checks failed
Some checks failed
- Add Development URL Quick Reference section to url-routing overview with all login URLs, entry points, and full examples - Replace /shop/ path segments with /storefront/ across 50 docs files - Update file references: shop_pages.py → storefront_pages.py, templates/shop/ → templates/storefront/, api/v1/shop/ → api/v1/storefront/ - Preserve domain references (orion.shop) and /store/ staff dashboard paths - Archive docs left unchanged (historical) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -4,14 +4,14 @@ Complete guide to the multi-tenant architecture supporting custom domains, subdo
|
||||
|
||||
## Overview
|
||||
|
||||
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.
|
||||
The Orion platform supports **three deployment modes** for multi-tenancy, allowing each store to have their own isolated storefront while sharing the same application instance and database.
|
||||
|
||||
**Key Concept**: One application, multiple isolated store shops, each accessible via different URLs.
|
||||
**Key Concept**: One application, multiple isolated store storefronts, each accessible via different URLs.
|
||||
|
||||
**Important Distinction:**
|
||||
- **Store Dashboard** (all modes): `/store/{code}/*` (singular) - Management interface for stores
|
||||
- **Shop Storefront** (path-based only): `/stores/{code}/shop/*` (plural) - Customer-facing shop
|
||||
- This naming distinction helps separate administrative routes from public-facing shop routes
|
||||
- **Storefront** (path-based only): `/storefront/{code}/*` - Customer-facing storefront
|
||||
- This naming distinction helps separate administrative routes from public-facing storefront routes
|
||||
|
||||
## The Three Routing Modes
|
||||
|
||||
@@ -21,16 +21,16 @@ The Orion platform supports **three deployment modes** for multi-tenancy, allowi
|
||||
|
||||
**Example**:
|
||||
```
|
||||
customdomain1.com → Store 1 Shop
|
||||
anothershop.com → Store 2 Shop
|
||||
beststore.net → Store 3 Shop
|
||||
customdomain1.com → Store 1 Storefront
|
||||
anothershop.com → Store 2 Storefront
|
||||
beststore.net → Store 3 Storefront
|
||||
```
|
||||
|
||||
**How it works**:
|
||||
1. Store registers a custom domain
|
||||
2. Domain's DNS is configured to point to the platform
|
||||
3. Platform detects store by matching domain in database
|
||||
4. Store's shop is displayed with their theme/branding
|
||||
4. Store's storefront is displayed with their theme/branding
|
||||
|
||||
**Use Case**: Professional stores who want their own branded domain
|
||||
|
||||
@@ -50,9 +50,9 @@ store_id | domain
|
||||
|
||||
**Example**:
|
||||
```
|
||||
store1.platform.com → Store 1 Shop
|
||||
store2.platform.com → Store 2 Shop
|
||||
store3.platform.com → Store 3 Shop
|
||||
store1.platform.com → Store 1 Storefront
|
||||
store2.platform.com → Store 2 Storefront
|
||||
store3.platform.com → Store 3 Storefront
|
||||
admin.platform.com → Admin Interface
|
||||
```
|
||||
|
||||
@@ -69,9 +69,9 @@ admin.platform.com → Admin Interface
|
||||
# Stores table
|
||||
id | code | name
|
||||
---|---------|----------
|
||||
1 | store1 | Store One Shop
|
||||
2 | store2 | Store Two Shop
|
||||
3 | store3 | Store Three Shop
|
||||
1 | store1 | Store One Storefront
|
||||
2 | store2 | Store Two Storefront
|
||||
3 | store3 | Store Three Storefront
|
||||
```
|
||||
|
||||
### 3. Path-Based Mode
|
||||
@@ -80,9 +80,9 @@ id | code | name
|
||||
|
||||
**Example**:
|
||||
```
|
||||
platform.com/stores/store1/shop → Store 1 Shop
|
||||
platform.com/stores/store2/shop → Store 2 Shop
|
||||
platform.com/stores/store3/shop → Store 3 Shop
|
||||
platform.com/storefront/store1 → Store 1 Storefront
|
||||
platform.com/storefront/store2 → Store 2 Storefront
|
||||
platform.com/storefront/store3 → Store 3 Storefront
|
||||
```
|
||||
|
||||
**How it works**:
|
||||
@@ -94,7 +94,7 @@ platform.com/stores/store3/shop → Store 3 Shop
|
||||
**Use Case**: Development and testing environments only
|
||||
|
||||
**Path Patterns**:
|
||||
- `/stores/{code}/shop/*` - Storefront pages (correct pattern)
|
||||
- `/storefront/{code}/*` - Storefront pages (correct pattern)
|
||||
- `/store/{code}/*` - Store dashboard pages (different context)
|
||||
|
||||
## Routing Mode Comparison
|
||||
@@ -107,7 +107,7 @@ platform.com/stores/store3/shop → Store 3 Shop
|
||||
| **SEO Benefits** | Best (own domain) | Good | Limited |
|
||||
| **Cost** | High (domain + SSL) | Low (wildcard SSL) | Lowest |
|
||||
| **Isolation** | Best (separate domain) | Good | Good |
|
||||
| **URL Appearance** | `shop.com` | `shop.platform.com` | `platform.com/store/shop` |
|
||||
| **URL Appearance** | `shop.com` | `shop.platform.com` | `platform.com/storefront/store` |
|
||||
|
||||
## Implementation Details
|
||||
|
||||
@@ -133,7 +133,7 @@ def detect_store(request):
|
||||
|
||||
# 3. Try path-based
|
||||
path = request.url.path
|
||||
if path.startswith("/store/") or path.startswith("/stores/"):
|
||||
if path.startswith("/store/") or path.startswith("/storefront/"):
|
||||
store_code = extract_code_from_path(path)
|
||||
store = find_by_code(store_code)
|
||||
if store:
|
||||
@@ -146,11 +146,11 @@ def detect_store(request):
|
||||
|
||||
For path-based routing, clean paths are extracted:
|
||||
|
||||
**Path-Based Shop Routes** (Development):
|
||||
**Path-Based Storefront Routes** (Development):
|
||||
```
|
||||
Original: /stores/ORION/shop/products
|
||||
Original: /storefront/ORION/products
|
||||
Extracted: store_code = "ORION"
|
||||
Clean: /shop/products
|
||||
Clean: /storefront/products
|
||||
```
|
||||
|
||||
**Store Dashboard Routes** (All environments):
|
||||
@@ -160,11 +160,11 @@ Extracted: store_code = "ORION"
|
||||
Clean: /dashboard
|
||||
```
|
||||
|
||||
**Note**: The shop storefront uses `/stores/` (plural) while the store dashboard uses `/store/` (singular). This distinction helps separate customer-facing shop routes from store management routes.
|
||||
**Note**: The storefront uses `/storefront/` while the store dashboard uses `/store/` (singular). This distinction helps separate customer-facing storefront routes from store management routes.
|
||||
|
||||
**Why Clean Path?**
|
||||
- FastAPI routes don't include store prefix
|
||||
- Routes defined as: `@app.get("/shop/products")`
|
||||
- Routes defined as: `@app.get("/storefront/products")`
|
||||
- Path must be rewritten to match routes
|
||||
|
||||
## Database Schema
|
||||
@@ -197,7 +197,7 @@ CREATE TABLE store_domains (
|
||||
```sql
|
||||
-- Stores
|
||||
INSERT INTO stores (code, name) VALUES
|
||||
('orion', 'Orion Shop'),
|
||||
('orion', 'Orion Storefront'),
|
||||
('techstore', 'Tech Store'),
|
||||
('fashionhub', 'Fashion Hub');
|
||||
|
||||
@@ -220,9 +220,9 @@ INSERT INTO store_domains (store_id, domain) VALUES
|
||||
**URLs**:
|
||||
```
|
||||
myplatform.com/admin
|
||||
myplatform.com/stores/shop1/shop
|
||||
myplatform.com/stores/shop2/shop
|
||||
myplatform.com/stores/shop3/shop
|
||||
myplatform.com/storefront/shop1
|
||||
myplatform.com/storefront/shop2
|
||||
myplatform.com/storefront/shop3
|
||||
```
|
||||
|
||||
**Infrastructure**:
|
||||
@@ -272,8 +272,8 @@ shop3.myplatform.com → Store 3
|
||||
shop4.myplatform.com → Store 4
|
||||
|
||||
# Path-based (free tier)
|
||||
myplatform.com/stores/shop5/shop → Store 5
|
||||
myplatform.com/stores/shop6/shop → Store 6
|
||||
myplatform.com/storefront/shop5 → Store 5
|
||||
myplatform.com/storefront/shop6 → Store 6
|
||||
```
|
||||
|
||||
**Infrastructure**:
|
||||
@@ -391,7 +391,7 @@ static/
|
||||
|
||||
**Request**:
|
||||
```http
|
||||
GET /shop/products HTTP/1.1
|
||||
GET /storefront/products HTTP/1.1
|
||||
Host: customdomain.com
|
||||
```
|
||||
|
||||
@@ -404,8 +404,8 @@ Host: customdomain.com
|
||||
- Sets: request.state.store = <Store 1>
|
||||
|
||||
2. ContextDetectionMiddleware
|
||||
- Analyzes: path = "/shop/products"
|
||||
- Sets: context_type = SHOP
|
||||
- Analyzes: path = "/storefront/products"
|
||||
- Sets: context_type = STOREFRONT
|
||||
|
||||
3. ThemeContextMiddleware
|
||||
- Queries: store_themes WHERE store_id = 1
|
||||
@@ -420,7 +420,7 @@ Host: customdomain.com
|
||||
|
||||
**Request**:
|
||||
```http
|
||||
GET /shop/products HTTP/1.1
|
||||
GET /storefront/products HTTP/1.1
|
||||
Host: orion.myplatform.com
|
||||
```
|
||||
|
||||
@@ -439,22 +439,22 @@ Host: orion.myplatform.com
|
||||
|
||||
**Request**:
|
||||
```http
|
||||
GET /stores/ORION/shop/products HTTP/1.1
|
||||
GET /storefront/ORION/products HTTP/1.1
|
||||
Host: myplatform.com
|
||||
```
|
||||
|
||||
**Processing**:
|
||||
```
|
||||
1. StoreContextMiddleware
|
||||
- Checks: path starts with "/store/"
|
||||
- Checks: path starts with "/storefront/"
|
||||
- Extracts: code = "ORION"
|
||||
- Queries: stores WHERE code = "ORION"
|
||||
- Sets: request.state.store = <Store>
|
||||
- Sets: request.state.clean_path = "/shop/products"
|
||||
- Sets: request.state.clean_path = "/storefront/products"
|
||||
|
||||
2. FastAPI Router
|
||||
- Routes registered with prefix: /stores/{store_code}/shop
|
||||
- Matches: /stores/ORION/shop/products
|
||||
- Routes registered with prefix: /storefront/{store_code}
|
||||
- Matches: /storefront/ORION/products
|
||||
- store_code path parameter = "ORION"
|
||||
|
||||
3-4. Same as previous examples (Context, Theme middleware)
|
||||
@@ -487,17 +487,17 @@ def test_store_detection_subdomain():
|
||||
### Integration Tests
|
||||
|
||||
```python
|
||||
def test_shop_page_multi_tenant(client):
|
||||
def test_storefront_page_multi_tenant(client):
|
||||
# Test subdomain routing
|
||||
response = client.get(
|
||||
"/shop/products",
|
||||
"/storefront/products",
|
||||
headers={"Host": "orion.platform.com"}
|
||||
)
|
||||
assert "Orion" in response.text
|
||||
|
||||
# Test different store
|
||||
response = client.get(
|
||||
"/shop/products",
|
||||
"/storefront/products",
|
||||
headers={"Host": "techstore.platform.com"}
|
||||
)
|
||||
assert "Tech Store" in response.text
|
||||
|
||||
Reference in New Issue
Block a user