refactor: rename shop to storefront throughout codebase

Rename "shop" to "storefront" as not all platforms sell items -
storefront is a more accurate term for the customer-facing interface.

Changes:
- Rename app/api/v1/shop/ → app/api/v1/storefront/
- Rename app/routes/shop_pages.py → app/routes/storefront_pages.py
- Rename app/modules/cms/routes/api/shop.py → storefront.py
- Rename tests/integration/api/v1/shop/ → storefront/
- Update API prefix from /api/v1/shop to /api/v1/storefront
- Update route tags from shop-* to storefront-*
- Rename get_shop_context() → get_storefront_context()
- Update architecture rules to reference storefront paths
- Update all test API endpoint paths

This is Phase 2 of the storefront module restructure plan.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-01-29 22:42:01 +01:00
parent 228163d920
commit 3e86d4b58b
20 changed files with 140 additions and 134 deletions

View File

@@ -4,13 +4,13 @@ API router configuration for multi-tenant ecommerce platform.
This module provides:
- API version 1 route aggregation
- Route organization by user type (admin, vendor, shop)
- Route organization by user type (admin, vendor, storefront)
- Proper route prefixing and tagging
"""
from fastapi import APIRouter
from app.api.v1 import admin, platform, shop, vendor
from app.api.v1 import admin, platform, storefront, vendor
from app.api.v1.shared import language, webhooks
api_router = APIRouter()
@@ -30,11 +30,12 @@ api_router.include_router(admin.router, prefix="/v1/admin", tags=["admin"])
api_router.include_router(vendor.router, prefix="/v1/vendor", tags=["vendor"])
# ============================================================================
# SHOP ROUTES (Public shop frontend API)
# Prefix: /api/v1/shop
# STOREFRONT ROUTES (Public customer-facing API)
# Prefix: /api/v1/storefront
# Note: Previously /api/v1/shop, renamed as not all platforms sell items
# ============================================================================
api_router.include_router(shop.router, prefix="/v1/shop", tags=["shop"])
api_router.include_router(storefront.router, prefix="/v1/storefront", tags=["storefront"])
# ============================================================================
# PLATFORM ROUTES (Public marketing and signup)

View File

@@ -1,8 +1,8 @@
# app/api/v1/shop/__init__.py
# app/api/v1/storefront/__init__.py
"""
Shop API router aggregation.
Storefront API router aggregation.
This module aggregates all shop-related JSON API endpoints (public facing).
This module aggregates all storefront-related JSON API endpoints (public facing).
Uses vendor context from middleware - no vendor_id in URLs.
Endpoints:
@@ -16,48 +16,50 @@ Authentication:
- Products, Cart, Content Pages: No auth required
- Orders: Requires customer authentication (get_current_customer_api)
- Auth: Public (login, register)
Note: Previously named "shop", renamed to "storefront" as not all platforms
sell items - storefront is a more accurate term for the customer-facing interface.
"""
from fastapi import APIRouter
# Import shop routers
# Import storefront routers
from . import addresses, auth, carts, messages, orders, products, profile
# CMS module router
from app.modules.cms.routes.api.shop import router as cms_shop_router
from app.modules.cms.routes.api.storefront import router as cms_storefront_router
# Create shop router
# Create storefront router
router = APIRouter()
# ============================================================================
# SHOP API ROUTES (All vendor-context aware via middleware)
# STOREFRONT API ROUTES (All vendor-context aware via middleware)
# ============================================================================
# Addresses (authenticated)
router.include_router(addresses.router, tags=["shop-addresses"])
router.include_router(addresses.router, tags=["storefront-addresses"])
# Authentication (public)
router.include_router(auth.router, tags=["shop-auth"])
router.include_router(auth.router, tags=["storefront-auth"])
# Products (public)
router.include_router(products.router, tags=["shop-products"])
router.include_router(products.router, tags=["storefront-products"])
# Shopping cart (public - session based)
router.include_router(carts.router, tags=["shop-cart"])
router.include_router(carts.router, tags=["storefront-cart"])
# Orders (authenticated)
router.include_router(orders.router, tags=["shop-orders"])
router.include_router(orders.router, tags=["storefront-orders"])
# Messages (authenticated)
router.include_router(messages.router, tags=["shop-messages"])
router.include_router(messages.router, tags=["storefront-messages"])
# Profile (authenticated)
router.include_router(profile.router, tags=["shop-profile"])
router.include_router(profile.router, tags=["storefront-profile"])
# CMS module router (self-contained module)
router.include_router(
cms_shop_router, prefix="/content-pages", tags=["shop-content-pages"]
cms_storefront_router, prefix="/content-pages", tags=["storefront-content-pages"]
)
# Legacy: content_pages.router moved to app.modules.cms.routes.api.shop
__all__ = ["router"]

View File

@@ -5,11 +5,11 @@ CMS module API routes.
Provides REST API endpoints for content page management:
- Admin API: Full CRUD for platform administrators
- Vendor API: Vendor-scoped CRUD with ownership checks
- Shop API: Public read-only access for storefronts
- Storefront API: Public read-only access for storefronts
"""
from app.modules.cms.routes.api.admin import router as admin_router
from app.modules.cms.routes.api.vendor import router as vendor_router
from app.modules.cms.routes.api.shop import router as shop_router
from app.modules.cms.routes.api.storefront import router as storefront_router
__all__ = ["admin_router", "vendor_router", "shop_router"]
__all__ = ["admin_router", "vendor_router", "storefront_router"]

