# API Architecture Consolidation Proposal

**Date:** 2025-11-22
**Status:** DRAFT - Awaiting Review
**Priority:** HIGH

## Executive Summary

The platform currently has **two parallel API structures** for shop/customer-facing endpoints:
1. **Original:** `/api/v1/public/vendors/{vendor_id}/*`
2. **New:** `/api/v1/shop/*`

This divergence creates confusion, maintenance overhead, and potential bugs. This document analyzes the situation and proposes a consolidation strategy.

---

## Current State Analysis

### 1. Original Architecture (`/api/v1/public/vendors/`)

**Location:** `app/api/v1/public/vendors/`

**Endpoints:**
```
GET  /api/v1/public/vendors                     → List active vendors
GET  /api/v1/public/vendors/{vendor_id}/products → Product catalog
GET  /api/v1/public/vendors/{vendor_id}/products/{product_id} → Product detail
POST /api/v1/public/vendors/{vendor_id}/cart     → Cart operations
GET  /api/v1/public/vendors/{vendor_id}/orders   → Customer orders
POST /api/v1/public/vendors/auth/login           → Customer authentication
POST /api/v1/public/vendors/auth/register        → Customer registration
```

**Characteristics:**
- ✅ **Vendor-scoped:** Requires explicit `vendor_id` in path
- ✅ **RESTful:** Clear resource hierarchy
- ✅ **Authentication:** Supports customer auth via `/auth/*` endpoints
- ✅ **Existing:** Already implemented with services and models
- ❌ **Verbose:** Requires vendor_id in every call

**Current Usage:**
- Product catalog: `products.py`
- Shopping cart: `cart.py`
- Orders: `orders.py`
- Customer auth: `auth.py`
- Vendor listing: `vendors.py`

---

### 2. New Architecture (`/api/v1/shop/`)

**Location:** `app/api/v1/shop/`

**Endpoints:**
```
GET /api/v1/shop/content-pages/navigation        → CMS navigation pages
GET /api/v1/shop/content-pages/{slug}            → CMS page content
```

**Characteristics:**
- ✅ **Vendor-agnostic URLs:** Clean paths without vendor_id
- ✅ **Middleware-driven:** Relies on `VendorContextMiddleware` to inject vendor
- ✅ **Simpler URLs:** `/api/v1/shop/products` vs `/api/v1/public/vendors/123/products`
- ❌ **Incomplete:** Only CMS endpoints implemented
- ❌ **Divergent:** Not consistent with existing public API

**Current Usage:**
- CMS content pages only
- Called from shop templates (e.g., `shop/products.html`, `shop/home.html`)

---

## The Problem

### Inconsistency

```javascript
// ❌ INCONSISTENT - Two different patterns for same context
// CMS pages use new pattern
fetch('/api/v1/shop/content-pages/about')

// Products use old pattern
fetch('/api/v1/public/vendors/123/products')
```

### Confusion

Developers must remember:
- "Is this endpoint under `/shop` or `/public/vendors`?"
- "Do I need to pass vendor_id or is it from middleware?"
- "Which authentication endpoints do I use?"

### Maintenance Overhead

- Two sets of documentation
- Two architectural patterns
- Duplicate functionality risk
- Testing complexity

### Broken Features

**Current Issue:** CMS pages not loading at `/vendors/wizamart/about`

**Root Cause:**
- CMS API exists at `/api/v1/shop/content-pages/{slug}`
- No corresponding HTML route handler in `vendor_pages.py`
- JavaScript might be calling wrong endpoint

---

## Options Analysis

### Option 1: Move Everything to `/api/v1/shop/*` (Middleware-Driven)

**Approach:** Consolidate all customer-facing endpoints under `/api/v1/shop/*`

**Proposed Structure:**
```
/api/v1/shop/
  ├── auth/
  │   ├── POST /login             → Customer login
  │   ├── POST /register          → Customer registration
  │   └── POST /logout            → Customer logout
  ├── products/
  │   ├── GET  /                  → Product catalog
  │   ├── GET  /{product_id}      → Product detail
  │   └── GET  /featured          → Featured products
  ├── cart/
  │   ├── GET  /                  → View cart
  │   ├── POST /items             → Add to cart
  │   └── PUT  /items/{item_id}   → Update quantity
  ├── orders/
  │   ├── GET  /                  → Order history
  │   ├── GET  /{order_id}        → Order detail
  │   └── POST /                  → Create order
  ├── content-pages/             → [EXISTING]
  │   ├── GET  /navigation        → Navigation pages
  │   └── GET  /{slug}            → Page content
  └── vendors/
      └── GET  /                  → List vendors (marketplace)
```

