8.4 KiB
NEO-60 — Implementation plan
Story reference
| Field | Value |
|---|---|
| Key | NEO-60 |
| Title | E3.M1: GET world resource-node-definitions + Bruno |
| Linear | https://linear.app/neon-sprawl/issue/NEO-60/e3m1-get-world-resource-node-definitions-bruno |
| Module | E3.M1 — ResourceNodeAndGatherLoop · Epic 3 Slice 2 · backlog E3M1-04 |
| Branch | NEO-60-e3m1-get-world-resource-node-definitions-bruno |
| Precursor | NEO-59 — IResourceNodeDefinitionRegistry + DI (Done on main) |
| Pattern | NEO-53 — GET /game/world/item-definitions |
Kickoff clarifications
| Topic | Question | Agent recommendation | Answer |
|---|---|---|---|
| Yield projection | Nested yield object vs flat itemId/quantity on the row? |
Nested yield: { itemId, quantity } — mirrors catalog split (node def + yield table) and matches NEO-59 registry shape; room for multi-yield later. |
User: nested yield object. |
| Row id JSON name | id vs nodeDefId? |
id — same HTTP convention as item/skill definition endpoints (NEO-53 / NEO-36). |
User: id. |
| Manual QA doc | Add docs/manual-qa/NEO-60.md? |
Yes — user-visible HTTP surface; mirror NEO-53. | User: yes. |
Goal, scope, and out-of-scope
Goal: Expose a stable, read-only JSON endpoint that returns all loaded prototype resource-node definitions (with yield summary) for dev tooling, Bruno, manual QA, and future client/codegen, backed by IResourceNodeDefinitionRegistry without duplicating catalog truth outside the server.
In scope (from Linear + E3M1-04):
GET /game/world/resource-node-definitionswith versioned envelope (schemaVersion1,nodesarray).- Each row:
id,displayName,gatherLens,maxGathers, nestedyieldwithitemIdandquantity(camelCase JSON). - Nodes ordered by
idordinal, matchingGetDefinitionsInIdOrder(). - Bruno folder
bruno/neon-sprawl-server/resource-node-definitions/. docs/manual-qa/NEO-60.md.server/README.mdsection.- API integration tests (AAA).
Out of scope (from Linear + backlog):
- Per-instance remaining capacity / depletion state (NEO-61).
- Gather engine, inventory mutation, interact wiring (NEO-62+).
- Client HUD.
Acceptance criteria checklist
- GET returns all four prototype defs with
schemaVersion1 and yield summary fields needed for QA. - Bruno happy path documented and runnable against dev server.
- Automated API tests (AAA) assert four ids in order and spot-check node + yield metadata.
Technical approach
-
Route:
GET /game/world/resource-node-definitions— parameterless read; injectIResourceNodeDefinitionRegistryonly (notResourceNodeCatalog). -
Response shape: Top-level
schemaVersion(ResourceNodeDefinitionsListResponse.CurrentSchemaVersion= 1) plusnodesarray. Each row maps fromResourceNodeDefRow+ joinedResourceYieldRowviaTryGetYield:id←NodeDefId,displayName,gatherLens,maxGathers,yield←{ itemId, quantity }. Prototype catalog guarantees one yield per node at load time; ifTryGetYieldfails for an enumerated def, treat as programmer error (should not occur post-NEO-58 validation). -
Ordering: Build list from
registry.GetDefinitionsInIdOrder(). Tests assert exact id sequence (ordinal):prototype_bio_mat_gamma,prototype_resource_node_alpha,prototype_subsurface_vein_beta,prototype_urban_bulk_delta. -
Implementation: New
ResourceNodeDefinitionsWorldApi+ResourceNodeDefinitionsListDtos.csinGame/Gathering/(mirrorItemDefinitionsWorldApi). Wireapp.MapResourceNodeDefinitionsWorldApi()fromProgram.csnext toMapItemDefinitionsWorldApi(). -
Bruno:
bruno/neon-sprawl-server/resource-node-definitions/withGet resource node definitions.bru+folder.bru. Tests: 200, JSON,schemaVersion1,nodes.length === 4, ascending id order, frozen four ids in registry order, spot-checkprototype_resource_node_alpha(gatherLensconsumer_salvage,maxGathers10,yield.itemIdscrap_metal_bulk,yield.quantity1) andprototype_urban_bulk_delta(yield.quantity5). -
Docs:
docs/manual-qa/NEO-60.md(mirror NEO-53). Updateserver/README.mdresource-node section with GET + curl. Update E3_M1 Related implementation slices and documentation_and_implementation_alignment.md E3.M1 row when landed. Flip E3M1-04 acceptance checkboxes in E3M1-prototype-backlog.md.
Files to add
| Path | Purpose |
|---|---|
server/NeonSprawl.Server/Game/Gathering/ResourceNodeDefinitionsWorldApi.cs |
Map* extension registering GET route; maps registry → JSON (node + nested yield). |
server/NeonSprawl.Server/Game/Gathering/ResourceNodeDefinitionsListDtos.cs |
Versioned response + row/yield DTOs for JSON serialization. |
server/NeonSprawl.Server.Tests/Game/Gathering/ResourceNodeDefinitionsWorldApiTests.cs |
HTTP integration: 200, schema v1, four ids in order, spot-check rows + yields. |
bruno/neon-sprawl-server/resource-node-definitions/Get resource node definitions.bru |
Manual / Bruno verification against dev server. |
bruno/neon-sprawl-server/resource-node-definitions/folder.bru |
Bruno folder metadata (match item-definitions). |
docs/manual-qa/NEO-60.md |
Checklist: start server, curl GET, confirm four ids + spot-check yield. |
Files to modify
| Path | Rationale |
|---|---|
server/NeonSprawl.Server/Program.cs |
Register MapResourceNodeDefinitionsWorldApi() alongside other game world APIs. |
server/README.md |
Document GET /game/world/resource-node-definitions, curl example, links to plan/manual QA/Bruno. |
docs/decomposition/modules/E3_M1_ResourceNodeAndGatherLoop.md |
Related implementation slices — HTTP read model bullet (NEO-60). |
docs/decomposition/modules/documentation_and_implementation_alignment.md |
E3.M1 row — note NEO-60 HTTP projection when landed. |
docs/plans/E3M1-prototype-backlog.md |
E3M1-04 acceptance checkboxes when landed. |
Tests
| Test file | What it covers |
|---|---|
server/NeonSprawl.Server.Tests/Game/Gathering/ResourceNodeDefinitionsWorldApiTests.cs |
Integration: GET /game/world/resource-node-definitions via InMemoryWebApplicationFactory; ReadFromJsonAsync; assert schemaVersion 1; nodes count 4; ordered id list equals frozen four (ordinal); spot-check prototype_resource_node_alpha (displayName “Prototype Salvage Heap”, gatherLens consumer_salvage, maxGathers 10, yield.itemId scrap_metal_bulk, yield.quantity 1) and prototype_urban_bulk_delta (gatherLens urban_bulk, yield.quantity 5). AAA per csharp-style. |
Bruno scripts complement automated tests for manual dev-server verification.
Open questions / risks
| Question / risk | Agent recommendation | Status |
|---|---|---|
| Linear blockedBy NEO-59 | Branch from main where NEO-59 is merged (confirmed at kickoff). |
adopted |
| Missing yield at map time | Rely on NEO-58 load parity (every node has exactly one yield row); no silent omission in HTTP mapper. | adopted |
| Instance depletion in response | Omit remaining gathers — instance state is NEO-61; this endpoint is definition catalog only. | adopted |
None blocking.
Decisions (kickoff)
- Nested
yieldobject —{ itemId, quantity }per row; joined from registry’s separate TryGet methods. - Row
idJSON name — consistent with item/skill world definition endpoints. nodestop-level array — parallel toitems/skillsnaming on sibling routes.- Manual QA doc included —
docs/manual-qa/NEO-60.md.