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:
@@ -25,8 +25,8 @@
|
||||
The Orion platform uses a **context-based authentication system** with three isolated security domains:
|
||||
|
||||
- **Admin Portal** - Platform administration and management
|
||||
- **Store Portal** - Multi-tenant shop management
|
||||
- **Customer Shop** - Public storefront and customer accounts
|
||||
- **Store Portal** - Multi-tenant storefront management
|
||||
- **Customer Storefront** - Public storefront and customer accounts
|
||||
|
||||
Each context uses **dual authentication** supporting both cookie-based (for HTML pages) and header-based (for API calls) authentication with complete isolation between contexts.
|
||||
|
||||
@@ -92,12 +92,12 @@ Each authentication context uses a separate cookie with path restrictions:
|
||||
|----------|------------------|-------------|--------------|
|
||||
| Admin | `admin_token` | `/admin` | Admin routes only |
|
||||
| Store | `store_token` | `/store` | Store routes only |
|
||||
| Customer | `customer_token` | `/shop` | Shop routes only |
|
||||
| Customer | `customer_token` | `/storefront` | Storefront routes only |
|
||||
|
||||
**Browser Behavior:**
|
||||
- When requesting `/admin/*`, browser sends `admin_token` cookie only
|
||||
- When requesting `/store/*`, browser sends `store_token` cookie only
|
||||
- When requesting `/shop/*`, browser sends `customer_token` cookie only
|
||||
- When requesting `/storefront/*`, browser sends `customer_token` cookie only
|
||||
|
||||
This prevents cookie leakage between contexts.
|
||||
|
||||
@@ -157,7 +157,7 @@ Set-Cookie: admin_token=<JWT>; Path=/admin; HttpOnly; Secure; SameSite=Lax
|
||||
**Role:** `store`
|
||||
**Cookie:** `store_token` (path=/store)
|
||||
|
||||
**Purpose:** Store shop management, product catalog, orders, team management.
|
||||
**Purpose:** Store management, product catalog, orders, team management.
|
||||
|
||||
**Access Control:**
|
||||
- ❌ Admin users blocked (admins use admin portal for store management)
|
||||
@@ -205,24 +205,24 @@ Set-Cookie: store_token=<JWT>; Path=/store; HttpOnly; Secure; SameSite=Lax
|
||||
|
||||
### 3. Customer Context
|
||||
|
||||
**Routes:** `/shop/account/*` (authenticated), `/shop/*` (public)
|
||||
**Routes:** `/storefront/account/*` (authenticated), `/storefront/*` (public)
|
||||
**Role:** `customer`
|
||||
**Cookie:** `customer_token` (path=/shop)
|
||||
**Cookie:** `customer_token` (path=/storefront)
|
||||
|
||||
**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://store.platform.com/shop/products`
|
||||
- **Custom Domain** (Production): `https://customdomain.com/shop/products`
|
||||
- **Path-Based** (Development): `http://localhost:8000/stores/{store_code}/shop/products`
|
||||
The `/storefront/*` routes work differently depending on deployment mode:
|
||||
- **Subdomain Mode** (Production): `https://store.platform.com/storefront/products`
|
||||
- **Custom Domain** (Production): `https://customdomain.com/storefront/products`
|
||||
- **Path-Based** (Development): `http://localhost:8000/storefront/{store_code}/products`
|
||||
|
||||
In path-based development mode, the full URL includes the store code (e.g., `/stores/acme/shop/products`), but the routes are still defined as `/shop/*` internally. See [URL Routing Guide](../architecture/url-routing/overview.md) for details.
|
||||
In path-based development mode, the full URL includes the store code (e.g., `/storefront/acme/products`), but the routes are still defined as `/storefront/*` internally. See [URL Routing Guide](../architecture/url-routing/overview.md) for details.
|
||||
|
||||
**Access Control:**
|
||||
- **Public Routes** (`/shop/products`, `/shop/cart`, etc.):
|
||||
- **Public Routes** (`/storefront/products`, `/storefront/cart`, etc.):
|
||||
- ✅ Anyone can access (no authentication)
|
||||
- **Account Routes** (`/shop/account/*`):
|
||||
- **Account Routes** (`/storefront/account/*`):
|
||||
- ❌ Admin users blocked
|
||||
- ❌ Store users blocked
|
||||
- ✅ Customer users only
|
||||
@@ -256,7 +256,7 @@ curl -X POST http://localhost:8000/api/v1/platform/stores/1/customers/login \
|
||||
|
||||
Additionally, sets cookie:
|
||||
```
|
||||
Set-Cookie: customer_token=<JWT>; Path=/shop; HttpOnly; Secure; SameSite=Lax
|
||||
Set-Cookie: customer_token=<JWT>; Path=/storefront; HttpOnly; Secure; SameSite=Lax
|
||||
```
|
||||
|
||||
---
|
||||
@@ -323,13 +323,13 @@ async def store_dashboard(
|
||||
})
|
||||
|
||||
# Customer account page
|
||||
@router.get("/shop/account/dashboard", response_class=HTMLResponse)
|
||||
@router.get("/storefront/account/dashboard", response_class=HTMLResponse)
|
||||
async def customer_dashboard(
|
||||
request: Request,
|
||||
current_user: User = Depends(get_current_customer_from_cookie_or_header),
|
||||
db: Session = Depends(get_db)
|
||||
):
|
||||
return templates.TemplateResponse("shop/account/dashboard.html", {
|
||||
return templates.TemplateResponse("storefront/account/dashboard.html", {
|
||||
"request": request,
|
||||
"user": current_user
|
||||
})
|
||||
@@ -375,7 +375,7 @@ def create_product(
|
||||
return {"message": "Product created"}
|
||||
|
||||
# Customer API
|
||||
@router.post("/api/v1/shop/orders")
|
||||
@router.post("/api/v1/storefront/orders")
|
||||
def create_order(
|
||||
order_data: OrderCreate,
|
||||
current_user: User = Depends(get_current_customer_api),
|
||||
@@ -389,10 +389,10 @@ def create_order(
|
||||
Simply don't use any authentication dependency:
|
||||
|
||||
```python
|
||||
@router.get("/shop/products")
|
||||
@router.get("/storefront/products")
|
||||
async def public_products(request: Request):
|
||||
# No authentication required
|
||||
return templates.TemplateResponse("shop/products.html", {
|
||||
return templates.TemplateResponse("storefront/products.html", {
|
||||
"request": request
|
||||
})
|
||||
```
|
||||
@@ -498,7 +498,7 @@ def get_orders(
|
||||
**Security Features:**
|
||||
- **Token type validation:** Only accepts tokens with `type: "customer"` - admin and store tokens are rejected
|
||||
- **Store validation:** Validates that `token.store_id` matches `request.state.store.id` (URL-based store)
|
||||
- Prevents cross-store token reuse (customer from Store A cannot use token on Store B's shop)
|
||||
- Prevents cross-store token reuse (customer from Store A cannot use token on Store B's storefront)
|
||||
|
||||
**Usage:**
|
||||
```python
|
||||
@@ -637,23 +637,23 @@ async def store_login_page(
|
||||
```python
|
||||
from models.database.customer import Customer
|
||||
|
||||
# Shop login page redirect
|
||||
@router.get("/shop/account/login")
|
||||
async def customer_login_page(
|
||||
# Storefront login page redirect
|
||||
@router.get("/storefront/account/login")
|
||||
async def storefront_login_page(
|
||||
request: Request,
|
||||
customer: Customer | None = Depends(get_current_customer_optional)
|
||||
):
|
||||
if customer:
|
||||
# Customer already logged in, redirect to account page
|
||||
return RedirectResponse(url="/shop/account", status_code=302)
|
||||
return RedirectResponse(url="/storefront/account", status_code=302)
|
||||
|
||||
# Not logged in, show login form
|
||||
return templates.TemplateResponse("shop/login.html", {"request": request})
|
||||
return templates.TemplateResponse("storefront/login.html", {"request": request})
|
||||
```
|
||||
|
||||
**Use Cases:**
|
||||
- Login pages (redirect if already authenticated)
|
||||
- Public shop pages with conditional customer content (e.g., "My Orders" link)
|
||||
- Public storefront pages with conditional customer content (e.g., "My Orders" link)
|
||||
- Root redirects based on authentication status
|
||||
|
||||
---
|
||||
@@ -744,7 +744,7 @@ All login endpoints return:
|
||||
Additionally, the response sets an HTTP-only cookie:
|
||||
- Admin: `admin_token` (path=/admin)
|
||||
- Store: `store_token` (path=/store)
|
||||
- Customer: `customer_token` (path=/shop)
|
||||
- Customer: `customer_token` (path=/storefront)
|
||||
|
||||
---
|
||||
|
||||
@@ -752,7 +752,7 @@ Additionally, the response sets an HTTP-only cookie:
|
||||
|
||||
### Role-Based Access Control Matrix
|
||||
|
||||
| User Role | Admin Portal | Store Portal | Shop Catalog | Customer Account |
|
||||
| User Role | Admin Portal | Store Portal | Storefront Catalog | Customer Account |
|
||||
|-----------|--------------|---------------|--------------|------------------|
|
||||
| Admin | ✅ Full | ❌ Blocked | ✅ View | ❌ Blocked |
|
||||
| Store | ❌ Blocked | ✅ Full | ✅ View | ❌ Blocked |
|
||||
@@ -863,7 +863,7 @@ Custom exceptions (such as those raised for missing claims) are preserved with t
|
||||
4. **Test navigation:**
|
||||
- Navigate to `/admin/dashboard` - Should work ✅
|
||||
- Navigate to `/store/TESTSTORE/dashboard` - Should fail (cookie not sent) ❌
|
||||
- Navigate to `/shop/account/dashboard` - Should fail (cookie not sent) ❌
|
||||
- Navigate to `/storefront/account/dashboard` - Should fail (cookie not sent) ❌
|
||||
|
||||
5. **Logout:**
|
||||
```
|
||||
@@ -886,23 +886,23 @@ Custom exceptions (such as those raised for missing claims) are preserved with t
|
||||
4. **Test navigation:**
|
||||
- Navigate to `/store/{STORE_CODE}/dashboard` - Should work ✅
|
||||
- Navigate to `/admin/dashboard` - Should fail ❌
|
||||
- Navigate to `/shop/account/dashboard` - Should fail ❌
|
||||
- Navigate to `/storefront/account/dashboard` - Should fail ❌
|
||||
|
||||
#### Test Customer Authentication
|
||||
|
||||
1. **Navigate to customer login:**
|
||||
```
|
||||
http://localhost:8000/shop/account/login
|
||||
http://localhost:8000/storefront/account/login
|
||||
```
|
||||
|
||||
2. **Login with customer credentials**
|
||||
|
||||
3. **Verify cookie in DevTools:**
|
||||
- Look for `customer_token` cookie
|
||||
- Verify `Path` is `/shop`
|
||||
- Verify `Path` is `/storefront`
|
||||
|
||||
4. **Test navigation:**
|
||||
- Navigate to `/shop/account/dashboard` - Should work ✅
|
||||
- Navigate to `/storefront/account/dashboard` - Should work ✅
|
||||
- Navigate to `/admin/dashboard` - Should fail ❌
|
||||
- Navigate to `/store/{CODE}/dashboard` - Should fail ❌
|
||||
|
||||
@@ -955,7 +955,7 @@ curl -X POST http://localhost:8000/api/v1/platform/stores/1/customers/login \
|
||||
-d '{"username":"customer","password":"customer123"}'
|
||||
|
||||
# Test authenticated endpoint with token
|
||||
curl http://localhost:8000/api/v1/shop/orders \
|
||||
curl http://localhost:8000/api/v1/storefront/orders \
|
||||
-H "Authorization: Bearer <customer_access_token>"
|
||||
|
||||
# Test cross-context blocking
|
||||
@@ -1101,8 +1101,8 @@ Admins should not log into store portal as this violates security boundaries.
|
||||
**Symptom:** Customer trying to access management interfaces
|
||||
|
||||
**Explanation:** Customers only have access to:
|
||||
- Public shop routes: `/shop/products`, etc.
|
||||
- Their account: `/shop/account/*`
|
||||
- Public storefront routes: `/storefront/products`, etc.
|
||||
- Their account: `/storefront/account/*`
|
||||
|
||||
Admin and store portals are not accessible to customers.
|
||||
|
||||
@@ -1169,7 +1169,7 @@ Look for:
|
||||
2. **Don't mix authentication contexts:**
|
||||
- Admin users should use admin portal
|
||||
- Store users should use store portal
|
||||
- Customers should use shop
|
||||
- Customers should use storefront
|
||||
|
||||
3. **Always check user.is_active:**
|
||||
```python
|
||||
|
||||
Reference in New Issue
Block a user