# 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). `MYKINDLEBOX_PORT` in `mykindlebox/.env` overrides the host port. Auth is account-based (first visit shows a one-time account-creation screen; more users added in Settings) — the old `MYKINDLEBOX_PASSWORD`/`AUTH_PASSWORD` env var is retired and ignored. ### 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. - **Versioning**: the app version is `mykindlebox/client/package.json`'s `version` (server package kept in sync), shown at the bottom of the sidebar and the mobile More menu. The checked-in pre-commit hook `.githooks/bump-version.mjs` bumps the patch number on every commit that touches `mykindlebox/` — don't bump patch versions by hand. For a minor/major release, run `npm version minor --no-git-tag-version` (or `major`) in `client/` before committing; the hook keeps it and syncs the server. Each clone must enable the hook once with `git config core.hooksPath .githooks`. - 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 self-hosted with **shared-herd user accounts** (users are separate logins to the same rabbitry — see `memory-bank/FEATURE_User_Accounts.md`; everyone equal, no roles). Out of scope: multi-tenancy (per-user herds), public listing pages, 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 | User accounts, shared herd (scrypt + SQLite sessions, 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 entered as freeform text (manual-ancestor JSON) rather than null FKs, so entry is never blocked by incomplete ancestor records. On rabbit creation the server then materializes those entries into real, linked Rabbit records (status `other`, deduped by ear number or name + farm — `server/lib/ancestors.ts`) so ancestors are reusable; text columns remain only for branches above an Unknown parent and for legacy data. 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.