5.3 KiB
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/ — a client/ (React + Vite) and a server/ (Express + SQLite/Drizzle). See memory-bank/progress.md for the phase-by-phase build log. The source-of-truth design docs are:
- memory-bank/app-design-document.md — full product spec: pages, components, data models, UX decisions
- memory-bank/tech-stack.md — the chosen stack (summarized below)
- memory-bank/architecture.md — current architecture + database schema
Commands
Backend (mykindlebox/server):
npm run dev— start the API on port 3001 withtsx watch(hot reload)npm run build— typecheck + compile todist/npm start— run the compiled server (node dist/index.js)- There is no test suite yet (
npm testis a placeholder).
Frontend (mykindlebox/client):
npm run dev— Vite dev server on port 5173 (proxies/apiand/uploadstolocalhost:3001)npm run build— production build todist/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.tsconverts both directions — don't hand-write conversions. - The client talks to the API over relative URLs (
/api,/uploads). Never reintroduce a hardcodedhttp://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
statusfield, not cached counters. - Mobile bottom nav's "Add" tab opens the rabbit entry flow directly.