Backend: embed buckets in the Scenario item representation #64

Closed
opened 2026-07-05 00:04:54 +02:00 by myrmidex · 0 comments
Owner

Context

Split out of #53 (frontend view-scenario). #53 needs to render a scenario's buckets, but the API has no clean way to fetch this scenario's buckets: GET /api/buckets returns all of a user's buckets across every scenario. A ?scenario= query filter (wrong for a resource-oriented API) and client-side filtering (papering over a missing capability) were both rejected. Buckets belong to the scenario, so they belong in the scenario's representation.

This is a backend-only serialization change and must land before #53.

Scope

GET /api/scenarios/{id} returns the scenario with its buckets nested inline, so the frontend fetches one resource.

  • Add the inverse OneToMany side Scenario::$buckets (mappedBy Bucket.scenario, inversedBy on the Bucket side). Mapping-only — no migration (the FK already exists on bucket.scenario_id).
  • Introduce the project's first serialization groups. Scenario item op embeds buckets; the collection op (GET /api/scenarios) does NOT (stays lean — names only).
  • Nested buckets expose: name, type, priority, sortOrder, allocationType, allocationValue, startingAmount, bufferMultiplier.
  • Buckets ordered by sortOrder ASC.
  • A scenario with no buckets serializes an empty buckets array (no error).
  • Drop the owner IRI from the Scenario item representation (currently exposed implicitly; server-set, never client-relevant).

Out of scope

  • Removing the flat GET /api/buckets collection (kept — #54-#59 use the Bucket resource for writes).
  • Any frontend work (that's #53).

Testing (TDD)

  • Characterization tests first: pin current Scenario item fields and current Bucket item+collection fields before introducing groups, so the group flip can't silently drop a field. (These are born-green baselines.)
  • Then: entity round-trip for the inverse relation, functional tests for the nested representation (fields, ordering, empty case, collection-does-not-embed), and owner-scoping regression pins (nested buckets contain only this scenario's buckets; a foreign scenario still 404s with no bucket leak).

Notes

  • cache:clear (dev + test) required after the entity/groups change — API Platform caches serialization metadata.
  • Confirm the migration diff is empty; a non-empty diff means the relation was miswired.

Depends on: nothing. Blocks: #53.

## Context Split out of #53 (frontend view-scenario). #53 needs to render a scenario's buckets, but the API has no clean way to fetch *this scenario's* buckets: `GET /api/buckets` returns all of a user's buckets across every scenario. A `?scenario=` query filter (wrong for a resource-oriented API) and client-side filtering (papering over a missing capability) were both rejected. Buckets belong to the scenario, so they belong in the scenario's representation. This is a backend-only serialization change and must land **before** #53. ## Scope `GET /api/scenarios/{id}` returns the scenario **with its buckets nested inline**, so the frontend fetches one resource. - Add the inverse `OneToMany` side `Scenario::$buckets` (mappedBy `Bucket.scenario`, `inversedBy` on the Bucket side). **Mapping-only — no migration** (the FK already exists on `bucket.scenario_id`). - Introduce the project's first serialization groups. Scenario **item** op embeds `buckets`; the **collection** op (`GET /api/scenarios`) does NOT (stays lean — names only). - Nested buckets expose: `name, type, priority, sortOrder, allocationType, allocationValue, startingAmount, bufferMultiplier`. - Buckets ordered by `sortOrder ASC`. - A scenario with no buckets serializes an empty `buckets` array (no error). - **Drop the `owner` IRI** from the Scenario item representation (currently exposed implicitly; server-set, never client-relevant). ## Out of scope - Removing the flat `GET /api/buckets` collection (kept — #54-#59 use the Bucket resource for writes). - Any frontend work (that's #53). ## Testing (TDD) - Characterization tests first: pin current Scenario item fields and current Bucket item+collection fields **before** introducing groups, so the group flip can't silently drop a field. (These are born-green baselines.) - Then: entity round-trip for the inverse relation, functional tests for the nested representation (fields, ordering, empty case, collection-does-not-embed), and owner-scoping regression pins (nested buckets contain only this scenario's buckets; a foreign scenario still 404s with no bucket leak). ## Notes - `cache:clear` (dev + test) required after the entity/groups change — API Platform caches serialization metadata. - Confirm the migration diff is **empty**; a non-empty diff means the relation was miswired. Depends on: nothing. Blocks: #53.
myrmidex added this to the v0.3.0 milestone 2026-07-05 00:04:54 +02:00
myrmidex added the
enhancement
label 2026-07-05 00:04:55 +02:00
myrmidex self-assigned this 2026-07-05 00:04:55 +02:00
myrmidex added a new dependency 2026-07-05 00:05:08 +02:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Reference: lvl0/buckets#64
No description provided.