- 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)
3.2 KiB
3.2 KiB
74 — Garden integrations (calendar + lists)
Goal
Wire the garden module into the two existing coordination modules:
- Calendar: schedule a plant care event on the household calendar from within a care schedule row.
- Lists: push all overdue care tasks to the household task list in one tap.
Depends on
- 73 (care schedules + overdue queries)
- 10 (calendar module —
createEvent) - 11 (lists module —
addItem)
Scope
Calendar integration
Server action (src/modules/garden/server/actions.ts)
scheduleOnCalendar(input: { scheduleId, calendarId, reminderMinutesBefore? }):
- Look up the schedule + plant; household check.
startAt=next_due_at(reject with user-facing error if null).endAt=startAt + 30 min;allDay = false.- Title convention:
"Water ${plant.name}"/"Fertilize ${plant.name}"/"Repot ${plant.name}"/"${careType} — ${plant.name}"for other types. - Notes:
"Scheduled from garden. Next due: ${next_due_at.toLocaleDateString()}". - Call
createCalendarEvent(...)from the bridge below.
Bridge file (src/modules/garden/server/calendar-bridge.ts)
export { createEvent as createCalendarEvent } from "@/modules/calendar/server/actions";
export { listCalendars } from "@/modules/calendar/server/queries";
This keeps the cross-module dependency explicit and swappable without touching _core.
UI
In care-schedule-editor.tsx, add an "Add to calendar" button per schedule row. Clicking it opens a popover with: calendar select (from listCalendars) + optional reminder-minutes input + "Schedule" button. Show a success toast linking to /calendar.
Lists integration
Server action (src/modules/garden/server/actions.ts)
pushOverdueToTaskList(): Promise<{ added: number }>:
- Call
getOverduePlants(householdId). - Find the household default task list via the bridge below.
- For each overdue
(plant, schedule)pair insert a list item:text: same title convention as the calendar integration.notes:"Overdue by ${daysOverdue} day(s)".dueAt:schedule.next_due_at.
- Skip pairs where an identical
textitem already exists in the list (prevent duplicates). - Return
{ added: N }.
Bridge file (src/modules/garden/server/lists-bridge.ts)
export { addItem as addListItem } from "@/modules/lists/server/actions";
export { listLists } from "@/modules/lists/server/queries";
UI
Add an "Add overdue to task list" button to the /garden page header (available before the dashboard widget in task 75). Shows a toast: "Added N tasks to your task list." If N = 0, toast says "No overdue care tasks."
Out of scope
- Bi-directional sync (checking off a list item does not mark the plant as cared-for).
- Recurring calendar events (garden creates single events only).
Acceptance criteria
- "Add to calendar" creates a calendar event visible at
/calendarwith the correct title. - "Add overdue to task list" pushes one item per overdue schedule, skips existing duplicates.
- Items appear in the task list at
/lists. - Both actions enforce household scope.
- Both are graceful no-ops when nothing is overdue / due.