- Add MinIO service to compose.yaml with named volume - Add generic /api/uploads POST+GET route with auth, 5 MB, image/* guards - Add src/lib/minio.ts singleton client with ensureBucket helper - Add garden Drizzle schema: containers, plants, care_logs, care_schedules, species_cache - Register garden module in src/modules/index.ts and src/lib/db.ts - Apply migration 0015_garden_schema.sql - Add MINIO_* and PERENUAL_API_KEY to .env.example - Add task briefs 70-75 for the full garden feature arc - Add uploads.spec.ts E2E test (RED → GREEN on route auth guard)
4.6 KiB
75 — Garden dashboard, widgets, and manifest completion
Goal
Complete the garden module: full manifest registration, two dashboard widgets, search integration, quick-add polish, and a Playwright happy-path test.
Depends on
- 70–74 (all previous garden tasks)
Scope
Manifest completion (src/modules/garden/manifest.tsx)
Replace the task-70 stub with the full manifest.
Entities:
entities: [
{
type: "garden.container",
label: { singular: "Container", plural: "Containers" },
share: { canShare: true, defaultCapabilities: ["read"] },
search: { search: searchContainers },
resolveUrl: (id) => `/garden/containers/${id}`,
loadForShare: loadContainerForShare,
renderSharedView: ...,
renderActivity: ...,
},
{
type: "garden.plant",
label: { singular: "Plant", plural: "Plants" },
share: { canShare: true, defaultCapabilities: ["read"] },
search: { search: searchPlants },
resolveUrl: (id) => `/garden/plants/${id}`,
loadForShare: loadPlantForShare,
renderSharedView: ...,
renderActivity: ...,
},
]
garden.schedule is internal (reminders only) — not registered as a shareable or searchable entity.
Quick adds (consolidate from tasks 71–73):
{ id: "garden.add-plant", label: "Add plant", icon: "leaf", url: "/garden/plants/new" }{ id: "garden.add-container", label: "Add container", icon: "box", url: "/garden/containers/new" }{ id: "garden.log-care", label: "Log plant care", icon: "droplets", url: "/garden?logCare=1" }
Nav: { href: "/garden", label: "Garden", icon: "sprout" }.
Widget 1: garden.care-due
Title: "Plants needing care" | Category: "Garden"
Default size: { w: 4, h: 4 } | Min size: { w: 3, h: 2 }
Config schema:
z.object({
containerIds: z.union([z.literal("all"), z.array(z.string().uuid())]),
daysAhead: z.number().int().min(0).max(30).default(0),
});
Default config: { containerIds: "all", daysAhead: 0 }.
resolveConfigOptions: returns { containers: [{ id, name }] }.
Render:
- Empty state if nothing is due: "All plants are on schedule."
- Otherwise: compact list sorted by days overdue. Each row: plant name, care type icon, urgency badge ("X days overdue" / "due today"), inline "Log care" button (calls
logCareaction + revalidates — no navigation). - Truncate at 10 rows; "View all" link to
/garden. - Rows with
next_due_atwithindaysAheaddays show as upcoming in a lighter style below overdue rows.
Widget 2: garden.overview
Title: "Garden overview" | Category: "Garden"
Default size: { w: 3, h: 2 } | Min size: { w: 2, h: 2 }
Config schema: z.object({}).
Render:
- Stat row: total plants, total containers, overdue care count.
- "Next care" line: "Next: water [Plant] in N days" / "today" / "overdue".
- Link to
/garden.
Widget component (src/modules/garden/components/plant-widget.tsx)
Server component implementing both widgets, following the pattern in src/modules/lists/components/list-widget.tsx.
Search adapters
Implement searchContainers and searchPlants using ilike on name fields, returning SearchResult[]. Both appear in the command palette.
Notification body improvement (optional)
If tickReminders in src/modules/_core/reminders.ts can be extended without structural changes — add a registry of entity-type resolvers and register "garden.schedule" to resolve to "Time to water [plant name]". If it requires core changes, defer and note as known limitation.
Playwright E2E test (tests/garden.spec.ts)
Happy path:
- Log in as the seeded user.
- Create container "Living Room Shelf".
- Create plant "Pothos" in that container (manual entry, no species lookup).
- Add watering schedule: every 7 days.
- Log care: watered.
- Verify schedule
next_due_atupdates to ~7 days from now. - Confirm plant appears grouped under "Living Room Shelf" on
/garden. - Add
garden.care-duewidget to the default dashboard. - Confirm no overdue items (just watered).
Out of scope
- Health trend charts.
- Weather-based watering adjustments.
- Social/community features.
Acceptance criteria
- Both widgets register and appear in the widget picker.
garden.care-dueshows overdue plants sorted by urgency; inline log button works.garden.overviewshows correct counts.- Both entities appear in command palette search.
- All three quick-adds appear in the
+sheet. - Garden nav link appears in sidebar and bottom nav.
- Playwright happy-path test passes.