v0.23.0 — Pantry: structured USED pull logs + move to /api/v1 service layer

Pantry now runs on the v1 API like Inventory/Animals: service layer in
src/lib/services/pantry.ts, pure logic + tests in src/lib/pantry/core.ts,
thin routes at /api/v1/pantry/* riding the items:* scopes. Pulls write
ItemLog type USED with a structured amount (queryable consumption).
Bulk-use runs its reads inside the transaction, accumulates repeated
pulls, and reports skipped items instead of silently dropping them —
the Pull dialog now surfaces those by name. Old /api/pantry routes
deleted.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Bonna Moon
2026-07-06 00:14:53 -05:00
parent 8f77b7c453
commit 25b1ba9aeb
27 changed files with 723 additions and 453 deletions

View File

@@ -138,7 +138,7 @@ export function PantryItemDialog({ item, locations, plants, onSuccess }: Props)
// Load catalog on open (for name autocomplete suggestions)
useEffect(() => {
if (!open) return;
fetch("/api/pantry/catalog")
fetch("/api/v1/pantry/catalog")
.then(r => r.json())
.then(setCatalog)
.catch(() => {});
@@ -160,7 +160,7 @@ export function PantryItemDialog({ item, locations, plants, onSuccess }: Props)
clearTimeout(debounceRef.current);
if (val.length < 2) { setNameSuggestions([]); setShowDropdown(false); return; }
debounceRef.current = setTimeout(async () => {
const res = await fetch(`/api/pantry/catalog?q=${encodeURIComponent(val)}`);
const res = await fetch(`/api/v1/pantry/catalog?q=${encodeURIComponent(val)}`);
if (!res.ok) return;
const data: CatalogData = await res.json();
setNameSuggestions(data.suggestions.slice(0, 6));
@@ -232,7 +232,7 @@ export function PantryItemDialog({ item, locations, plants, onSuccess }: Props)
kind: "CONSUMABLE",
tags,
};
const res = await fetch(item ? `/api/pantry/${item.id}` : "/api/pantry", {
const res = await fetch(item ? `/api/v1/pantry/${item.id}` : "/api/v1/pantry", {
method: item ? "PATCH" : "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(body),