Fixed url pattern in the doc for path-based shops
This commit is contained in:
@@ -211,6 +211,14 @@ Set-Cookie: vendor_token=<JWT>; Path=/vendor; HttpOnly; Secure; SameSite=Lax
|
||||
|
||||
**Purpose:** Product browsing (public), customer accounts, orders, profile management.
|
||||
|
||||
**Important - URL Pattern Context:**
|
||||
The `/shop/*` routes work differently depending on deployment mode:
|
||||
- **Subdomain Mode** (Production): `https://vendor.platform.com/shop/products`
|
||||
- **Custom Domain** (Production): `https://customdomain.com/shop/products`
|
||||
- **Path-Based** (Development): `http://localhost:8000/vendors/{vendor_code}/shop/products`
|
||||
|
||||
In path-based development mode, the full URL includes the vendor code (e.g., `/vendors/acme/shop/products`), but the routes are still defined as `/shop/*` internally. See [URL Routing Guide](../architecture/url-routing/overview.md) for details.
|
||||
|
||||
**Access Control:**
|
||||
- **Public Routes** (`/shop/products`, `/shop/cart`, etc.):
|
||||
- ✅ Anyone can access (no authentication)
|
||||
|
||||
@@ -73,9 +73,9 @@ Injects: request.state.vendor = <Vendor object>
|
||||
- Rewrites `request.scope['path']` to remove vendor prefix
|
||||
- Allows FastAPI routes to match correctly
|
||||
|
||||
**Example**:
|
||||
**Example** (Path-Based Development Mode):
|
||||
```
|
||||
Original path: /vendor/WIZAMART/shop/products
|
||||
Original path: /vendors/WIZAMART/shop/products
|
||||
Clean path: /shop/products (set by VendorContextMiddleware)
|
||||
↓
|
||||
Path Rewrite Middleware changes request path to: /shop/products
|
||||
|
||||
@@ -8,6 +8,11 @@ The Wizamart platform supports **three deployment modes** for multi-tenancy, all
|
||||
|
||||
**Key Concept**: One application, multiple isolated vendor shops, each accessible via different URLs.
|
||||
|
||||
**Important Distinction:**
|
||||
- **Vendor Dashboard** (all modes): `/vendor/{code}/*` (singular) - Management interface for vendors
|
||||
- **Shop Storefront** (path-based only): `/vendors/{code}/shop/*` (plural) - Customer-facing shop
|
||||
- This naming distinction helps separate administrative routes from public-facing shop routes
|
||||
|
||||
## The Three Routing Modes
|
||||
|
||||
### 1. Custom Domain Mode
|
||||
@@ -75,9 +80,9 @@ id | code | name
|
||||
|
||||
**Example**:
|
||||
```
|
||||
platform.com/vendor/vendor1/shop → Vendor 1 Shop
|
||||
platform.com/vendor/vendor2/shop → Vendor 2 Shop
|
||||
platform.com/vendors/vendor3/shop → Vendor 3 Shop (alternative)
|
||||
platform.com/vendors/vendor1/shop → Vendor 1 Shop
|
||||
platform.com/vendors/vendor2/shop → Vendor 2 Shop
|
||||
platform.com/vendors/vendor3/shop → Vendor 3 Shop
|
||||
```
|
||||
|
||||
**How it works**:
|
||||
@@ -86,12 +91,11 @@ platform.com/vendors/vendor3/shop → Vendor 3 Shop (alternative)
|
||||
3. Path is rewritten for routing
|
||||
4. All vendors on same domain
|
||||
|
||||
**Use Case**: Simplest deployment, single domain certificate
|
||||
**Use Case**: Development and testing environments only
|
||||
|
||||
**Path Patterns**:
|
||||
- `/vendor/{code}/shop/*` - Storefront pages
|
||||
- `/vendor/{code}/api/*` - API endpoints (if needed)
|
||||
- `/vendors/{code}/shop/*` - Alternative pattern
|
||||
- `/vendors/{code}/shop/*` - Storefront pages (correct pattern)
|
||||
- `/vendor/{code}/*` - Vendor dashboard pages (different context)
|
||||
|
||||
## Routing Mode Comparison
|
||||
|
||||
@@ -142,20 +146,22 @@ def detect_vendor(request):
|
||||
|
||||
For path-based routing, clean paths are extracted:
|
||||
|
||||
**Example 1**: Single vendor prefix
|
||||
```
|
||||
Original: /vendor/WIZAMART/shop/products
|
||||
Extracted: vendor_code = "WIZAMART"
|
||||
Clean: /shop/products
|
||||
```
|
||||
|
||||
**Example 2**: Plural vendors prefix
|
||||
**Path-Based Shop Routes** (Development):
|
||||
```
|
||||
Original: /vendors/WIZAMART/shop/products
|
||||
Extracted: vendor_code = "WIZAMART"
|
||||
Clean: /shop/products
|
||||
```
|
||||
|
||||
**Vendor Dashboard Routes** (All environments):
|
||||
```
|
||||
Original: /vendor/WIZAMART/dashboard
|
||||
Extracted: vendor_code = "WIZAMART"
|
||||
Clean: /dashboard
|
||||
```
|
||||
|
||||
**Note**: The shop storefront uses `/vendors/` (plural) while the vendor dashboard uses `/vendor/` (singular). This distinction helps separate customer-facing shop routes from vendor management routes.
|
||||
|
||||
**Why Clean Path?**
|
||||
- FastAPI routes don't include vendor prefix
|
||||
- Routes defined as: `@app.get("/shop/products")`
|
||||
@@ -214,9 +220,9 @@ INSERT INTO vendor_domains (vendor_id, domain) VALUES
|
||||
**URLs**:
|
||||
```
|
||||
myplatform.com/admin
|
||||
myplatform.com/vendor/shop1/shop
|
||||
myplatform.com/vendor/shop2/shop
|
||||
myplatform.com/vendor/shop3/shop
|
||||
myplatform.com/vendors/shop1/shop
|
||||
myplatform.com/vendors/shop2/shop
|
||||
myplatform.com/vendors/shop3/shop
|
||||
```
|
||||
|
||||
**Infrastructure**:
|
||||
@@ -266,8 +272,8 @@ shop3.myplatform.com → Vendor 3
|
||||
shop4.myplatform.com → Vendor 4
|
||||
|
||||
# Path-based (free tier)
|
||||
myplatform.com/vendor/shop5/shop → Vendor 5
|
||||
myplatform.com/vendor/shop6/shop → Vendor 6
|
||||
myplatform.com/vendors/shop5/shop → Vendor 5
|
||||
myplatform.com/vendors/shop6/shop → Vendor 6
|
||||
```
|
||||
|
||||
**Infrastructure**:
|
||||
@@ -433,7 +439,7 @@ Host: wizamart.myplatform.com
|
||||
|
||||
**Request**:
|
||||
```http
|
||||
GET /vendor/WIZAMART/shop/products HTTP/1.1
|
||||
GET /vendors/WIZAMART/shop/products HTTP/1.1
|
||||
Host: myplatform.com
|
||||
```
|
||||
|
||||
|
||||
@@ -47,11 +47,11 @@ vendor2.platform.com → Vendor 2 Shop
|
||||
admin.platform.com → Admin Interface
|
||||
```
|
||||
|
||||
#### Path-Based Mode
|
||||
#### Path-Based Mode (Development Only)
|
||||
```
|
||||
platform.com/vendor/vendor1/shop → Vendor 1 Shop
|
||||
platform.com/vendor/vendor2/shop → Vendor 2 Shop
|
||||
platform.com/admin → Admin Interface
|
||||
platform.com/vendors/vendor1/shop → Vendor 1 Shop
|
||||
platform.com/vendors/vendor2/shop → Vendor 2 Shop
|
||||
platform.com/admin → Admin Interface
|
||||
```
|
||||
|
||||
**See:** [Multi-Tenant System](multi-tenant.md) for detailed implementation
|
||||
|
||||
@@ -121,8 +121,8 @@ request.state.clean_path = "/shop/products"
|
||||
**Example** (Path-Based Mode):
|
||||
|
||||
```python
|
||||
# Input (path-based mode)
|
||||
original_path = "/vendor/WIZAMART/shop/products"
|
||||
# Input (path-based development mode)
|
||||
original_path = "/vendors/WIZAMART/shop/products"
|
||||
clean_path = "/shop/products" # From VendorContextMiddleware
|
||||
|
||||
# Path rewrite
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
|
||||
There are three ways depending on the deployment mode:
|
||||
|
||||
**⚠️ Important:** This guide describes **customer-facing shop routes**. For vendor dashboard/management routes, see [Vendor Dashboard Documentation](../../vendor/). The shop uses `/vendors/{code}/shop/*` (plural) in path-based mode, while the vendor dashboard uses `/vendor/{code}/*` (singular).
|
||||
|
||||
### 1. **SUBDOMAIN MODE** (Production - Recommended)
|
||||
```
|
||||
https://VENDOR_SUBDOMAIN.platform.com/shop/products
|
||||
@@ -26,11 +28,11 @@ https://shop.techpro.io/shop/cart
|
||||
|
||||
### 3. **PATH-BASED MODE** (Development Only)
|
||||
```
|
||||
http://localhost:PORT/vendor/VENDOR_CODE/shop/products
|
||||
http://localhost:PORT/vendors/VENDOR_CODE/shop/products
|
||||
|
||||
Example:
|
||||
http://localhost:8000/vendor/acme/shop/products
|
||||
http://localhost:8000/vendor/techpro/shop/checkout
|
||||
http://localhost:8000/vendors/acme/shop/products
|
||||
http://localhost:8000/vendors/techpro/shop/checkout
|
||||
```
|
||||
|
||||
---
|
||||
@@ -107,15 +109,15 @@ id | vendor_id | domain | is_active | is_verified
|
||||
|
||||
### 3. PATH-BASED MODE (Development Only)
|
||||
|
||||
**URL Pattern:** `http://localhost:PORT/vendor/VENDOR_CODE/shop/...`
|
||||
**URL Pattern:** `http://localhost:PORT/vendors/VENDOR_CODE/shop/...`
|
||||
|
||||
**Example:**
|
||||
- Development: `http://localhost:8000/vendor/acme/shop/products`
|
||||
- With port: `http://localhost:8000/vendor/acme/shop/products/123`
|
||||
- Development: `http://localhost:8000/vendors/acme/shop/products`
|
||||
- With port: `http://localhost:8000/vendors/acme/shop/products/123`
|
||||
|
||||
**How It Works:**
|
||||
1. Developer visits `http://localhost:8000/vendor/acme/shop/products`
|
||||
2. `vendor_context_middleware` detects path-based routing pattern `/vendor/acme/...`
|
||||
1. Developer visits `http://localhost:8000/vendors/acme/shop/products`
|
||||
2. `vendor_context_middleware` detects path-based routing pattern `/vendors/acme/...`
|
||||
3. Extracts vendor code `"acme"` from the path
|
||||
4. Looks up Vendor: `SELECT * FROM vendors WHERE subdomain = 'acme'`
|
||||
5. Sets `request.state.vendor = Vendor(acme)`
|
||||
@@ -151,12 +153,12 @@ https://acme.wizamart.com/shop/account/profile → Profile (Auth Require
|
||||
|
||||
### Path-Based (DEVELOPMENT)
|
||||
```
|
||||
http://localhost:8000/vendor/acme/shop/ → Homepage
|
||||
http://localhost:8000/vendor/acme/shop/products → Products
|
||||
http://localhost:8000/vendor/acme/shop/products/123 → Product Detail
|
||||
http://localhost:8000/vendor/acme/shop/cart → Cart
|
||||
http://localhost:8000/vendor/acme/shop/checkout → Checkout
|
||||
http://localhost:8000/vendor/acme/shop/account/login → Login
|
||||
http://localhost:8000/vendors/acme/shop/ → Homepage
|
||||
http://localhost:8000/vendors/acme/shop/products → Products
|
||||
http://localhost:8000/vendors/acme/shop/products/123 → Product Detail
|
||||
http://localhost:8000/vendors/acme/shop/cart → Cart
|
||||
http://localhost:8000/vendors/acme/shop/checkout → Checkout
|
||||
http://localhost:8000/vendors/acme/shop/account/login → Login
|
||||
```
|
||||
|
||||
### API Endpoints (Same for All Modes)
|
||||
@@ -350,9 +352,9 @@ In Jinja2 template:
|
||||
The `vendor_context_middleware` sets `clean_path` for path-based URLs, but this isn't used for FastAPI routing.
|
||||
|
||||
**Problem:**
|
||||
- Incoming: `GET http://localhost:8000/vendor/acme/shop/products`
|
||||
- Incoming: `GET http://localhost:8000/vendors/acme/shop/products`
|
||||
- Routes registered: `@router.get("/shop/products")`
|
||||
- FastAPI tries to match `/vendor/acme/shop/products` against `/shop/products`
|
||||
- FastAPI tries to match `/vendors/acme/shop/products` against `/shop/products`
|
||||
- Result: ❌ 404 Not Found
|
||||
|
||||
**Solution (Recommended):**
|
||||
@@ -374,7 +376,7 @@ app.middleware("http")(path_rewrite_middleware)
|
||||
Or alternatively, mount the router twice:
|
||||
```python
|
||||
app.include_router(shop_pages.router, prefix="/shop")
|
||||
app.include_router(shop_pages.router, prefix="/vendor") # Allows /vendor/* paths
|
||||
app.include_router(shop_pages.router, prefix="/vendors/{vendor_code}/shop") # Path-based development mode
|
||||
```
|
||||
|
||||
---
|
||||
@@ -401,7 +403,7 @@ Set-Cookie: customer_token=eyJ...; Path=/shop; HttpOnly; SameSite=Lax
|
||||
|------|-----|----------|-----|-----|
|
||||
| Subdomain | `vendor.platform.com/shop` | Production (standard) | *.platform.com | Add subdomains |
|
||||
| Custom Domain | `vendor-domain.com/shop` | Production (premium) | Per vendor | Vendor configures |
|
||||
| Path-Based | `localhost:8000/vendor/v/shop` | Development only | None | None |
|
||||
| Path-Based | `localhost:8000/vendors/v/shop` | Development only | None | None |
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -207,7 +207,7 @@ Middleware for request/response logging and performance monitoring.
|
||||
Middleware function that rewrites request paths for path-based vendor routing.
|
||||
|
||||
**Purpose:**
|
||||
Allows `/vendor/VENDORCODE/shop/products` to be internally routed as `/shop/products` for proper FastAPI route matching.
|
||||
Allows `/vendors/VENDORCODE/shop/products` (path-based development mode) to be internally routed as `/shop/products` for proper FastAPI route matching.
|
||||
|
||||
**Execution Order:**
|
||||
Must run AFTER VendorContextMiddleware and BEFORE ContextDetectionMiddleware.
|
||||
|
||||
@@ -66,11 +66,11 @@ vendor2.platform.com → Vendor 2 Shop
|
||||
admin.platform.com → Admin Interface
|
||||
```
|
||||
|
||||
**3. Path-Based Mode**
|
||||
**3. Path-Based Mode** (Development Only)
|
||||
```
|
||||
platform.com/vendor/vendor1/shop → Vendor 1 Shop
|
||||
platform.com/vendor/vendor2/shop → Vendor 2 Shop
|
||||
platform.com/admin → Admin Interface
|
||||
platform.com/vendors/vendor1/shop → Vendor 1 Shop
|
||||
platform.com/vendors/vendor2/shop → Vendor 2 Shop
|
||||
platform.com/admin → Admin Interface
|
||||
```
|
||||
|
||||
**Learn more**: [Multi-Tenant System](architecture/multi-tenant.md)
|
||||
|
||||
Reference in New Issue
Block a user