docs: add consolidated dev URL reference and migrate /shop to /storefront
Some checks failed
CI / ruff (push) Successful in 10s
CI / validate (push) Has been cancelled
CI / dependency-scanning (push) Has been cancelled
CI / docs (push) Has been cancelled
CI / deploy (push) Has been cancelled
CI / pytest (push) Has been cancelled

- 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:
2026-02-25 13:23:44 +01:00
parent 3df75e2e78
commit d648c921b7
50 changed files with 1104 additions and 1049 deletions

View File

@@ -7,12 +7,12 @@
│ Browser │
│ │
│ ┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐ │
│ │ Admin Area │ │ Store Area │ │ Shop Area │ │
│ │ /admin/* │ │ /store/* │ │ /shop/* │ │
│ │ Admin Area │ │ Store Area │ │ Storefront Area │ │
│ │ /admin/* │ │ /store/* │ │ /storefront/* │ │
│ │ │ │ │ │ │ │
│ │ 🍪 admin_token │ │ 🍪 store_token │ │ 🍪 customer_ │ │
│ │ Path: /admin │ │ Path: /store │ │ token │ │
│ │ │ │ │ │ Path: /shop │ │
│ │ │ │ │ │ Path: /storefront │ │
│ └──────────────────┘ └──────────────────┘ └──────────────────┘ │
│ │ │ │ │
│ ├──────────────────────┼─────────────────────┤ │
@@ -22,8 +22,8 @@
│ │ │
▼ ▼ ▼
┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐
│ Admin Backend │ │ Store Backend │ │ Shop Backend │
│ /admin/* │ │ /store/* │ │ /shop/* │
│ Admin Backend │ │ Store Backend │ │ Storefront Backend │
│ /admin/* │ │ /store/* │ │ /storefront/* │
│ │ │ │ │ │
│ ✅ admin_token │ │ ✅ store_token │ │ ✅ customer_ │
│ ❌ store_token │ │ ❌ admin_token │ │ token │
@@ -128,14 +128,14 @@
└────────────────────────────────────┘
```
## Login Flow - Customer (Shop)
## Login Flow - Customer (Storefront)
```
┌──────────┐
│ Browser │
└──────────┘
│ POST /api/v1/shop/auth/login
│ POST /api/v1/storefront/auth/login
│ { email, password }
┌─────────────────────────┐
@@ -146,20 +146,20 @@
│ 3. Generate JWT │
└─────────────────────────┘
│ Set-Cookie: customer_token=<JWT>; Path=/shop; HttpOnly; SameSite=Lax
│ Set-Cookie: customer_token=<JWT>; Path=/storefront; HttpOnly; SameSite=Lax
│ Response: { access_token, user }
┌──────────┐
│ Browser │──────────────────────────────────────┐
│ │ │
│ 🍪 customer_token (Path=/shop) │
│ 🍪 customer_token (Path=/storefront) │
│ 💾 localStorage.access_token │
└──────────┘ │
│ │
├── Navigate to /shop/account/dashboard ─────┤
├── Navigate to /storefront/account/dashboard ─────┤
│ (Cookie sent automatically) │
│ │
└── API call to /api/v1/shop/orders ─────────┤
└── API call to /api/v1/storefront/orders ─────────┤
(Authorization: Bearer <token>) │
┌────────────────────────────────────────┐
@@ -189,7 +189,7 @@
┌───────────────────────────┼───────────────────────────┐
│ │ │ │ │
Starts with Starts with Starts with Starts with Starts with
/admin/* /store/* /shop/* /api/* (public)
/admin/* /store/* /storefront/* /api/* (public)
│ │ │ │ │
▼ ▼ ▼ ▼ ▼
┌────────────────┐┌────────────────┐┌────────────────┐┌────────────────┐┌────────────────┐
@@ -307,17 +307,17 @@ Customer trying to access admin route:
```
```
Customer cookie sent to shop route (allowed):
Customer cookie sent to storefront route (allowed):
┌──────────────────────────────────────────┐
│ Cookie: customer_token=<JWT> (Path=/shop)│
│ Request: GET /shop/account/orders │
│ Cookie: customer_token=<JWT> (Path=/storefront)│
│ Request: GET /storefront/account/orders │
└──────────────────────────────────────────┘
Browser checks cookie path
Path /shop matches /shop
Path /storefront matches /storefront
✅ Cookie SENT automatically
@@ -342,7 +342,7 @@ LOGIN
├── Server sets cookie:
│ • Name: admin_token, store_token, or customer_token
│ • Value: JWT
│ • Path: /admin, /store, or /shop (context-specific)
│ • Path: /admin, /store, or /storefront (context-specific)
│ • HttpOnly: true
│ • Secure: true (production)
│ • SameSite: Lax
@@ -386,5 +386,5 @@ LOGOUT
2. **Role Checking** = Strict role validation at each boundary (admin, store, customer)
3. **Dual Auth Support** = Cookies for HTML pages, headers for API endpoints
4. **Security First** = HttpOnly, Secure, SameSite protection on all cookies
5. **Clear Boundaries** = Each context (admin/store/shop) is completely isolated
5. **Clear Boundaries** = Each context (admin/store/storefront) is completely isolated
6. **Three User Types** = Admins manage platform, stores manage stores, customers shop

View File

@@ -27,7 +27,7 @@ def store_page(user: User = Depends(get_current_store_from_cookie_or_header)):
pass
# Customer page - NOTE: Returns Customer, not User!
@router.get("/shop/account/dashboard")
@router.get("/storefront/account/dashboard")
def customer_page(customer: Customer = Depends(get_current_customer_from_cookie_or_header)):
pass # customer.id, customer.email, customer.store_id
```
@@ -53,7 +53,7 @@ def store_api(user: User = Depends(get_current_store_api)):
pass # user.token_store_id for store context
# Customer API - NOTE: Returns Customer, not User!
@router.post("/api/v1/shop/orders")
@router.post("/api/v1/storefront/orders")
def customer_api(request: Request, customer: Customer = Depends(get_current_customer_api)):
pass # customer.id, request.state.store validated to match
```
@@ -66,7 +66,7 @@ def customer_api(request: Request, customer: Customer = Depends(get_current_cust
|---------|--------|------|------|--------|
| **Admin** | `admin_token` | `/admin` | `admin` | `/admin/*` |
| **Store** | `store_token` | `/store` | `store` | `/store/*` |
| **Customer** | `customer_token` | `/shop` | `customer` | `/shop/account/*` |
| **Customer** | `customer_token` | `/storefront` | `customer` | `/storefront/account/*` |
---
@@ -208,8 +208,8 @@ console.log(parseJwt(localStorage.getItem('token')));
3.**Admins** cannot access store/customer portals
4.**Stores** cannot access admin/customer portals
5.**Customers** cannot access admin/store portals
6.**Public shop** (`/shop/products`) needs no auth
7.**Customer accounts** (`/shop/account/*`) need auth
6.**Public storefront** (`/storefront/products`) needs no auth
7.**Customer accounts** (`/storefront/account/*`) need auth
---

View File

@@ -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

View File

@@ -167,7 +167,7 @@ Returns JSON error responses suitable for API clients.
### Admin/Store Dashboard (`/admin/*`, `/store/*`)
Returns JSON errors or redirects to error pages based on accept headers.
### Shop Requests (`/shop/*`)
### Storefront Requests (`/storefront/*`)
Returns themed error pages matching the store's shop design.
## Logging

View File

@@ -335,5 +335,5 @@ Customer → Store Portal Customer → Own Account
Cookie Isolation:
admin_token (path=/admin) ← Only sent to /admin/*
store_token (path=/store) ← Only sent to /store/*
customer_token (path=/shop) ← Only sent to /shop/*
customer_token (path=/storefront) ← Only sent to /storefront/*
```

View File

@@ -86,7 +86,7 @@ The application operates in three isolated contexts:
|---------|--------|----------------|------------|
| **Admin** | `/admin/*` | `admin_token` cookie | `super_admin`, `platform_admin` |
| **Store** | `/store/*` | `store_token` cookie | `merchant_owner`, `store_member` |
| **Shop** | `/shop/account/*` | `customer_token` cookie | Customers |
| **Storefront** | `/storefront/account/*` | `customer_token` cookie | Customers |
**Important:** These contexts are security boundaries. Admin users cannot access store routes, store users cannot access admin routes, and customers are entirely separate.
@@ -802,7 +802,7 @@ role = Role(
┌─────────────┐
│ Client │
│ │
│ 🍪 customer_token (path=/shop) │
│ 🍪 customer_token (path=/storefront) │
│ 💾 localStorage.token │
└─────────────┘
```
@@ -838,7 +838,7 @@ response.set_cookie(
response.set_cookie(
key="customer_token",
value=jwt_token,
path="/shop", # Only sent to /shop/* routes
path="/storefront", # Only sent to /storefront/* routes
httponly=True,
secure=True,
samesite="lax"

View File

@@ -92,7 +92,7 @@ Get paginated list of products for current store.
```http
GET /api/v1/storefront/products?skip=0&limit=20&is_featured=true
Referer: http://localhost:8000/stores/orion/shop/products
Referer: http://localhost:8000/storefront/orion/products
```
**Response (200 OK):**
@@ -142,7 +142,7 @@ Get detailed information for a specific product.
```http
GET /api/v1/storefront/products/1
Referer: http://localhost:8000/stores/orion/shop/products
Referer: http://localhost:8000/storefront/orion/products
```
**Response (200 OK):**
@@ -200,7 +200,7 @@ Retrieve cart contents for a session.
```http
GET /api/v1/storefront/cart/session-abc-123
Referer: http://localhost:8000/stores/orion/shop/cart
Referer: http://localhost:8000/storefront/orion/cart
```
**Response (200 OK):**