View File

@@ -1,8 +1,8 @@
# app/modules/cms/routes/api/shop.py
# app/modules/cms/routes/api/storefront.py
"""
Shop Content Pages API (Public)
Storefront Content Pages API (Public)
Public endpoints for retrieving content pages in shop frontend.
Public endpoints for retrieving content pages in storefront.
No authentication required.
"""

View File

@@ -127,14 +127,14 @@ async def homepage(
if landing_page:
# Render landing page with selected template
from app.routes.shop_pages import get_shop_context
from app.routes.storefront_pages import get_storefront_context
template_name = landing_page.template or "default"
template_path = f"vendor/landing-{template_name}.html"
logger.info(f"[HOMEPAGE] Rendering vendor landing page: {template_path}")
return templates.TemplateResponse(
template_path, get_shop_context(request, db=db, page=landing_page)
template_path, get_storefront_context(request, db=db, page=landing_page)
)
# No landing page - redirect to shop

View File

@@ -1,19 +1,22 @@
# app/routes/shop_pages.py
# app/routes/storefront_pages.py
"""
Shop/Customer HTML page routes using Jinja2 templates.
Storefront/Customer HTML page routes using Jinja2 templates.
These routes serve the public-facing shop interface for customers.
These routes serve the public-facing storefront interface for customers.
Authentication required only for account pages.
Note: Previously named "shop_pages.py", renamed to "storefront" as not all
platforms sell items - storefront is a more accurate term.
AUTHENTICATION:
- Public pages (catalog, products): No auth required
- Account pages (dashboard, orders): Requires customer authentication
- Customer authentication accepts:
* customer_token cookie (path=/shop) - for page navigation
* customer_token cookie (path=/storefront) - for page navigation
* Authorization header - for API calls
- Customers CANNOT access admin or vendor routes
Routes (all mounted at /shop/* or /vendors/{code}/shop/* prefix):
Routes (all mounted at /storefront/* or /vendors/{code}/storefront/* prefix):
- GET / Shop homepage / product catalog
- GET /products Product catalog
- GET /products/{id} Product detail page
@@ -86,7 +89,7 @@ def get_resolved_storefront_config(db: Session, vendor) -> dict:
# ============================================================================
def get_shop_context(request: Request, db: Session = None, **extra_context) -> dict:
def get_storefront_context(request: Request, db: Session = None, **extra_context) -> dict:
"""
Build template context for shop pages.
@@ -103,13 +106,13 @@ def get_shop_context(request: Request, db: Session = None, **extra_context) -> d
Example:
# Simple usage
get_shop_context(request)
get_storefront_context(request)
# With database session for navigation
get_shop_context(request, db=db)
get_storefront_context(request, db=db)
# With extra data
get_shop_context(request, db=db, user=current_user, product_id=123)
get_storefront_context(request, db=db, user=current_user, product_id=123)
"""
# Extract from middleware state
vendor = getattr(request.state, "vendor", None)
@@ -235,7 +238,7 @@ async def shop_products_page(request: Request, db: Session = Depends(get_db)):
)
return templates.TemplateResponse(
"shop/products.html", get_shop_context(request, db=db)
"shop/products.html", get_storefront_context(request, db=db)
)
@@ -261,7 +264,7 @@ async def shop_product_detail_page(
)
return templates.TemplateResponse(
"shop/product.html", get_shop_context(request, db=db, product_id=product_id)
"shop/product.html", get_storefront_context(request, db=db, product_id=product_id)
)
@@ -287,7 +290,7 @@ async def shop_category_page(
)
return templates.TemplateResponse(
"shop/category.html", get_shop_context(request, db=db, category_slug=category_slug)
"shop/category.html", get_storefront_context(request, db=db, category_slug=category_slug)
)
@@ -306,7 +309,7 @@ async def shop_cart_page(request: Request, db: Session = Depends(get_db)):
},
)
return templates.TemplateResponse("shop/cart.html", get_shop_context(request, db=db))
return templates.TemplateResponse("shop/cart.html", get_storefront_context(request, db=db))
@router.get("/checkout", response_class=HTMLResponse, include_in_schema=False)
@@ -324,7 +327,7 @@ async def shop_checkout_page(request: Request, db: Session = Depends(get_db)):
},
)
return templates.TemplateResponse("shop/checkout.html", get_shop_context(request, db=db))
return templates.TemplateResponse("shop/checkout.html", get_storefront_context(request, db=db))
@router.get("/search", response_class=HTMLResponse, include_in_schema=False)
@@ -342,7 +345,7 @@ async def shop_search_page(request: Request, db: Session = Depends(get_db)):
},
)
return templates.TemplateResponse("shop/search.html", get_shop_context(request, db=db))
return templates.TemplateResponse("shop/search.html", get_storefront_context(request, db=db))
# ============================================================================
@@ -366,7 +369,7 @@ async def shop_register_page(request: Request, db: Session = Depends(get_db)):
)
return templates.TemplateResponse(
"shop/account/register.html", get_shop_context(request, db=db)
"shop/account/register.html", get_storefront_context(request, db=db)
)
@@ -386,7 +389,7 @@ async def shop_login_page(request: Request, db: Session = Depends(get_db)):
)
return templates.TemplateResponse(
"shop/account/login.html", get_shop_context(request, db=db)
"shop/account/login.html", get_storefront_context(request, db=db)
)
@@ -408,7 +411,7 @@ async def shop_forgot_password_page(request: Request, db: Session = Depends(get_
)
return templates.TemplateResponse(
"shop/account/forgot-password.html", get_shop_context(request, db=db)
"shop/account/forgot-password.html", get_storefront_context(request, db=db)
)
@@ -434,7 +437,7 @@ async def shop_reset_password_page(
)
return templates.TemplateResponse(
"shop/account/reset-password.html", get_shop_context(request, db=db)
"shop/account/reset-password.html", get_storefront_context(request, db=db)
)
@@ -500,7 +503,7 @@ async def shop_account_dashboard_page(
)
return templates.TemplateResponse(
"shop/account/dashboard.html", get_shop_context(request, user=current_customer)
"shop/account/dashboard.html", get_storefront_context(request, user=current_customer)
)
@@ -525,7 +528,7 @@ async def shop_orders_page(
)
return templates.TemplateResponse(
"shop/account/orders.html", get_shop_context(request, user=current_customer)
"shop/account/orders.html", get_storefront_context(request, user=current_customer)
)
@@ -554,7 +557,7 @@ async def shop_order_detail_page(
return templates.TemplateResponse(
"shop/account/order-detail.html",
get_shop_context(request, user=current_customer, order_id=order_id),
get_storefront_context(request, user=current_customer, order_id=order_id),
)
@@ -579,7 +582,7 @@ async def shop_profile_page(
)
return templates.TemplateResponse(
"shop/account/profile.html", get_shop_context(request, user=current_customer)
"shop/account/profile.html", get_storefront_context(request, user=current_customer)
)
@@ -604,7 +607,7 @@ async def shop_addresses_page(
)
return templates.TemplateResponse(
"shop/account/addresses.html", get_shop_context(request, user=current_customer)
"shop/account/addresses.html", get_storefront_context(request, user=current_customer)
)
@@ -629,7 +632,7 @@ async def shop_wishlist_page(
)
return templates.TemplateResponse(
"shop/account/wishlist.html", get_shop_context(request, user=current_customer)
"shop/account/wishlist.html", get_storefront_context(request, user=current_customer)
)
@@ -654,7 +657,7 @@ async def shop_settings_page(
)
return templates.TemplateResponse(
"shop/account/settings.html", get_shop_context(request, user=current_customer)
"shop/account/settings.html", get_storefront_context(request, user=current_customer)
)
@@ -679,7 +682,7 @@ async def shop_messages_page(
)
return templates.TemplateResponse(
"shop/account/messages.html", get_shop_context(request, db=db, user=current_customer)
"shop/account/messages.html", get_storefront_context(request, db=db, user=current_customer)
)
@@ -711,7 +714,7 @@ async def shop_message_detail_page(
return templates.TemplateResponse(
"shop/account/messages.html",
get_shop_context(
get_storefront_context(
request, db=db, user=current_customer, conversation_id=conversation_id
),
)
@@ -787,7 +790,7 @@ async def generic_content_page(
)
return templates.TemplateResponse(
"shop/content-page.html", get_shop_context(request, db=db, page=page)
"shop/content-page.html", get_storefront_context(request, db=db, page=page)
)