**Implementation:**
- Vendor extracted by `VendorContextMiddleware` from request
- All endpoints use `request.state.vendor` instead of path parameter
- URLs are cleaner: `/api/v1/shop/products` instead of `/api/v1/public/vendors/123/products`

**Pros:**
- ✅ Clean, consistent API structure
- ✅ Simpler URLs for frontend
- ✅ Vendor is contextual (from domain/subdomain/path)
- ✅ Aligns with multi-tenant architecture
- ✅ Easier to document and understand

**Cons:**
- ❌ **Breaking change** for existing clients
- ❌ Requires moving ~8-10 endpoint files
- ❌ Need to update all frontend code
- ❌ Testing effort to verify all endpoints work

**Migration Effort:** HIGH (2-3 days)

---

### Option 2: Keep `/api/v1/public/vendors/*` and Deprecate `/api/v1/shop/*`

**Approach:** Move CMS endpoints to `/api/v1/public/vendors/{vendor_id}/content-pages/*`

**Proposed Changes:**
```
# Move CMS endpoints
FROM: /api/v1/shop/content-pages/navigation
TO:   /api/v1/public/vendors/{vendor_id}/content-pages/navigation

FROM: /api/v1/shop/content-pages/{slug}
TO:   /api/v1/public/vendors/{vendor_id}/content-pages/{slug}
```

**Pros:**
- ✅ Maintains existing architecture
- ✅ No breaking changes to existing endpoints
- ✅ RESTful vendor-scoped URLs
- ✅ Minimal code changes

**Cons:**
- ❌ Verbose URLs with vendor_id everywhere
- ❌ Doesn't leverage middleware architecture
- ❌ Less elegant than Option 1
- ❌ Frontend must always know vendor_id

**Migration Effort:** LOW (1 day)

---

### Option 3: Hybrid Approach with Alias Routes

**Approach:** Support both patterns during transition period

**Implementation:**
```python
# Primary (new pattern)
@router.get("/products")
async def get_products_new(request: Request, db: Session = Depends(get_db)):
    vendor = request.state.vendor
    # ...

# Alias (old pattern for backwards compatibility)
@router.get("/vendors/{vendor_id}/products")
async def get_products_legacy(vendor_id: int, db: Session = Depends(get_db)):
    # Redirect or proxy to new pattern
    # ...
```

**Pros:**
- ✅ No breaking changes
- ✅ Gradual migration path
- ✅ Both patterns work simultaneously

**Cons:**
- ❌ Maintains complexity
- ❌ Doubles maintenance burden
- ❌ Confusing for developers
- ❌ Technical debt accumulates

**Migration Effort:** MEDIUM (1-2 days + ongoing maintenance)

---

## Recommendation

### **OPTION 1: Consolidate to `/api/v1/shop/*` (Middleware-Driven)**

**Rationale:**

1. **Architectural Alignment**: Platform uses middleware for vendor context injection. APIs should leverage this instead of requiring explicit vendor_id.

2. **User Experience**: Cleaner URLs are easier for frontend developers:
   ```javascript
   // ✅ GOOD
   fetch('/api/v1/shop/products')

   // ❌ BAD
   fetch('/api/v1/public/vendors/123/products')
   ```

3. **Multi-Tenant Best Practice**: Vendor context should be implicit (from domain/path), not explicit in every API call.

4. **Consistency**: All shop endpoints follow same pattern - no mixing `/shop` and `/public/vendors`.

5. **Future-Proof**: Easier to add new shop features without worrying about vendor_id paths.

---

## Migration Plan

### Phase 1: Create New Endpoints (Week 1)

**Day 1-2: Move Products**
```bash
# Copy and adapt
app/api/v1/public/vendors/products.py  →  app/api/v1/shop/products.py

# Changes:
- Remove vendor_id path parameter
- Use request.state.vendor instead
- Update route paths
```

**Day 3: Move Cart**
```bash
app/api/v1/public/vendors/cart.py  →  app/api/v1/shop/cart.py
```

**Day 4: Move Orders**
```bash
app/api/v1/public/vendors/orders.py  →  app/api/v1/shop/orders.py
```

**Day 5: Move Auth**
```bash
app/api/v1/public/vendors/auth.py  →  app/api/v1/shop/auth.py
```

### Phase 2: Update Frontend (Week 1)

