Plant catalog backend: CRUD + seeded built-ins #12

Closed
opened 2026-07-18 18:17:48 +00:00 by steve · 0 comments
Owner

Part of epic #20 · Design: DESIGN.md

Context

The plant catalog backs every planting: name, category, mature spacing (cm — drives derived plop counts), display color, emoji icon. Built-in plants (owner_id NULL) ship seeded and read-only; users create their own or clone built-ins to customize. Users see built-ins + their own rows.

Scope

  • Migration 0002_seed_plants.sql: ~30 built-ins covering common garden staples with sensible spacing/colors/emoji — suggested set: garlic 🧄15cm, onion 🧅10, basil 🌿25, cilantro 🌿10, dill 🌿15, parsley 🌿15, oregano 🌿25, thyme 🌿20, rosemary 🌿45, sage 🌿45, mint 🌿30, bush bean 🫘 10, pole bean 🫘15, pea 🫛 8, tomato 🍅60, pepper 🌶️45, cucumber 🥒30, zucchini 🥒60, winter squash 🎃90, carrot 🥕 8, radish 🌱 5, beet 🌱10, lettuce 🥬20, spinach 🥬10, kale 🥬45, broccoli 🥦45, cabbage 🥬45, potato 🥔30, corn 🌽25, strawberry 🍓30, sunflower 🌻45, marigold 🌼25. Adjust freely; categories per the DESIGN.md enum.
  • internal/store/plants.go + internal/service/plants.go (conventions from #7): List (built-ins + actor's own), Create, Update/Delete own rows only — built-ins return ErrForbidden. Validation: name non-empty, spacing_cm > 0, hex color, category in enum, icon non-empty (emoji as plain string).
  • API: GET,POST /api/v1/plants, PATCH,DELETE /api/v1/plants/:id (version guard as usual). "Clone" is client-side: POST a copy — no special endpoint.
  • DELETE of a plant referenced by plantings: block with a clear 409/400 error (simplest safe choice; note it in the handler).
  • Service tests: visibility (user A doesn't see user B's plants), built-in immutability, validation.

Out of scope

  • Frontend (#13). Plantings (#14). Richer horticulture data (sun/water/companion info — post-v1 columns).

Key files & patterns

  • Table: DESIGN.md § Domain model (plants). Migration runner from #1.

Dependencies

Blocked by #7 (service conventions; schema from #1).

Acceptance criteria

  • Fresh DB migrates and GET /plants returns the seeded set; re-running migrations doesn't duplicate them.
  • Create/edit/delete own plant works; PATCH on a built-in → 403; user B's custom plants invisible to user A.
  • Deleting a plant in use is refused with a clear error.
  • go test ./internal/service/... green.
Part of epic #20 · Design: [DESIGN.md](https://gitea.stevedudenhoeffer.com/steve/pansy/src/branch/main/DESIGN.md) ## Context The plant catalog backs every planting: name, category, mature spacing (cm — drives derived plop counts), display color, emoji icon. Built-in plants (`owner_id NULL`) ship seeded and read-only; users create their own or clone built-ins to customize. Users see built-ins + their own rows. ## Scope - [ ] Migration `0002_seed_plants.sql`: ~30 built-ins covering common garden staples with sensible spacing/colors/emoji — suggested set: garlic 🧄15cm, onion 🧅10, basil 🌿25, cilantro 🌿10, dill 🌿15, parsley 🌿15, oregano 🌿25, thyme 🌿20, rosemary 🌿45, sage 🌿45, mint 🌿30, bush bean 🫘 10, pole bean 🫘15, pea 🫛 8, tomato 🍅60, pepper 🌶️45, cucumber 🥒30, zucchini 🥒60, winter squash 🎃90, carrot 🥕 8, radish 🌱 5, beet 🌱10, lettuce 🥬20, spinach 🥬10, kale 🥬45, broccoli 🥦45, cabbage 🥬45, potato 🥔30, corn 🌽25, strawberry 🍓30, sunflower 🌻45, marigold 🌼25. Adjust freely; categories per the DESIGN.md enum. - [ ] `internal/store/plants.go` + `internal/service/plants.go` (conventions from #7): List (built-ins + actor's own), Create, Update/Delete **own rows only** — built-ins return `ErrForbidden`. Validation: name non-empty, `spacing_cm > 0`, hex color, category in enum, icon non-empty (emoji as plain string). - [ ] API: `GET,POST /api/v1/plants`, `PATCH,DELETE /api/v1/plants/:id` (version guard as usual). "Clone" is client-side: POST a copy — no special endpoint. - [ ] DELETE of a plant referenced by plantings: block with a clear 409/400 error (simplest safe choice; note it in the handler). - [ ] Service tests: visibility (user A doesn't see user B's plants), built-in immutability, validation. ## Out of scope - Frontend (#13). Plantings (#14). Richer horticulture data (sun/water/companion info — post-v1 columns). ## Key files & patterns - Table: `DESIGN.md` § Domain model (`plants`). Migration runner from #1. ## Dependencies Blocked by #7 (service conventions; schema from #1). ## Acceptance criteria - Fresh DB migrates and `GET /plants` returns the seeded set; re-running migrations doesn't duplicate them. - Create/edit/delete own plant works; PATCH on a built-in → 403; user B's custom plants invisible to user A. - Deleting a plant in use is refused with a clear error. - `go test ./internal/service/...` green.
steve added the backendplants labels 2026-07-18 18:17:48 +00:00
steve closed this issue 2026-07-19 01:48:23 +00:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: steve/pansy#12