docs: update CLAUDE.md with Italian rule, error workflow, and full data model

Added Italian communication requirement, error-first workflow (report then wait),
and missing Prisma models: ProductVariant, PasswordResetToken, Page/PageSection,
SiteSettings, AuditLog. Added app/coverage/ to .gitignore.
This commit is contained in:
2026-05-19 14:05:31 +02:00
parent ea5fca6561
commit 93cfe1ad5e
2 changed files with 139 additions and 0 deletions
+4
View File
@@ -6,11 +6,15 @@
# Node
app/node_modules/
node_modules/
test/node_modules
# Next.js build output
app/.next/
app/out/
# Test coverage report
app/coverage/
# Prisma generated client (rebuilt on npm install)
app/node_modules/.prisma/
+135
View File
@@ -0,0 +1,135 @@
# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## How to work with the user
Before implementing any new feature, **always discuss it first**: explain whether it makes sense professionally, how it is typically done in production e-commerce platforms, and propose alternatives if there is a better approach. Only proceed with implementation after the user confirms.
**Communicate in Italian.** The user speaks Italian — all responses, explanations, and questions must be in Italian.
**Error handling workflow:** When you find an error (in logs, code, or output), report what you found and stop. Do not propose or implement a fix until the user explicitly asks. Present: what the error is, where it occurs, and what likely caused it — then wait for instructions.
## Running the project
```bash
# Start everything (first run takes a few minutes to build)
docker compose up -d --build
# Check logs
docker compose logs -f app
# Stop
docker compose down
```
The app is available at http://localhost. Admin panel at http://localhost/admin.
Default credentials are in `.env` (`INITIAL_ADMIN_EMAIL` / `INITIAL_ADMIN_PASSWORD`).
Test emails are visible at http://localhost:8025 (Mailpit).
## Development commands (run inside `app/`)
```bash
npm run dev # local dev server (port 3000, no Docker)
npm run build # production build
npx prisma studio # visual DB browser
npx prisma migrate dev --name <name> # create a new migration
npx prisma migrate deploy # apply migrations (done automatically on container start)
```
## Architecture
**Stack:** Next.js 14 App Router · PostgreSQL 16 · Prisma 5 · Stripe · Nodemailer · TailwindCSS · Zod · Docker + Caddy
**Source root:** `app/src/`
| Directory | Purpose |
|---|---|
| `app/api/` | REST API routes — one folder per resource |
| `app/admin/` | Admin dashboard pages (role-gated at layout level) |
| `app/(storefront)/` | Public-facing pages |
| `components/` | Shared React components and UI primitives |
| `lib/` | Core utilities (auth, email, storage, Stripe, validation, rate limiting) |
| `context/` | Client-side UserContext |
## Key patterns
**API routes** follow a consistent shape: validate input with Zod → check auth/role via `getCurrentUser()` → query Prisma → return JSON. Copy an existing route as a starting point.
**Auth** is session-based (no NextAuth). `lib/auth.ts` handles token creation, hashing (SHA256), and the `getCurrentUser()` helper used in every protected route. Sessions expire after 30 days.
**Admin protection** is enforced in the admin layout: `CUSTOMER` role is blocked, `ADMIN` and `OWNER` are allowed. A `mustChangePassword` flag redirects new owners to a password-change page before anything else.
**Validation schemas** live in `lib/validate.ts` (Zod). Add new schemas there; never validate inline in routes.
**Image uploads** go through `lib/storage.ts`, which validates magic bytes (JPEG/PNG/WebP/ICO) before writing to `/app/public/uploads/<productId>/`. Uploads are stored in a named Docker volume (`uploads`) shared between the `app` and `caddy` containers.
**Emails** are sent via `lib/email.ts` (Nodemailer). Locally they land in Mailpit; in production, configure SMTP env vars.
**Rate limiting** is IP-based and backed by the `LoginAttempt` DB table (10 attempts / 15 min). Logic is in `lib/rate-limit.ts`.
## Data model (high level)
- **User** → has role (`CUSTOMER` / `ADMIN` / `OWNER`), sessions, orders, reviews
- **Product** → belongs to one **ProductType** (defines the attribute schema), many-to-many with **Category**, has **MediaAsset**, **ProductVariant**, **Review**
- **ProductType** → defines a JSON schema for product attributes (e.g. "clothing" has size/color)
- **ProductVariant** → SKU, price, stock per variante (es. taglia/colore di un prodotto)
- **Category** → hierarchical (self-referential `parentId`), many-to-many with Product
- **Order** → status state machine (`PENDING → PAID → FULFILLED`, `CANCELLED`, `REFUNDED`), has **OrderItem** and **Payment**
- **PasswordResetToken** → token hashed con scadenza per il flusso reset password
- **Page** / **PageSection** → CMS minimale per pagine statiche (slug, titolo, sezioni JSON ordinate)
- **SiteSettings** — key/value store for shop configuration (branding, etc.)
- **AuditLog** — tracks admin actions
## Environment variables
Copy `.env.example` to `.env`. For production, generate a strong `AUTH_SECRET` with `openssl rand -hex 32` and replace all placeholder values. The `DATABASE_URL` uses the Docker service name `db` as host — do not change it for containerised deployments.
## Debugging
**Check app logs (first thing to do):**
```bash
docker compose logs -f app # live
docker compose logs app --tail=100 # last 100 lines
```
**Common error patterns to look for in logs:**
- `EACCES: permission denied` → volume/filesystem permissions issue
- `PrismaClientKnownRequestError` → DB constraint violation or bad query
- `401 / 403` in API → session expired or role check failing
- Silent form failures → always check `res.ok` in `fetch` calls; UI may show success even on API error
**API errors not surfacing in the UI** are almost always caused by a missing `res.ok` check in the frontend `fetch` call. The pattern to use in every form submit:
```ts
const res = await fetch('/api/...', { method: 'POST', ... })
if (!res.ok) {
const data = await res.json().catch(() => ({}))
setError(data.error || `Errore (${res.status})`)
return
}
```
**Database inspection:**
```bash
# Open Prisma Studio (visual DB browser)
cd app && npx prisma studio
# Or connect directly
docker compose exec db psql -U ecommerce ecommerce
```
**Rebuild after code changes:**
```bash
docker compose up -d --build app # rebuild only the app container
```
**TypeScript errors in IDE but not in build:** likely a missing `node_modules` or stale tsconfig in the IDE. Run `npm install` inside `app/` and restart the IDE TypeScript server.
## Deployment
1. Point your domain DNS to the server.
2. Set `APP_URL` to `https://yourdomain.com` in `.env`.
3. Edit `Caddyfile`: replace `localhost` with your domain.
4. `docker compose up -d --build`
Caddy handles TLS automatically via Let's Encrypt. Ports 80 and 443 must be open on the firewall.