**Templates:**
- Update all `fetch()` calls in shop templates
- Change from `/api/v1/public/vendors/${vendorId}/...` to `/api/v1/shop/...`

**JavaScript:**
- Update any shop-related API client code
- Remove hardcoded vendor_id references

### Phase 3: Testing (Week 2, Day 1-2)

- ✅ Test all shop pages load correctly
- ✅ Test product catalog
- ✅ Test cart operations
- ✅ Test order placement
- ✅ Test customer authentication
- ✅ Test CMS pages

### Phase 4: Deprecation Notice (Week 2, Day 3)

- Add deprecation warnings to old endpoints
- Update documentation
- Add logging to track old endpoint usage

### Phase 5: Removal (Week 3+)

- Monitor old endpoint usage
- After no usage for 2 weeks, remove old endpoints
- Clean up code

---

## Code Examples

### Before (Current - `/api/v1/public/vendors`)

```python
# app/api/v1/public/vendors/products.py
@router.get("/{vendor_id}/products")
def get_public_product_catalog(
    vendor_id: int = Path(...),
    db: Session = Depends(get_db),
):
    vendor = db.query(Vendor).filter(Vendor.id == vendor_id).first()
    # ...
```

```javascript
// Frontend
const vendorId = 123;
fetch(`/api/v1/public/vendors/${vendorId}/products`)
```

### After (Proposed - `/api/v1/shop`)

```python
# app/api/v1/shop/products.py
@router.get("/products")
def get_product_catalog(
    request: Request,
    db: Session = Depends(get_db),
):
    vendor = request.state.vendor  # Injected by middleware
    # ...
```

```javascript
// Frontend
fetch('/api/v1/shop/products')  // Vendor context automatic
```

---

## Impact Assessment

### Breaking Changes
- All frontend code calling `/api/v1/public/vendors/*` must update
- Mobile apps (if any) must update
- Third-party integrations (if any) must update

### Non-Breaking
- Admin APIs: `/api/v1/admin/*` → No changes
- Vendor APIs: `/api/v1/vendor/*` → No changes
- Vendor listing: Keep `/api/v1/public/vendors` (list all vendors for marketplace)

### Risk Mitigation
1. **Deprecation Period**: Keep old endpoints for 2-4 weeks
2. **Logging**: Track usage of old endpoints
3. **Documentation**: Clear migration guide for developers
4. **Testing**: Comprehensive E2E tests before deployment

---

## Alternative: Quick Fix for Current Issue

If full migration is not approved immediately, we can do a **minimal fix** for the CMS issue:

### Quick Fix: Just Move CMS to Public API

```python
# Move: app/api/v1/shop/content_pages.py
# To:   app/api/v1/public/vendors/content_pages.py

# Update routes:
@router.get("/{vendor_id}/content-pages/navigation")
@router.get("/{vendor_id}/content-pages/{slug}")
```

**Effort:** 1-2 hours
**Impact:** Fixes immediate CMS issue
**Debt:** Maintains architectural divergence

---

## Decision Required

**Question for Team:**

Should we:
1. ✅ **Consolidate to `/api/v1/shop/*`** (Recommended)
2. ❌ **Keep `/api/v1/public/vendors/*`** and move CMS there
3. ❌ **Hybrid approach** with both patterns
4. ❌ **Quick fix only** - move CMS, address later

**Timeline:** Please decide by [DATE] so we can plan sprint accordingly.

---

## Appendix: Current Endpoint Inventory

### `/api/v1/public/vendors/*`
- ✅ `vendors.py` - Vendor listing
- ✅ `auth.py` - Customer authentication
- ✅ `products.py` - Product catalog
- ✅ `cart.py` - Shopping cart
- ✅ `orders.py` - Order management
- 🚧 `payments.py` - Stub
- 🚧 `search.py` - Stub
- 🚧 `shop.py` - Stub

### `/api/v1/shop/*`
- ✅ `content_pages.py` - CMS pages

### To Be Created (if Option 1 chosen)
- 📝 `shop/products.py`
- 📝 `shop/cart.py`
- 📝 `shop/orders.py`
- 📝 `shop/auth.py`
- 📝 `shop/vendors.py` (marketplace listing)

---

## References

- [Authentication Dependencies Guide](../development/auth-dependencies-guide.md)
- [Multi-Tenant Architecture](./multi-tenant.md)
- [Middleware Stack Documentation](./middleware.md)
- [URL Routing Overview](./url-routing/overview.md)
