Commit Graph

52 Commits

Author SHA1 Message Date
8f77b7c453 v0.22.0 — Inventory search + Location/Label grouping; Suggestions styling fix
Adds a search box (matches name, location, and labels) and a Location/Label
grouping toggle to Inventory, and fixes the unstyled Suggestions page.
(Renumbered from 0.19.0 → 0.22.0: Pantry work took 0.19–0.21 in parallel.)

Hardening from a max-effort code review of the new grid:
- Contained items resolve to their container's effective location, so search
  finds them and the flat view groups them under the right place (not "No
  location").
- Location/label groups key on id, not name, so same-named places/labels stay
  separate; synthetic bucket renamed "No labels" to avoid colliding with a real
  label; fixed duplicate React keys and two empty-state regressions.
- deleteItem now reparents a deleted container's contents into its own spot
  (its place or parent item) instead of orphaning them; the grid also treats
  any still-orphaned child as top-level so nothing silently vanishes.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-04 20:12:21 -05:00
Bonna Moon
dd7af9e8d4 v0.21.1 — Pantry: delete items with inline confirm
Trash icon on each row; clicking shows "Delete? Yes / No" inline
(no dialog needed). Soft-deletes via active=false. Removed the
admin-only guard on DELETE /api/pantry/[id] since anyone logged in
should be able to manage their own pantry.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-29 18:32:30 -05:00
Bonna Moon
6b75e47ee9 v0.21.0 — Pantry: bulk pull dialog
New "Pull from pantry" button opens a dialog where you search/filter
all items, type a quantity next to each one you're taking, pick or type
a reason, and submit all in one shot. Items with amounts entered
highlight; over-stock amounts show inline error. Backed by new
POST /api/pantry/bulk-use (transactional quantity deduction + ItemLog).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-29 18:31:14 -05:00
Bonna Moon
d3af826e3a v0.20.0 — Pantry: multi-tag items (e.g. Pre-cooked + Poultry)
Uses existing Label/LabelOnItem tables — no schema change. Tags field
in the add/edit dialog: type + Enter/comma to add, backspace to remove,
autocomplete from previously-used labels. Tags display as chips on each
item row. API: POST/PATCH accept tags[], upsert Label rows, sync
LabelOnItem. Catalog endpoint also returns all label names for
autocomplete.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-29 18:25:07 -05:00
Bonna Moon
70df86ba59 Pantry: show plain location name, not full path
The dropdown already only shows Kitchen locations so the
"Kitchen › Freezer" prefix is redundant — just show "Freezer".

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-29 18:12:26 -05:00
Bonna Moon
67bc23c64e v0.19.2 — Combobox: always show "Add new…" when allowCustom
Previously the "Add" option only appeared after typing a non-matching
query, which wasn't discoverable. Now the combobox always shows
"Add new…" at the bottom when allowCustom=true; clicking it focuses the
search input so you can type the new name.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-29 18:12:05 -05:00
Bonna Moon
3b35e835c8 v0.19.1 — Pantry: quantity steppers go by whole numbers
Changed step from 0.25 to 1 on the Quantity and "how much are you
using" number inputs so the spinner arrows move by wholes. Added
noValidate on both forms (native step-mismatch validation would
otherwise block submitting typed partials like 2.5) plus manual
amount-bounds checks in the use dialog to replace the native min/max
constraints that noValidate disables.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-29 17:58:04 -05:00
Bonna Moon
61dc8acacf v0.19.0 — Pantry: tag what you used items for
Quick-pick chips (Family dinner, Dinner party, Taking on a trip, Meal
prep, Gave it away) in the Use dialog, alongside the existing freeform
notes field — picking one fills the note, no schema change needed.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-29 17:55:13 -05:00
Bonna Moon
c449b0c2ae v0.18.1 patch — Pantry: location dropdown shows Kitchen only
Filter locations to Kitchen and its children (fridge, freezer, pantry
shelves, etc.). Display the full path so "Kitchen › Freezer" shows
instead of just "Freezer".

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-29 17:49:37 -05:00
Bonna Moon
e501679416 v0.18.1 — Pantry: add custom categories on the fly
Type a new name in the Category or Subcategory dropdown and pick
"Add '...'" at the bottom. Custom categories persist (stored as strings
on the item) and reappear merged into future dropdowns.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-29 17:48:44 -05:00
Bonna Moon
608a192877 v0.6.2 — Pantry: searchable category/subcategory comboboxes 2026-06-29 17:42:54 -05:00
Bonna Moon
62a0089ec2 v0.6.1 — Pantry: categories, price tracking, and autocomplete 2026-06-29 17:37:59 -05:00
Bonna Moon
0d52ea5ad1 v0.6.0 — Kitchen: Pantry & Freezer inventory 2026-06-29 17:28:28 -05:00
Bonna Moon
f483630419 Add Change password link to user menu 2026-06-29 17:18:58 -05:00
Bonna Moon
8ec43f3561 Add password recovery page at /recover 2026-06-29 16:45:19 -05:00
ddc0a60a0c v0.18.0 — Locations Quick setup + place-based reminders (#4 groundwork)
#4 cleanup + Tony's house structure.

- Task.locationId (migration): reminders can attach to a place, not just a
  plant/item/animal. Add one from a location's menu (e.g. clean gutters on House >
  Exterior); the Reminders page + tasks service surface the linked location/item/
  animal.
- Locations "Quick setup": paste/confirm an indented outline → creates the nested
  tree (find-or-create by name+parent, idempotent), pre-filled with the Moon
  homestead house layout. Optional "sweep existing garden areas under Yard" moves
  every top-level place that holds plants under a new Yard parent — the
  'move all the yard stuff to a new top level' ask.
- Pure outline parser (src/lib/locations/outline.ts, +4 tests); bulk setup service
  + /api/locations/bulk. Verified end-to-end: nested tree + paths, garden sweep,
  place reminder.

Yard sub-bucketing deferred per Tony.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-16 02:33:52 -05:00
4aacffdf4e v0.17.0 — Mobile menu (#3) + Suggestions readability & header lightbulb (#2)
Addresses Gitea suggestions #3 and #2.

#3 Mobile: the sidebar was desktop-only (hidden md:flex), leaving phones with no
nav at all. Added a slide-out drawer (hamburger in the top bar, md:hidden) that
reuses the nav. Lifted navItems/settingsItems into src/components/layout/nav-items.ts
so the sidebar and mobile drawer share one source + active-state logic. No HTTPS
needed (pure responsive UI).

#2 Suggestions: the @otm/account-panel SuggestionsPanel hardcodes light neutral-*
text that assumes a white backdrop, so it washed out on the app theme — now
rendered on a white card for contrast in light/dark. Added a lightbulb button in
the header that jumps to Suggestions (like FMB).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-16 02:16:57 -05:00
b8af0f986b docs: refresh README + CLAUDE.md for current modules; add deploy guide for any Claude
- README/CLAUDE.md: Inventory depth (warranty/value/maintenance/sold/custom fields,
  HomeBox CSV import), Locations page, the two-world data-model rule, API-first +
  service-layer conventions, and the HTTPS-gated future work (MCP/PWA/camera)
- New docs/git-deploy-guide.md: self-contained git + deploy walkthrough for a
  Claude instance working without this repo's CLAUDE.md (NAS is a git checkout,
  push + pull/rebuild, never rsync, secrets in host .env, prisma-at-runtime gotcha)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-16 01:27:30 -05:00
80324afea2 v0.16.1 — Fix forced-password-change re-firing every visit
The dashboard gate trusted session.user.mustChangePassword from the JWT, which is
only refreshed on re-login/update() — so after a user set a new password the stale
cookie kept bouncing them back to /change-password. Read the flag from the DB (the
source of truth) so it clears immediately and never re-fires. Cheap for a 2-user
app; also re-checks the account is still active.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-16 01:26:00 -05:00
5f4c482636 v0.16.0 — HomeBox CSV import + sold lifecycle + custom fields
Bring an existing HomeBox inventory straight in, and capture the fields HomeBox
has that we were missing (skipping asset IDs per Tony).

- Item: soldTo/soldPrice/soldDate/soldNotes + flexible customFields (JSON, e.g.
  VIN / oil weight for vehicles); both editable in the item dialog and shown on
  the detail page
- Pure HomeBox CSV parser (src/lib/inventory/homebox-import.ts, +5 tests) —
  RFC4180 quoting (commas/newlines/escaped quotes in fields), HomeBox's 0001-*
  null dates and 0 = empty price, semicolon labels, HB.field.* custom columns,
  nested 'A / B' location paths
- Import service + /api/v1/items/import: find-or-creates the nested locations
  and labels, creates items, recomputes location paths, returns a summary
- Inventory 'Import' button: paste/upload CSV, review every row with checkboxes
  (uncheck to skip), then import. Preview parses client-side (parser is pure)
- Verified end-to-end: nested locations, split labels, sold + custom fields,
  skip, quoted names, null-date handling. tsc + 38 tests + build green

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-16 01:01:17 -05:00
63569aabd3 v0.15.0 — Inventory depth (HomeBox parity) + Locations page
Rounds out Inventory toward HomeBox, and gives Locations a real home.

Inventory:
- Attach manuals, receipts, and warranty docs (any file), not just photos —
  attachment uploader now has a kind picker; WARRANTY kind added
- Richer purchase/warranty: purchasedFrom, warrantyDetails, lifetimeWarranty,
  insured (item dialog + detail facts + header badge)
- Schedule recurring maintenance from an item (creates a Task linked via
  itemId); item detail shows its maintenance with overdue flagged. Task create
  now accepts itemId/animalId

Locations:
- New Locations page + nav: browse/add/rename/move/delete the whole place tree
  (LocationManager over the existing /api/locations routes); shows plant/item
  counts per place. The spot to merge near-dupes before dropping legacy zone

Verified end-to-end against a running server (new fields round-trip, maintenance
task links to item, MANUAL attachment stored). tsc + 33 tests + build green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-16 00:34:07 -05:00
cffa739056 docs: add Animals module to README + CLAUDE.md
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-16 00:28:51 -05:00
39be24c2fc v0.14.0 — Animals & Pets
Livestock and household pets as leaves on the Location tree, mirroring Garden.

- Animal model (species/breed/sex/birthdate/location, soft-delete) + AnimalLog
  (feeding, vet, weight, medication, breeding, acquired, died); Task.animalId for
  recurring care reminders
- API-first /api/v1/animals (CRUD) + logs, animals:read/write scopes; animals
  service shared with the coming MCP
- Animals pages: list grouped by species with auto-computed age, detail with
  facts + latest weight + care log; add/edit/remove + log entry. Nav entry.
  Backup/restore cover the new tables
- Pure age.ts (newborn/days/months/years) with tests; verified end-to-end against
  a running server (create, vet + weigh-in logs, read-back)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-16 00:23:53 -05:00
777569a21a docs: add README, refresh CLAUDE.md for current modules + git-checkout deploy
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-16 00:18:06 -05:00
b0118d3fec v0.13.0 — Inventory (HomeBox): durable items that nest
The first inventory vertical on the shared spine. Things you own — tools, gear,
equipment — each living in a Location or inside another Item.

- Item model (kind DURABLE|CONSUMABLE; consumable fields present but unused so
  Pantry needs no migration), self-nesting via parentItemId (toolbox holds drill,
  with a cycle guard), value/warranty/serial/brand/qty, qrSlug, photo
- Label (m2m) + ItemAttachment (photos/manuals/receipts) + ItemLog
  (maintenance/repair/move/dispose) history; Task.itemId
- API-first: /api/v1/items (CRUD), labels, logs, multipart attachments — the UI
  consumes the same scoped endpoints. items service shared with the coming MCP
- Inventory pages: tree grouped by Location with items nested inside items;
  item detail with warranty status, photos, contents, history; add/edit/delete,
  log, photo upload. Nav entry. Backup/restore cover the new tables
- Pure value.ts (warrantyStatus, totalValue) with tests; verified end-to-end
  against a running server (nest, cycle-guard 400, log 201)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-16 00:12:03 -05:00
0904790dca Security: force first-login password change, gate admin tools, validate restore
Fixes from the code review:
- #1 Wire mustChangePassword: dashboard layout redirects to a new /change-password
  page + /api/account/change-password (verifies current pw, re-hashes, clears the
  flag, refreshes the session). Provisioned admins can no longer keep the default.
- #2 Assert NEXTAUTH_SECRET in production (not during build); set it on authOptions.
- #3 Backup page now server-gated to admins (split into server page + client panel),
  matching the Updates page.
- #4 Restore validates input: strict zod schema for the users table (known fields,
  role enum) + array checks for the rest; returns generic errors instead of String(err).

