# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. # IMPORTANT: # Always read memory-bank/@architecture.md before writing any code. Include entire database schema. # Always read memory-bank/@app-design-document.md before writing any code. # After adding a major feature or completing a milestone, update memory-bank/@architecture.md. ## Project status The application is built and lives under [mykindlebox/](mykindlebox/) — a `client/` (React + Vite) and a `server/` (Express + SQLite/Drizzle). See [memory-bank/progress.md](memory-bank/progress.md) for the phase-by-phase build log. The source-of-truth design docs are: - [memory-bank/app-design-document.md](memory-bank/app-design-document.md) — full product spec: pages, components, data models, UX decisions - [memory-bank/tech-stack.md](memory-bank/tech-stack.md) — the chosen stack (summarized below) - [memory-bank/architecture.md](memory-bank/architecture.md) — current architecture + database schema ### Commands Backend (`mykindlebox/server`): - `npm run dev` — start the API on port 3001 with `tsx watch` (hot reload) - `npm run build` — typecheck + compile to `dist/` - `npm start` — run the compiled server (`node dist/index.js`) - There is no test suite yet (`npm test` is a placeholder). Frontend (`mykindlebox/client`): - `npm run dev` — Vite dev server on port 5173 (proxies `/api` and `/uploads` to `localhost:3001`) - `npm run build` — production build to `dist/` - `npm run lint` — ESLint Deployment: `docker compose up --build` from `mykindlebox/` serves the app on port 8080 by default (nginx serves the built client and reverse-proxies `/api` + `/uploads` to the Node server). Configure via `mykindlebox/.env`: `MYKINDLEBOX_PORT` overrides the host port, and `MYKINDLEBOX_PASSWORD` requires a login (if unset, auth is disabled). ### Conventions - The REST API speaks **snake_case** at the boundary; Drizzle columns are camelCase. `server/utils/case.ts` converts both directions — don't hand-write conversions. - The client talks to the API over **relative URLs** (`/api`, `/uploads`). Never reintroduce a hardcoded `http://localhost:3001`; it breaks LAN/PWA access from other devices. ## What MyKindlebox is A self-hosted rabbitry (rabbit breeding herd) management web app, replacing an existing PHP app (`belowland.com/rabbitsite`). It is single-user, self-hosted, and out of scope for v1 includes multi-tenancy, public listing pages, show tracking, and payments. The core differentiator: **adding a rabbit starts from a pedigree tree, not a blank form** — the 3-generation ancestor tree (sire/dam, their sires/dams) is the primary data-entry surface, with inline autocomplete search against existing herd records and graceful fallback to freeform text for unknown/bought-in ancestors. ## Tech stack (planned) | Layer | Choice | |---|---| | Frontend | React + Vite (PWA-ready) | | Routing | React Router v7 | | State | Zustand (local UI state) + React Query (server sync) | | Styling | Tailwind CSS with custom theme tokens | | Backend | Node.js + Express (REST API) | | Database | SQLite via Drizzle ORM (single-file DB) | | Auth | Single-user session token (no OAuth) | | Hosting | Docker Compose (Nginx + Node + SQLite volume) | ## Data model There are only two core tables — no separate "Kit" table: - **Rabbit**: name, sex, dob, weight_lbs, status (`active`/`for_sale`/`on_hold`/`sold`/`deceased`/`other`), `sire_id`/`dam_id` (self-referencing FKs), and genetics loci fields (`locus_a/b/c/d/e/en/v`). - **Litter**: `sire_id`/`dam_id`, `kindle_date`, `kit_count`, `notes`. Kits are full Rabbit records from birth, linked to a litter implicitly via matching `sire_id`/`dam_id`/DOB — the Litter detail page derives its kit list by querying Rabbits rather than a join table. When adding features touching litters or kits, preserve this derivation rather than introducing a Kit entity. Ancestor pedigree nodes that aren't in the DB are stored as freeform text rather than null FKs, so entry is never blocked by incomplete ancestor records. Weight is stored as a decimal float in lbs internally; lb+oz vs decimal display is a per-user setting applied at the read/write boundary, not stored separately. The genetics calculator's pairings are session-only and never persisted. ## Key UX decisions to preserve - Pedigree-first entry flow (Step 1: pedigree tree → Step 2: rabbit details → Step 3: genetics loci, collapsible/optional → Step 4: review & save). - Genetics section defaults collapsed on Add, expanded on Edit if loci data already exists. - Dashboard herd counts (For Sale/On Hold/Sold/etc.) are derived live from the Rabbit `status` field, not cached counters. - Mobile bottom nav's "Add" tab opens the rabbit entry flow directly.