Context
Issue #300 adds district unlock progress tracking. This companion issue adds a map-oriented endpoint that returns all districts in a format suitable for visualization — UI clients can render a map of unlocked vs locked districts per agent.
What to implement
Route: GET /api/agents/[id]/districts/map
Response (GeoJSON-like, renderer-agnostic):
{
"agentId": "bot-1",
"districts": [
{
"id": "sector-alpha",
"label": "Sector Alpha",
"status": "unlocked",
"unlockedAt": 1719432000000,
"xpRequired": 500,
"xpAtUnlock": 531
},
{
"id": "sector-beta",
"label": "Sector Beta",
"status": "locked",
"xpRequired": 1500,
"xpCurrent": 531,
"progressPct": 35
}
]
}
Static district metadata (lib/districts/district-registry.ts)
Labels and any future display metadata (color, icon slug) live here. Separate from unlock logic.
Acceptance criteria
Context
Issue #300 adds district unlock progress tracking. This companion issue adds a map-oriented endpoint that returns all districts in a format suitable for visualization — UI clients can render a map of unlocked vs locked districts per agent.
What to implement
Route: GET /api/agents/[id]/districts/map
Response (GeoJSON-like, renderer-agnostic):
{ "agentId": "bot-1", "districts": [ { "id": "sector-alpha", "label": "Sector Alpha", "status": "unlocked", "unlockedAt": 1719432000000, "xpRequired": 500, "xpAtUnlock": 531 }, { "id": "sector-beta", "label": "Sector Beta", "status": "locked", "xpRequired": 1500, "xpCurrent": 531, "progressPct": 35 } ] }Static district metadata (lib/districts/district-registry.ts)
Labels and any future display metadata (color, icon slug) live here. Separate from unlock logic.
Acceptance criteria
status: 'unlocked'andunlockedAttimestampstatus: 'locked'andprogressPctxpRequiredmatches the threshold from issue District unlock progress: track XP toward unlocking each district and expose progress via API #300