No version bump/changelog — left for you to fold into the next release (you're
editing those live). Not pushed, not deployed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-15 23:59:39 -05:00
c5bf108cb9 v0.12.0 — REST API + personal access tokens
A bidirectional API so other apps (Home Assistant, phone shortcuts, scripts,
and the coming MCP server) can read and update the homestead.

- ApiToken model (sha256-hashed, scoped, with prefix/lastUsed/expiry/revoke)
- authenticateRequest() accepts EITHER a NextAuth cookie session OR a Bearer
  PAT; cookie sessions get full access, tokens are limited to their scopes
  (write implies read; resource and global wildcards). ApiError + handleApiError
- Shared service layer (plants/tasks/locations/plant-types) reused by every
  endpoint and, later, the MCP server — logic lives once
- /api/v1: plants (read + add log), plant-types, locations, tasks (read/create/
  complete), and a whoami/discovery root
- Settings → API tokens: create with per-resource read/write checkboxes, raw
  token shown once, revoke; tokens added to backup/restore
- Pure tests for scope matching + token hashing; verified end-to-end (401/403/
  201, lastUsedAt) against a running server

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-15 23:55:58 -05:00
cdb21ed58a v0.11.0 — Plant types: the reusable "kind" record
A rich-but-all-optional reference record per kind of plant (care, sun, water,
bloom & harvest windows, toxic-to-pets, edible parts, spacing), distinct from a
specific planting or a group.

