Initial commit
This commit is contained in:
@@ -0,0 +1,391 @@
|
||||
# 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.
|
||||
Reference in New Issue
Block a user