Files
famapp/docs/tasks/75-garden-dashboard.md
ginnoir 2fd0677c5f feat: add garden module infrastructure (task 70)
- 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)
2026-06-01 19:23:19 -05:00

4.6 KiB
Raw Permalink Blame History

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

  • 7074 (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 7173):

  • { 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 logCare action + revalidates — no navigation).
  • Truncate at 10 rows; "View all" link to /garden.
  • Rows with next_due_at within daysAhead days 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:

  1. Log in as the seeded user.
  2. Create container "Living Room Shelf".
  3. Create plant "Pothos" in that container (manual entry, no species lookup).
  4. Add watering schedule: every 7 days.
  5. Log care: watered.
  6. Verify schedule next_due_at updates to ~7 days from now.
  7. Confirm plant appears grouped under "Living Room Shelf" on /garden.
  8. Add garden.care-due widget to the default dashboard.
  9. 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-due shows overdue plants sorted by urgency; inline log button works.
  • garden.overview shows 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.