Files
Moonbase/CLAUDE.md
Bonna Moon fe24cd73be v0.27.0 — Garden brain: zone-4b knowledge, calendar suggestions, UW citations
src/lib/garden/knowledge.ts holds hand-curated zone-4b (~May 15 frost)
knowledge for 28 crops/fruits/flowers: monthly care timing, companion
friends/foes, rotation families. Pure matchers knowledgeFor/tipsForMonth
use whole-word stem matching (tested — 'Pear' must not hit 'Pea'). The
calendar gains a "Good to do this month" list matched to owned plants,
deduped against existing task titles, with one-click Remind me → YEARLY
task via /api/v1/tasks. Plant type pages gain a "Growing in zone 4b"
card (timeline, companions, rotation). Tips cite UW Extension via site
search URLs — no fabricated article links.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 19:35:45 -05:00

145 lines
8.1 KiB
Markdown
Raw Permalink 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.

# Moon Base — Project Notes
Property management for the Moon homestead (Eau Claire, WI). Next.js 14 + Prisma +
Postgres. Same conventions as FMB (`/Users/bonnamoon/Projects/fullmoonbakehouse`).
Repo on Gitea: **`bonna61/Moonbase`**. Live at NAS:8053. See `README.md` for the
user-facing overview.
## Modules (all live)
- **Garden** — Plant registry + care/harvest logs, plant **groups**, reusable
**PlantType** records, Wikipedia photos. Plants sit on the shared location tree.
Harvest logs carry structured `amount`+`unit` (legacy freeform `quantity` kept
for old rows — don't regress); a harvest can simultaneously create a pantry
item (`addPlantLog`'s `pantry` input → GARDEN-source consumable). PlantTypes
can link a UWMadison Extension article (`uwExtensionUrl/Title`), searched via
`/api/v1/plant-types/uw-search` (proxy to hort.extension.wisc.edu's WP REST
API; helper `src/lib/garden/uw-extension.ts`).
- **Inventory** — durable **Item**s that nest (`parentItemId`: a toolbox is an
Item that holds Items, with a cycle guard), with **Label**s (M:N via
`LabelOnItem`), `ItemAttachment` (PHOTO/MANUAL/RECEIPT/WARRANTY), and `ItemLog`.
Items carry value/purchase/warranty (incl. `lifetimeWarranty`, `insured`),
`serial`/`modelNumber`/`brand`, a **sold** lifecycle, and freeform `customFields`
(JSON, e.g. VIN). Maintenance = a `Task` linked via `Task.itemId`. **HomeBox CSV
import** at `/api/v1/items/import` (pure parser `src/lib/inventory/homebox-import.ts`).
`kind` is DURABLE|CONSUMABLE. Shares the Location spine.
- **Pantry** (Kitchen → Pantry & Freezer) — CONSUMABLE Items with categories,
price paid, tags (shared `Label` table), and expiry. Pulls go through
`/api/v1/pantry/[id]/use` or `/bulk-use` and write `ItemLog` type `USED` with a
structured `amount` (consumption is queryable — don't regress to NOTE strings).
Service `src/lib/services/pantry.ts`; pure logic + tests in `src/lib/pantry/core.ts`.
Rides the `items:*` scopes (pantry items ARE Items).
- **Animals** — `Animal` + `AnimalLog` (pets/livestock); placed on the Location
tree, and `Task`s can link to an animal (`Task.animalId`).
- **Locations** — `Location` tree (self-ref `parentId`) shared by plants, items, animals.
- **Reminders** — `Task` + `TaskCompletion`; recurrence in `src/lib/tasks/schedule.ts`
(incl. `occurrencesInRange` projection). **/calendar** renders a month view of
all tasks (garden + house) plus PlantType bloom/harvest windows
(`src/lib/garden/season.ts`) and garden-brain suggestions.
- **Garden brain** — `src/lib/garden/knowledge.ts`: hand-curated zone-4b
(~May 15 frost) care timing, companions/foes, rotation families for ~28
crops; pure matchers `knowledgeFor`/`tipsForMonth` (whole-word stem match —
beware "Pear"/"Pea"-style false hits, tested). Surfaced as calendar
"Good to do this month" (one-click YEARLY task via /api/v1/tasks) and a
"Growing in zone 4b" card on type pages. Tips cite UW Extension via site
search URLs — never fabricate article URLs.
- **REST API** — `/api/v1/*` authed by `ApiToken` (per-scope; logic in `src/lib/api/`).
- **Suggestions** — `@otm/account-panel` (Gitea npm registry) → files issues to the repo.
- **Backup & Restore** — `/api/admin/backup` + `/api/admin/restore` (admin only).
- **Self-update** — admin "Pull & rebuild" (see Deploy).
## Data model (the one rule)
**Two nesting worlds, crossed once.** *Places* (`Location`, self-ref `parentId`,
unlimited depth — `LocationKind` is an icon hint, never a constraint) nest in
places. *Items* (things you own) nest in items, and an Item lives in a Place **or**
inside another Item. You never put a Place inside an Item. **Plants** and
**Animals** are leaves in a Place (own logs, don't nest). HomeBox + Grocy + farmOS
collapse into: **Places · Plants/Animals (leaves) · Items (durable + consumable,
nesting)**. Logs are per-domain tables (`PlantLog`/`ItemLog`/`AnimalLog`), NOT a
polymorphic table; `Task` carries nullable `plantId`/`itemId`/`animalId`.
## Architecture conventions
- **API-first.** New modules (Inventory, Animals) are built on `/api/v1/*` and the
UI calls those same endpoints — no separate UI routes. Garden/Tasks predate this
and still use `/api/plants` etc.
- **Service layer** `src/lib/services/*` does DB work + AuditEvent, taking
`(ctx: AuthContext, input)`. Routes are thin: `authenticateRequest(req, scope)`
service → `handleApiError`. The MCP server (unbuilt) will reuse these services.
- **Auth helper** `src/lib/api/authenticate.ts` accepts EITHER a NextAuth cookie
session (full scope `["*"]`) OR a Bearer PAT (limited to its `scopes`; write
implies read). Scope constants in `src/lib/api/scopes.ts` (client-safe).
- **Decimals** for money/quantity (`@db.Decimal`) — convert to `Number()` before
passing to client components (Prisma Decimal isn't serializable across the boundary).
## Blocked on a domain + HTTPS (deferred)
Camera scanning/photo-capture (`getUserMedia` needs a secure context), the **PWA**
(service worker + install need HTTPS), and the **MCP server** (Claude needs a public
HTTPS URL) all wait until there's a domain + reverse-proxy/tunnel. The app is
LAN-only over `http://NAS:8053` today. Pantry/consumables and other pure web work
can ship before then.
## Local dev
- DB: `postgresql://tonym@localhost:5432/moonbase_dev`; copy `.env.example``.env`.
- `npm install`, `npm run dev` (3000). After schema edits: `npx prisma generate`.
- `npx prisma migrate deploy` provisions Bonna + Tony. `npm run db:seed` for demo
data (`SEED_MODE=minimal` = accounts only).
- Backfills for the location/plant-type refactors: `npm run db:backfill-locations`,
`npm run db:backfill-plant-types`.
## Deploy — git checkout on the NAS (NOT rsync)
> Working without this file (e.g. a Claude on another machine)? The self-contained
> version is `docs/git-deploy-guide.md`.
The NAS appdata (`/mnt/user/appdata/moonbase`) is a real **git checkout** tracking
`origin/master` (remote URL carries the token). Deploy by:
```sh
git push origin master
ssh root@192.168.0.5 'cd /mnt/user/appdata/moonbase && git pull && docker compose up -d --build'
```
Or admins click **Settings → Updates → Pull & rebuild**, which signals the
privileged `updater` sidecar (docker socket + adnanh/webhook) to run the same
`git pull && compose up -d --build app` detached; the UI polls `/api/version` and
reloads. **Never rsync over the appdata dir** — it fights the checkout.
- **Secrets** (`NEXTAUTH_SECRET`, `GITEA_TOKEN`, `UPDATER_SECRET`) live in a
gitignored host `.env` next to the compose file, interpolated in — never committed.
- **Docker runtime** mirrors FMB: `node:20-bookworm-slim` + openssl, runs as root,
full `node_modules`, `next start`. Migrations run on container start via the
entrypoint (waits for Postgres first). Image gotcha: don't let `npx prisma`
resolve at runtime — with no local prisma on PATH it pulls Prisma 7, which
rejects `url` in the datasource.
## Conventions (same as FMB)
- **Every commit bumps APP_VERSION** in `src/lib/version.ts` + a plain-English
entry atop `src/lib/changelog.ts` (the footer shows it + an "update available"
badge from `src/lib/update-check.ts`). Minor for features/migrations, patch for fixes.
**Fetch first**: parallel sessions push to master — check
`git show origin/master:src/lib/version.ts` before picking a number
(a v0.22.0 collision has already happened once).
- **AuditEvent on every mutation** — append-only.
- **Soft-delete** via `active=false`.
- **Pure core + colocated test** — logic in `src/lib/...` with a `.test.ts`; routes thin.
## Auth
- Username OR email login. Accounts `bonna` / `tony`, role `ADMIN`.
- `getSession()` / `requireAuth()` / `isAdmin()` in `src/lib/auth.ts`.
- **Forced password change is wired** (provisioned accounts ship `moonbase!` +
`mustChangePassword=true`): the dashboard layout redirects to `/change-password`
(outside the layout group; backed by `/api/account/change-password`). Don't
remove that redirect.
- `NEXTAUTH_SECRET` is asserted at runtime in production (skipped during build).
## Color palette
Forest / earth theme: `--canopy` (sidebar), `--leaf` (accent), `--soil` (text),
`--dew` (bg), `--ember` (destructive).