MyKindlebox/CLAUDE.md

5.9 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:

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.