MyKindlebox/CLAUDE.md

82 lines
5.3 KiB
Markdown

# 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.
- 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.
</content>
</invoke>