# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Project Overview

**The Pet Loft** — a full-stack ecommerce platform for pet supplies. Turborepo monorepo with two Next.js apps, a shared Convex backend, and shared packages.

## Development Commands

Two processes must run simultaneously for full-stack development:

```bash
# Terminal 1 — Convex backend (must run first)
npx convex dev

# Terminal 2 — Next.js apps
npm run dev              # Both apps in parallel
npm run dev:storefront   # Storefront only (port 3000)
npm run dev:admin        # Admin only (port 3001)
```

```bash
npm run type-check       # TypeScript check across all workspaces
npm run lint             # ESLint via Turbo
npm run test             # Vitest watch mode (edge-runtime)
npm run test:once        # Run all tests once
npm run test:coverage    # Coverage report
npm run build            # Build both apps
```

To run a single test file: `npx vitest run convex/carts.test.ts`

## Architecture

### Monorepo Layout

```
apps/storefront/    # Customer store — Next.js + HeroUI (port 3000)
apps/admin/         # Staff dashboard — Next.js + ShadCN (port 3001)
convex/             # Serverless backend: schema, functions, HTTP routes, tests
packages/types/     # Shared TypeScript interfaces (Product, Order, User…)
packages/utils/     # Shared helpers: formatPrice, slugify, formatDate
packages/convex/    # ConvexClientProvider (Clerk + Convex integration)
```

### Backend: Convex

All backend logic lives in `convex/`. The schema defines 11 tables:

- **users** — Clerk-synced; roles: `customer`, `admin`, `super_admin`
- **products** / **productImages** / **productVariants** — catalog with SKUs
- **categories** — hierarchical (parent + topCategory slugs)
- **carts** — guest (`sessionId`) or authenticated (`userId`), 30-day expiry
- **orders** / **orderItems** — price/address snapshots at order time
- **addresses** — shipping/billing with validation flag
- **reviews** / **wishlists** — community features

Business logic is extracted into `convex/model/*.ts` helpers and reused across public functions.

### Auth Flow

1. Clerk handles UI + JWT. `ConvexProviderWithClerk` (from `@repo/convex`) passes the JWT to Convex.
2. `convex/auth.config.ts` trusts the Clerk JWT issuer domain.
3. Convex functions access the user via `ctx.auth.getUserIdentity()`.
4. `convex/model/users.ts` exports `getCurrentUser`, `requireAdmin`, `requireOwnership`.
5. Clerk webhooks sync user changes to the `users` table via `convex/http.ts`.

### Guest Cart & Session

- A guest `sessionId` is generated on first load and stored in a cookie (`apps/storefront/src/lib/session/`).
- All cart/wishlist queries accept either `userId` (signed-in) or `sessionId` (guest).
- On sign-in, `SessionCartMerge` component triggers a merge mutation to fold the guest cart into the user's cart.

### Checkout Flow

1. Address validation — `convex/model/checkout.ts` + Convex address functions
2. Shipping rates — Shippo API via `convex/model/shippo.ts`
3. Payment intent — Stripe via `convex/stripeActions.ts`
4. Order creation — snapshots of items, addresses, and pricing captured in `convex/orders.ts`
5. Stripe webhook — handled in `convex/http.ts`, updates order payment status

## Convex Function Conventions

Always use the new function syntax with explicit validators:

```typescript
import { query, mutation } from "./_generated/server";
import { v } from "convex/values";

export const myFunction = query({
  args: { id: v.id("products") },
  handler: async (ctx, args) => { ... },
});
```

- Use `internalQuery` / `internalMutation` / `internalAction` for private functions.
- HTTP endpoints go in `convex/http.ts` using `httpAction`.
- Use `ctx.runQuery` / `ctx.runMutation` from actions; avoid chaining many calls (race conditions).
- Leverage index-based queries over full table scans.

## Storefront UI Rules

**HeroUI** is the component library for the storefront. Two mandatory overrides:

| Situation | Use |
|-----------|-----|
| Internal navigation | `next/link` `<Link>` (never `@heroui/react` `Link`) |
| Content images | `next/image` `<Image>` (never raw `<img>`) |

Preserve semantic HTML (`<main>`, `<header>`, `<footer>`, `<article>` per product card, `<ol>` for breadcrumbs) even when composing Hero UI components around them.

## PetPaws Branding (Storefront)

**Typography:**
- Headings (h1–h3): Fraunces serif — `font-[family-name:var(--font-fraunces)]`
- Body / UI: DM Sans — `font-sans` (default)

**Key colors:**
| Token | Hex | Usage |
|-------|-----|-------|
| Deep Teal | `#236f6b` | Header/footer bg, price text |
| Brand Teal | `#38a99f` | Primary buttons, links, focus rings |
| Sunny Amber | `#f4a13a` | High-priority CTAs ("Add to Cart") |
| Playful Coral | `#f2705a` | Discount badges, sale text, alerts |
| Forest Black | `#1a2e2d` | Body text (never pure `#000000`) |
| Ice White | `#f0f8f7` | Page background |

Prefer CSS variables or Tailwind arbitrary values over raw hex. Do not mix coral and amber in the same component.

## Shared Packages

```typescript
import type { Product, Order, User } from "@repo/types";
import { formatPrice, slugify, formatDate } from "@repo/utils";
import { ConvexClientProvider } from "@repo/convex";  // wraps app layouts
```

Both apps' `next.config.js` transpile `@repo/*` packages.

## Testing

Tests are co-located with source files (`convex/*.test.ts`). Vitest runs in edge-runtime using `convex-test`. Environment variables for tests are not required — `convex-test` mocks the Convex runtime.

## Environment Variables

Each app has its own `.env.local` (copy from `.env.example`). Required vars:
- `NEXT_PUBLIC_CONVEX_URL` — from Convex dashboard
- `NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY` / `CLERK_SECRET_KEY`
- `STRIPE_SECRET_KEY` / `NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY`
- `SHIPPO_API_KEY`

Convex backend env vars (set in Convex Dashboard): `CLERK_JWT_ISSUER_DOMAIN`, `STRIPE_SECRET_KEY`, `STRIPE_WEBHOOK_SECRET`, `SHIPPO_API_KEY`.
