Garden objects backend: polymorphic CRUD + /full endpoint #10

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

Part of epic #20 · Design: DESIGN.md

Context

Garden objects are the things placed on the field: beds, grow bags, containers, in-ground plots, trees, paths, structures. They live in one polymorphic table (kind column + props JSON for kind-specific extras) since placement/geometry behavior is identical across kinds. This issue implements their CRUD plus GET /gardens/:id/full — the one-shot payload the editor loads.

Scope

  • internal/store/objects.go + internal/service/objects.go following the #7 conventions (actor param, requireGardenRole(editor) for mutations, version guard).
  • Validation: kind in the DESIGN.md enum; shape rect|circle (reject polygon for now with a clear "not yet supported"); positive dimensions; object roughly within garden bounds (loose — allow partial overhang); rotation_deg normalized to [0,360); plantable defaults by kind (bed/grow_bag/container/in_ground → true; tree/path/structure → false) but is overridable.
  • POST /api/v1/gardens/:id/objects, PATCH /api/v1/objects/:id (partial: any of name/x/y/width/height/rotation/z_index/color/props/notes/plantable + required version), DELETE /api/v1/objects/:id (cascades plantings — FK ON DELETE CASCADE from #1's schema).
  • GET /api/v1/gardens/:id/full (any role): {garden, objects[], plantings[], plants[]} — plantings filtered to removed_at IS NULL, plants = referenced ones only. Arrays will be empty until #12/#14; define the response shape completely now so the frontend types once.
  • Service tests: CRUD, validation rejects, version conflict, viewer-role mutation denial (owner-only until #16 — test with a second user).

Out of scope

  • Plantings CRUD (#14). Frontend (#11). Polygon shapes (post-v1).

Key files & patterns

  • Table/columns: DESIGN.md § Domain model (garden_objects); conventions from #7.

Dependencies

Blocked by #7.

Acceptance criteria

  • curl: create a bed, move it (PATCH x/y), rotate it, delete it; stale version → 409 + current row.
  • /full returns the documented shape with coherent data; a non-owner (pre-#16) gets 404.
  • go test ./internal/service/... green including validation cases.
Part of epic #20 · Design: [DESIGN.md](https://gitea.stevedudenhoeffer.com/steve/pansy/src/branch/main/DESIGN.md) ## Context Garden objects are the things placed on the field: beds, grow bags, containers, in-ground plots, trees, paths, structures. They live in **one polymorphic table** (`kind` column + `props` JSON for kind-specific extras) since placement/geometry behavior is identical across kinds. This issue implements their CRUD plus `GET /gardens/:id/full` — the one-shot payload the editor loads. ## Scope - [ ] `internal/store/objects.go` + `internal/service/objects.go` following the #7 conventions (actor param, `requireGardenRole(editor)` for mutations, version guard). - [ ] Validation: `kind` in the DESIGN.md enum; `shape` rect|circle (reject polygon for now with a clear "not yet supported"); positive dimensions; object roughly within garden bounds (loose — allow partial overhang); `rotation_deg` normalized to [0,360); `plantable` defaults by kind (bed/grow_bag/container/in_ground → true; tree/path/structure → false) but is overridable. - [ ] `POST /api/v1/gardens/:id/objects`, `PATCH /api/v1/objects/:id` (partial: any of name/x/y/width/height/rotation/z_index/color/props/notes/plantable + required `version`), `DELETE /api/v1/objects/:id` (cascades plantings — FK ON DELETE CASCADE from #1's schema). - [ ] `GET /api/v1/gardens/:id/full` (any role): `{garden, objects[], plantings[], plants[]}` — plantings filtered to `removed_at IS NULL`, plants = referenced ones only. Arrays will be empty until #12/#14; define the response shape completely now so the frontend types once. - [ ] Service tests: CRUD, validation rejects, version conflict, viewer-role mutation denial (owner-only until #16 — test with a second user). ## Out of scope - Plantings CRUD (#14). Frontend (#11). Polygon shapes (post-v1). ## Key files & patterns - Table/columns: `DESIGN.md` § Domain model (`garden_objects`); conventions from #7. ## Dependencies Blocked by #7. ## Acceptance criteria - curl: create a bed, move it (PATCH x/y), rotate it, delete it; stale version → 409 + current row. - `/full` returns the documented shape with coherent data; a non-owner (pre-#16) gets 404. - `go test ./internal/service/...` green including validation cases.
steve added the backenddrawing labels 2026-07-18 18:17:10 +00:00
steve closed this issue 2026-07-18 23:48:40 +00:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: steve/pansy#10