- PlantType model + optional Plant.plantTypeId; migration + idempotent backfill
  that seeds 247 kinds from the built-in plant library and links plantings by
  species/common name (wired into the deploy entrypoint)
- /api/plant-types CRUD; new "Plant types" section (browse by category, edit a
  kind, see every spot you've planted it)
- New plants auto-link to their type on create; plant detail shows "More about…"
- PlantType added to backup/restore; bump APP_VERSION 0.11.0 + changelog

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-15 23:46:07 -05:00
9c0312676a v0.10.0 — Location spine: garden moved onto a shared place tree
Completes the Location feature (schema + migration landed earlier under 98cabc5).

- Hierarchical Location model is the shared spine; unlimited nesting
- Garden add/edit now picks a reusable Location (inline create) instead of
  freeform text; garden groups By Location off the real tree
- Dual-write keeps legacy Plant.zone in sync with location.name (Release A)
- /api/locations CRUD + /api/locations/[id]/log (logs a location + its sub-locations)
- Location tree pure-core (buildTree/computePath/descendantIds) with tests
- Location added to backup/restore export
- Bump APP_VERSION 0.10.0 + plain-English changelog entry

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-15 23:36:54 -05:00
6f8fe9a798 ignore self-update runtime log
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-15 22:48:47 -05:00
98cabc514d v0.9.1 — Self-update: 403 on trigger mismatch + reliability
webhook returns 200 even when a trigger rule isn't satisfied, which would let
the app's res.ok check falsely report success if the secret drifted. Set
trigger-rule-mismatch-http-response-code: 403 so unauthorized triggers are
clearly rejected.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-15 22:44:36 -05:00
4e02339f59 updater: fix webhook secret template (backtick literal, not escaped quotes)
The -template parser is Go text/template; JSON-escaped \" broke the action.
Backtick raw-string literal is valid inside the JSON string and parses cleanly.
Config-only (mounted + hotreload) — no app rebuild.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-15 22:41:28 -05:00
a4a6fe4c9b updater: mark /appdata as safe.directory before git ops
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-15 22:22:32 -05:00
1c66dbd481 v0.9.0 — One-click self-update (homegrown, no OTM)
Add an admin 'Pull & rebuild' button (Settings → Updates). It POSTs an
admin-gated route that signals a privileged 'updater' sidecar (adnanh/webhook +
docker socket) over the internal network with a shared secret; the sidecar runs
'git fetch && reset --hard origin/master && docker compose up -d --build app'
detached. The UI polls /api/version until the rebuilt app returns on the new
version, then reloads.

Secret matching uses webhook -template + getenv so UPDATER_SECRET stays out of
the repo (host .env only). No request data reaches the shell — the command is
fixed in updater/update.sh.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-15 22:20:48 -05:00
42cd7a7b4d v0.8.0 — Update-available detection (version chip + changelog)
Footer becomes a changelog chip and shows an 'Update available' badge when a
newer APP_VERSION exists upstream. Detection reads src/lib/version.ts from the
Gitea default branch (dms model) and compares — self-contained, no OTM control
plane. Adds src/lib/update-check.ts and GET /api/version (also a running-version
probe for the upcoming one-click rebuild).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-15 22:12:18 -05:00
2e0931343f v0.7.0 — Suggestions module via @otm/account-panel
Wire the shared Gitea-backed suggestions panel: page, list/create + comments +
upload API routes, sidebar link. Suggestions file as issues on bonna61/Moonbase;
screenshot uploads persist via a mounted volume. Mirrors the FMB wiring.

Secrets (NEXTAUTH_SECRET, GITEA_TOKEN) moved out of docker-compose.yml to an
interpolated gitignored .env on the host, per CLAUDE.md (never commit the token).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-15 22:03:47 -05:00
1f5aa001a8 v0.6.0 — Backup & Restore page; install netcat for Postgres-wait
Version the backup/restore feature that merged in unversioned, and add
netcat-openbsd to the bookworm-slim runtime so the new entrypoint Postgres
readiness check (nc -z postgres 5432) works instead of looping forever.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-15 21:52:15 -05:00
Bonna Moon
c12e607be7 Add Backup & Restore page (zip download + drag-drop upload) 2026-06-15 21:47:49 -05:00
Bonna Moon
9ec4457552 Add db:backup and db:restore npm scripts 2026-06-15 21:45:09 -05:00
Bonna Moon
4bc5ddc77b Wait for Postgres ready before running migrations 2026-06-15 21:39:21 -05:00
6603717cbb v0.5.2 — Fix Docker deploy on NAS (glibc base, openssl, root, full deps)
The NAS container was crash-looping: npx pulled Prisma 7.8.0 (which rejects
url in the datasource), and the alpine + non-root + standalone setup couldn't
detect openssl or write the migration engine. Switch to the FMB-proven runtime
(node:20-bookworm-slim + openssl, run as root, full node_modules, next start)
so the local pinned Prisma 5.22 CLI runs and migrations apply cleanly.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-15 21:36:30 -05:00
Bonna Moon
1ebfb06e68 Fix Docker entrypoint using pinned local Prisma CLI
npx prisma was downloading Prisma CLI v7.8.0 which dropped the
url = env("DATABASE_URL") schema syntax. Use the project's own
installed Prisma CLI from node_modules instead, copied from the
builder stage.
2026-06-15 21:09:08 -05:00
Bonna Moon
175ebecdc8 Add public dir so Docker COPY doesn't fail
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-15 21:00:24 -05:00
Bonna Moon
4245232834 Fix TS errors blocking Docker build; docker-compose builds locally
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-15 20:56:37 -05:00
Bonna Moon
04dec2a198 v0.5.1 — Reminders, plant groups, location views, Wikipedia photos, Docker deploy
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-15 20:53:03 -05:00
Bonna Moon
e3f6a8ec92 v0.2.3 — Fix new plant categories rejected by API validation 2026-06-15 17:45:34 -05:00
Bonna Moon
f27838745c v0.2.2 — Fix add plant form (simplify, remove react-hook-form) 2026-06-15 17:41:06 -05:00
Bonna Moon
ed4a50dae9 v0.2.1 — Fix add plant button not submitting 2026-06-15 17:36:46 -05:00
Bonna Moon
5938c6346e v0.2.0 — Plant autocomplete + annual/perennial flower categories 2026-06-15 17:07:26 -05:00
Bonna Moon
78728963f4 v0.1.1 — Garden: edit and delete plants 2026-06-15 16:58:03 -05:00