# Connecting to Backend

## Contents

- [Overview](#overview)
- [Detecting the Backend](#detecting-the-backend-critical)
- [Framework Detection](#framework-detection)
- [Environment Configuration](#environment-configuration)
- [Backend-Specific Integration](#backend-specific-integration)
- [Authentication Patterns](#authentication-patterns)
- [Cart State Management](#cart-state-management)
- [Error Handling for Ecommerce](#error-handling-for-ecommerce)
- [Performance Patterns](#performance-patterns)
  - [Data Fetching with TanStack Query](#data-fetching-with-tanstack-query-recommended)
- [Checklist](#checklist)

## Overview

Best practices for connecting storefront to ecommerce backend APIs. Framework-agnostic patterns for authentication, cart state management, error handling, and performance optimization.

**For Medusa-specific integration**, see `reference/medusa.md` for SDK setup, pricing, regions, and Medusa patterns.

## Detecting the Backend (CRITICAL)

**Before implementing any backend integration, identify which ecommerce backend is being used.**

### Detection Strategy

**1. Check for monorepo structure:**
```bash
# Look for backend directory
ls -la ../backend
ls -la ./backend
ls -la ../../apps/backend
```

Common monorepo patterns:
- `/apps/storefront` + `/apps/backend`
- `/frontend` + `/backend`
- `/packages/web` + `/packages/api`

**2. Check package.json dependencies:**
```json
{
  "dependencies": {
    "@medusajs/js-sdk": "...",  // Medusa
    // check other ecommerce frameworks...
  }
}
```

**3. Check environment variables:**
```bash
# Look in .env, .env.local, .env.example
grep -i "api\|backend\|medusa\|shopify\|commerce" .env*
```

Common patterns:
- `NEXT_PUBLIC_MEDUSA_BACKEND_URL` → Medusa
- Custom `API_URL` or `BACKEND_URL` → Other backend

**4. If unsure, ASK THE USER:**

```markdown
I need to connect to the ecommerce backend. Which backend are you using?

Options:
- Medusa (open-source headless commerce)
- Custom backend
- Other
```

### Backend Documentation and MCP Servers

**ALWAYS refer to the backend's official documentation or MCP server for:**

- API endpoints and data structures
- Authentication requirements
- SDK usage and installation
- Environment configuration
- Rate limits and best practices

**For Medusa:**
- Documentation: https://docs.medusajs.com
- MCP Server: If available, use Medusa MCP server for real-time API information
- JS SDK docs: https://docs.medusajs.com/resources/js-sdk
- See `reference/medusa.md` for detailed integration guide

**For other backends:**
- Check the backend's documentation portal
- Look for MCP server if available
- Verify API endpoints and authentication methods
- Never assume API structure without verification

**Important:** Do not guess API endpoints or data formats. Always verify with documentation or ask the user to confirm the backend's API structure.

## Framework Detection

Identify the frontend framework to determine appropriate data fetching patterns:

**Next.js:**
- App Router: Server Components (async/await), Client Components (useEffect/TanStack Query)
- Pages Router: getServerSideProps/getStaticProps (server), useEffect (client)

**SvelteKit:**
- Load functions for server-side data
- Client-side: fetch in component lifecycle

**TanStack Start:**
- Server functions for server-side data
- Client-side: fetch with React hooks

**General Rule:**
- **Server-side for initial load**: SEO, performance, security (product pages, listings)
- **Client-side for interactions**: Cart, filters, search, user-specific data

## Environment Configuration

**Store API URLs and keys in environment variables:**

```typescript
// .env.local
NEXT_PUBLIC_API_URL=https://api.example.com
NEXT_PUBLIC_PUBLISHABLE_KEY=pk_...
```

**Framework-specific prefixes:**
- Next.js: `NEXT_PUBLIC_` for client-side
- SvelteKit: `PUBLIC_` for client-side
- Vite-based (TanStack Start): `VITE_` for client-side

**Security:**
- ❌ NEVER expose secret/admin keys in client-side code
- ✅ Publishable keys are safe for client (Medusa, Stripe)
- ✅ Secret keys only in server-side code or environment

## Backend-Specific Integration

### Medusa Backend

**For complete Medusa integration guide**, see `reference/medusa.md` which covers:
- SDK installation and setup
- Vite configuration (for TanStack Start, etc.)
- TypeScript types from `@medusajs/types`
- Price display (never divide by 100)
- Common operations (products, cart, categories, customers)
- Custom endpoints
- Region state management
- Error handling with SDK

### Other Backends

For non-Medusa backends (custom APIs, third-party platforms):

**1. Consult backend's API documentation** for:
   - Authentication requirements
   - Available endpoints
   - Request/response formats
   - SDK availability (check if official SDK exists)

**2. Use backend's official SDK if available** - provides type safety, error handling, and best practices

**3. If no SDK, create API client wrapper:**
   - Centralize API calls in one module
   - Group by resource (products, cart, customers, orders)
   - Handle authentication (include tokens/cookies)
   - Handle errors consistently
   - Use native fetch or axios

## Authentication Patterns

### Customer Authentication

**Session-based (cookies):**
- Backend manages session via cookies
- No manual token management needed
- Works across page refreshes
- Common in traditional ecommerce backends
- Call backend login endpoint, check auth state, logout methods

**Token-based (JWT, OAuth):**
- Store token in localStorage or secure cookie after login
- Include token in Authorization header for all authenticated requests
- Common in headless/API-first backends
- Format: `Authorization: Bearer {token}`

### Protecting Customer Routes

**Check authentication before rendering customer-specific pages** (account, orders, addresses):

- **Server-side**: Check auth in server functions (getServerSideProps, load functions, etc.). Redirect to login if not authenticated.
- **Client-side**: Check auth state on mount. Redirect to login if not authenticated.

Use framework-specific auth patterns for redirects.

### Cart Access Pattern

**Guest carts:**
- Store cart ID in localStorage or cookie
- Check for existing cart ID on app load
- Create new cart if none exists
- Allows shopping without account
- Persists across sessions

**Logged-in carts:**
- Associate cart with customer account
- Syncs across devices
- **CRITICAL: Merge guest cart with customer cart on login** - Transfer guest cart items to customer's account cart, then clear guest cart ID from localStorage

## Cart State Management

**Critical ecommerce pattern**: Cart must be accessible throughout the app.

### Global Cart State

**React Context (for simple cases):**
- Create CartContext and CartProvider
- Store cart state and cartId (from localStorage)
- Load cart on mount if cartId exists
- Provide methods: addItem, removeItem, updateQuantity, clearCart
- Update cart state after each operation

**State management libraries (Zustand, Redux):**
- Use for complex state requirements
- Better for large applications
- Easier to debug with DevTools
- Same pattern: Store cart, provide actions, sync with backend

**Key requirements:**
- Cart accessible from any component
- Real-time cart count updates
- Optimistic UI updates (update UI immediately, sync with backend)

### Cart Cleanup After Order Placement (CRITICAL)

**IMPORTANT: After order is successfully placed, you MUST reset the cart state.**

**Common issue:** Cart popup and global cart state still show old items after order completion. This happens when cart state isn't cleared after checkout.

**Required cleanup actions:**

1. **Clear cart from global state** - Reset cart state to null/empty in Context/Zustand/Redux
2. **Clear localStorage cart ID** - Remove cart ID: `localStorage.removeItem('cart_id')`
3. **Invalidate cart queries** - If using TanStack Query: `queryClient.invalidateQueries({ queryKey: ['cart'] })`
4. **Update cart count to 0** - Navbar and UI should reflect empty cart

**When to clear:**
- After successful order placement (order confirmed)
- On navigation to order confirmation page
- Before redirecting to thank you page

**Why this is critical:**
- Prevents "phantom cart" from appearing in cart popup after order
- Ensures clean state for next shopping session
- Improves UX by not showing old cart items

## Error Handling for Ecommerce

### Ecommerce-Specific Errors

**Out of stock:**
- Catch errors when adding to cart
- Check for "out of stock" or "inventory" in error message
- Show user-friendly message: "Sorry, this item is now out of stock"
- Update product availability UI to show out of stock

**Price changed during checkout:**
- Compare cart total with expected total
- If different, show warning: "Prices have been updated. Please review your cart."
- Highlight changed prices in cart

**Payment failed:**
- Catch errors during order completion
- Check for specific payment errors: payment_declined, insufficient_funds, etc.
- Show specific messages:
  - Payment declined → "Payment declined. Please try a different payment method."
  - Insufficient funds → "Insufficient funds. Please use a different card."
  - Generic → "Payment failed. Please try again or contact support."

**Session expired:**
- Catch 401/Unauthorized errors
- Clear auth state
- Redirect to login with message: "Your session has expired. Please log in again."

### User-Friendly Error Messages

**Transform technical errors to clear messages:**
- Network/fetch errors → "Unable to connect. Please check your internet connection."
- Timeout errors → "Request timed out. Please try again."
- Inventory errors → "This item is no longer available in the requested quantity."
- Generic fallback → "Something went wrong. Please try again or contact support."

**Pattern**: Check error message or status code, map to user-friendly message, show in UI (toast, banner, inline).

## Performance Patterns

### Data Fetching with TanStack Query (RECOMMENDED)

**Use TanStack Query for all backend API calls** - provides automatic caching, request deduplication, loading/error states, and optimistic updates.

**Installation:** `npm install @tanstack/react-query`

**Setup:**
- Create QueryClient with default options (staleTime: 5 min, retry: 1)
- Wrap app with QueryClientProvider

**Query pattern (for fetching data):**
- Use `useQuery` with queryKey and queryFn
- queryKey: Array with resource and identifier `['products', categoryId]`
- queryFn: API call function
- Returns: `data`, `isLoading`, `error`
- Use for: Products, cart, customer data, categories

**Mutation pattern (for modifying data):**
- Use `useMutation` with mutationFn
- mutationFn: API operation (add to cart, update, delete)
- onSuccess: Update cache or invalidate queries
- Returns: `mutate` function, `isPending` state
- Use for: Add to cart, remove from cart, update quantities, place order

**Benefits:**
- Automatic caching (no manual cache management)
- Built-in loading/error states
- Request deduplication
- Optimistic updates (update UI before server responds)
- Cache invalidation strategies

**Ecommerce-specific usage:**
- Products: Long stale time (5-10 min) - products don't change often
- Cart: Short or no stale time - prices/inventory can change
- Categories: Long stale time - rarely change

### Caching Strategy

**Client-side caching:**
- TanStack Query handles automatically with `staleTime` and `cacheTime`
- Configure globally or per-query
- Product data: 5-10 min stale time
- Cart data: Fresh on every fetch
- Categories: Long stale time

**Server-side caching (framework-specific):**
- Next.js: Use `revalidate` export or cache configuration
- Set revalidation period (e.g., 300 seconds for product pages)
- Static generation with ISR for product pages

### Request Deduplication

TanStack Query and modern frameworks handle this automatically - multiple components requesting same data result in single request.

### Pagination Pattern

**Offset-based:** Pass limit and offset parameters to API `limit: 24, offset: page * 24`

**Cursor-based (better performance):** Pass limit and cursor (last item ID) `limit: 24, cursor: lastProductId`

Check backend documentation for supported pagination type.

## Checklist

**Essential backend integration:**

- [ ] Backend detected (Medusa, Shopify, custom, etc.)
- [ ] Environment variables configured (API URL, keys)
- [ ] Framework-specific data fetching patterns identified
- [ ] **RECOMMENDED: TanStack Query installed and configured for API calls**
- [ ] Server-side fetching for product pages (SEO)
- [ ] Client-side fetching for cart and user interactions (use TanStack Query)
- [ ] Authentication flow implemented (login/logout)
- [ ] Cart ID persisted in localStorage or cookies
- [ ] Global cart state management (context or store)
- [ ] Cart count synced across app
- [ ] Optimistic UI updates for cart operations
- [ ] Error handling for out of stock scenarios
- [ ] Error handling for payment failures
- [ ] Session expiration handling (redirect to login)
- [ ] User-friendly error messages (not technical)
- [ ] Caching strategy for product data
- [ ] Stock availability checks before checkout
- [ ] Price change detection and warnings

**For Medusa backends, also check:**
- [ ] Medusa SDK installed (`@medusajs/js-sdk` + `@medusajs/types`)
- [ ] SDK initialized with baseUrl and publishableKey
- [ ] Vite SSR config added (if using TanStack Start/Vite)
- [ ] Using official types from `@medusajs/types`
- [ ] Not dividing prices by 100 (display as-is)
- [ ] Region context implemented for multi-region stores
- [ ] Region passed to cart and product queries

See `reference/medusa.md` for complete Medusa integration guide.
