MyKindlebox/mykindlebox/README.md

185 lines
6.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# MyKindlebox
A self-hosted rabbitry (rabbit breeding herd) management web app — track your
rabbits, their pedigrees, litters, and genetics. Self-hosted, with simple user
accounts sharing one herd, and designed to replace a legacy PHP
herd-management site.
The core differentiator: **adding a rabbit starts from a pedigree tree, not a
blank form.** The 3-generation ancestor tree (sire/dam and their sires/dams) is
the primary data-entry surface, with inline autocomplete against your existing
herd and graceful fallback to freeform text for bought-in or unknown ancestors.
## Features
- **Pedigree-first rabbit entry** — build the ancestor tree first, then fill in
details; unknown ancestors can be stored as plain text so entry is never
blocked by missing records.
- **Herd management** — name, sex, DOB, weight, and status
(`active` / `for_sale` / `on_hold` / `sold` / `deceased` / `other`).
- **Litters** — record kindle dates and kit counts; the kit list is derived
live from Rabbit records (no separate Kit table).
- **Genetics** — per-rabbit loci (`A/B/C/D/E/En/V`) and a session-only pairing
calculator for predicting offspring.
- **Dashboard** — herd counts derived live from rabbit status.
- **Pedigree printing**, CSV import/export, and a configurable weight display
(decimal lbs or lb + oz).
- **PWA-ready** with a mobile bottom nav, installable on phones/tablets.
## Tech stack
| Layer | Choice |
| -------- | ----------------------------------------------------- |
| Frontend | React 19 + Vite (PWA-ready) |
| Routing | React Router v7 |
| State | React Query (server sync) |
| Styling | Tailwind CSS |
| Backend | Node.js + Express 5 (REST API) |
| Database | SQLite via Drizzle ORM (single-file DB) |
| Auth | User accounts, shared herd (scrypt + DB sessions) |
| Hosting | Docker Compose (Nginx + Node + SQLite volume) |
## Project layout
```
mykindlebox/
├── client/ React + Vite frontend
├── server/ Express + SQLite/Drizzle API
└── docker-compose.yml Production stack (nginx + node + volume)
```
## Development
Run the backend and frontend in two terminals.
**Backend** (`server/`):
```bash
cd server
npm install
npm run dev # API on http://localhost:3001 (tsx watch, hot reload)
```
Other scripts: `npm run build` (typecheck + compile to `dist/`),
`npm start` (run compiled server), `npm test`.
**Frontend** (`client/`):
```bash
cd client
npm install
npm run dev # Vite dev server on http://localhost:5173
```
The dev server proxies `/api` and `/uploads` to `localhost:3001`. Other
scripts: `npm run build`, `npm run lint`, `npm test`.
> The client talks to the API over **relative URLs** (`/api`, `/uploads`) so the
> app works over LAN and as an installed PWA — never hardcode a host.
## Deployment (Docker Compose)
From the `mykindlebox/` directory:
```bash
docker compose up --build
```
The app is served on **http://localhost:8080** — nginx serves the built client
and reverse-proxies `/api` + `/uploads` to the Node server. The SQLite database
and uploaded photos live in the `server-data` Docker volume.
To serve on a different host port, set `MYKINDLEBOX_PORT` (e.g. in a `.env` file
next to `docker-compose.yml`):
```env
MYKINDLEBOX_PORT=3000
```
Then re-run `docker compose up -d` — the app is served on that port instead of
8080. (Only the host side changes; inside the compose network nginx still
listens on 80.)
### Updating an existing deployment
Compose builds from whatever is checked out on the host, so pull first, then
rebuild. Run from the repo root on the server:
```bash
# 1. Back up the database (schema migrations run automatically on startup)
cd mykindlebox
docker compose cp server:/app/data ./data-backup-$(date +%F)
# 2. Pull the latest code
cd ..
git checkout main
git pull
git log --oneline -1 # confirm you're on the commit you expect
# 3. Rebuild and restart both services
cd mykindlebox
docker compose up --build -d
```
**Verify both containers were recreated:**
```bash
docker compose ps
```
Both `client` and `server` should show a recent **CREATED** time (seconds or
minutes ago), and `server` should reach **(healthy)** within ~15 seconds. If
either still shows an old CREATED time, Compose reused a cached image — force
it:
```bash
docker compose build --no-cache server # or client
docker compose up -d --force-recreate server
```
The client and server must be from the same version; a new client against an
old server will fail on login and newer pages. If the server never becomes
healthy, check `docker compose logs server --tail 50`.
Finally, hard-refresh the browser (Ctrl+Shift+R). On an installed phone PWA,
fully close and reopen the app to pick up the new build. Once everything looks
right, the `data-backup-*` folder can be deleted.
### Pedigree scanning (optional)
**Add Rabbit → Scan a pedigree** reads a photo of a paper pedigree (any layout,
printed or handwritten) and fills in the tree. It uses the Claude API, so it
needs an API key from [console.anthropic.com](https://console.anthropic.com) and
internet access on the server. Add it to `.env` next to `docker-compose.yml`:
```env
ANTHROPIC_API_KEY=sk-ant-...
```
Then run `docker compose up --build -d`. Without a key the scan button is hidden
and everything else works as before. Each scan costs roughly 5–10¢ in API usage.
The photo is sent to Anthropic for the scan and is not stored by MyKindlebox.
### Authentication
The app uses **user accounts** — everyone shares the same herd; accounts are
separate logins with their own theme and weight-display preference. On first
launch the app shows a one-time **create your account** screen; add more people
later under **Settings → Users**. Passwords are hashed (scrypt) and sessions
last 30 days, surviving server restarts.
> **Upgrading from the password-only version?** The old `MYKINDLEBOX_PASSWORD`
> env var is no longer used — remove it from your `.env`. On your next visit
> you'll see the one-time account-creation screen; your herd data is untouched.
## Data & backups
The herd database (`server/data/`), uploaded photos, and `.env` files are
**gitignored** — they are never committed. In production they persist in the
`server-data` volume; back that volume up to preserve your data. A quick
snapshot from a running stack:
```bash
docker compose cp server:/app/data ./data-backup-$(date +%F)
```