Files
the-pet-loft/CLAUDE.md
ianshaloom cc15338ad9 feat: initial commit — storefront, convex backend, and shared packages
Completes the first milestone of The Pet Loft ecommerce platform:
- apps/storefront: full customer-facing Next.js app with HeroUI (cart,
  checkout, orders, wishlist, product detail, shop, search, auth)
- convex/: serverless backend with schema, queries, mutations, actions,
  HTTP routes, Stripe/Shippo integrations, and co-located tests
- packages/types, packages/utils, packages/convex: shared workspace packages

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-04 09:31:18 +03:00

154 lines
5.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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 (h1h3): 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`.