MyKindlebox/CLAUDE.md

4.7 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 (nginx serves the built client and reverse-proxies /api + /uploads to the Node server). Set MYKINDLEBOX_PASSWORD (e.g. in mykindlebox/.env) to require 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.