Plane Backend-Agent-Status als naechsten Slice
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
parent
30b862008a
commit
ef657997b2
2 changed files with 400 additions and 0 deletions
151
docs/plans/2026-03-22-backend-agent-status-design.md
Normal file
151
docs/plans/2026-03-22-backend-agent-status-design.md
Normal file
|
|
@ -0,0 +1,151 @@
|
|||
# Backend-Agent Status Slice Design
|
||||
|
||||
**Goal:** Stabilize the current backend foundation and add the first small, real backend-agent status path without introducing database or MQTT dependencies yet.
|
||||
|
||||
**Architecture:** The backend keeps its existing in-memory/runtime-only character, but gains stronger HTTP test coverage and a minimal player status ingestion endpoint. The agent reuses its internal health snapshot and posts a compact status payload to the backend on a timer, so the first end-to-end data flow is exercised before larger sync and broker work begins.
|
||||
|
||||
**Tech Stack:** Go stdlib HTTP server/client, existing repo docs, existing agent health model.
|
||||
|
||||
---
|
||||
|
||||
## Decision
|
||||
|
||||
For the next slice, we intentionally do **not** implement full player registration, persistence, authentication, or MQTT.
|
||||
|
||||
Instead we build a narrow vertical slice with these boundaries:
|
||||
|
||||
1. harden existing backend routes and validation coverage
|
||||
2. add `POST /api/v1/player/status` in the backend with shared error handling
|
||||
3. add a small agent status reporter that periodically sends the current health snapshot
|
||||
4. document the temporary v1-dev contract clearly so later persistence and auth can replace it cleanly
|
||||
|
||||
## Why this order
|
||||
|
||||
### Option A - Recommended: backend hardening, then minimal status path
|
||||
|
||||
Pros:
|
||||
|
||||
- least architectural churn for the current repo stage
|
||||
- gives the project its first real backend-agent integration
|
||||
- keeps risk low because the payload is small and derived from already tested agent state
|
||||
- creates a natural foundation for later registration, revisions, and MQTT state
|
||||
|
||||
Cons:
|
||||
|
||||
- still not very visible to end users
|
||||
- uses temporary in-memory handling on the backend
|
||||
|
||||
### Option B - Agent-first connectivity expansion
|
||||
|
||||
Pros:
|
||||
|
||||
- fast to implement in the agent
|
||||
- extends the new health model quickly
|
||||
|
||||
Cons:
|
||||
|
||||
- creates local connectivity logic without a meaningful server contract
|
||||
- duplicates future work once the backend path exists
|
||||
|
||||
### Option C - Bigger vertical slice with registration and status
|
||||
|
||||
Pros:
|
||||
|
||||
- closer to the eventual architecture
|
||||
- more obviously “real” system behavior
|
||||
|
||||
Cons:
|
||||
|
||||
- too much surface area for the current codebase maturity
|
||||
- would mix lifecycle hardening, API design, auth placeholders, and agent behavior at once
|
||||
|
||||
## Scope
|
||||
|
||||
### Backend
|
||||
|
||||
- keep `GET /healthz`, `GET /api/v1`, `GET /api/v1/meta`, and the existing `message-wall` route
|
||||
- add route-level tests for the existing endpoints
|
||||
- expand `message_wall` validation tests to match the documented rules more closely
|
||||
- add `POST /api/v1/player/status`
|
||||
- accept a small JSON payload and respond with a compact acknowledgement
|
||||
- no database write, no in-memory historical store yet beyond the request/response path unless needed for tests
|
||||
|
||||
### Agent
|
||||
|
||||
- keep the current lifecycle and health snapshot model
|
||||
- add an HTTP status reporter component that transforms the snapshot into a backend payload
|
||||
- send periodic status updates on a configurable interval
|
||||
- keep failures non-fatal and log them as structured events
|
||||
- no registration, no retries beyond the next normal interval, no MQTT yet
|
||||
|
||||
## Proposed temporary API contract
|
||||
|
||||
### Request
|
||||
|
||||
`POST /api/v1/player/status`
|
||||
|
||||
```json
|
||||
{
|
||||
"screen_id": "info01-dev",
|
||||
"ts": "2026-03-22T16:00:00Z",
|
||||
"status": "running",
|
||||
"server_url": "http://127.0.0.1:8080",
|
||||
"mqtt_broker": "tcp://127.0.0.1:1883",
|
||||
"heartbeat_every_seconds": 30,
|
||||
"started_at": "2026-03-22T15:59:30Z",
|
||||
"last_heartbeat_at": "2026-03-22T16:00:00Z"
|
||||
}
|
||||
```
|
||||
|
||||
### Response
|
||||
|
||||
```json
|
||||
{
|
||||
"status": "accepted"
|
||||
}
|
||||
```
|
||||
|
||||
### Notes
|
||||
|
||||
- this is a dev-stage HTTP substitute for the richer future status/heartbeat model described in `API-MQTT-VERTRAG.md`
|
||||
- the payload is deliberately derived from fields the agent already owns today
|
||||
- later player identity, auth, richer connectivity flags, and persistence can evolve this contract without invalidating the current slice
|
||||
|
||||
## Error handling
|
||||
|
||||
- invalid JSON -> existing shared API error envelope with `400`
|
||||
- missing `screen_id` or invalid timestamps -> shared API error envelope with `400`
|
||||
- successful ingest -> `200` with compact acknowledgement
|
||||
- agent-side send failures -> structured log event, but the agent keeps running
|
||||
|
||||
## Testing strategy
|
||||
|
||||
### Backend tests
|
||||
|
||||
- route tests for `/healthz`, `/api/v1`, `/api/v1/meta`
|
||||
- route tests for valid and invalid `POST /api/v1/player/status`
|
||||
- broaden `message_wall` validation tests for version, unit, fit mode, duplicate slots, out-of-bounds slots, empty slots
|
||||
|
||||
### Agent tests
|
||||
|
||||
- reporter payload generation from `HealthSnapshot`
|
||||
- status send success path using `httptest.Server`
|
||||
- non-fatal error handling on send failure
|
||||
- interval-driven reporting using injectable ticker/clock seams where needed
|
||||
|
||||
## Out of scope
|
||||
|
||||
- database persistence of player status
|
||||
- player registration
|
||||
- auth tokens
|
||||
- MQTT broker integration
|
||||
- screenshots and media sync
|
||||
- admin UI visualization of the status data
|
||||
|
||||
## Expected result
|
||||
|
||||
After this slice, the repository still remains intentionally simple, but it gains:
|
||||
|
||||
- hardened backend route and validation coverage
|
||||
- the first real backend-agent HTTP interaction
|
||||
- a cleaner base for later registration, sync, and MQTT work
|
||||
249
docs/plans/2026-03-22-backend-agent-status-plan.md
Normal file
249
docs/plans/2026-03-22-backend-agent-status-plan.md
Normal file
|
|
@ -0,0 +1,249 @@
|
|||
# Backend-Agent Status Slice Implementation Plan
|
||||
|
||||
> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
|
||||
|
||||
**Goal:** Harden the backend HTTP foundation and add the first minimal agent-to-backend status reporting path.
|
||||
|
||||
**Architecture:** The backend remains a small in-memory Go service with stronger HTTP and validation tests plus a narrow `POST /api/v1/player/status` contract. The agent reuses its internal health snapshot and periodically posts it over HTTP, logging failures without stopping playback/lifecycle behavior.
|
||||
|
||||
**Tech Stack:** Go stdlib, existing `net/http` router, `httptest`, existing agent health model.
|
||||
|
||||
---
|
||||
|
||||
### Task 1: Backend route coverage for existing endpoints
|
||||
|
||||
**Files:**
|
||||
- Modify: `server/backend/internal/httpapi/messagewall_test.go`
|
||||
- Possibly create: `server/backend/internal/httpapi/router_test.go`
|
||||
|
||||
**Step 1: Write the failing tests**
|
||||
|
||||
Add focused tests for:
|
||||
- `GET /healthz` returns `200` and `status=ok`
|
||||
- `GET /api/v1` returns base info and tool list
|
||||
- `GET /api/v1/meta` returns the documented tool route
|
||||
|
||||
**Step 2: Run test to verify it fails**
|
||||
|
||||
Run: `go test ./internal/httpapi -run 'TestRouter'`
|
||||
Expected: FAIL because the new route tests do not exist yet or assertions fail.
|
||||
|
||||
**Step 3: Write minimal implementation**
|
||||
|
||||
Only add or adjust router/response code if the tests expose gaps. Do not refactor unrelated HTTP code.
|
||||
|
||||
**Step 4: Run test to verify it passes**
|
||||
|
||||
Run: `go test ./internal/httpapi -run 'TestRouter'`
|
||||
Expected: PASS.
|
||||
|
||||
**Step 5: Commit**
|
||||
|
||||
```bash
|
||||
git add server/backend/internal/httpapi/*.go
|
||||
git commit -m "Ergaenze HTTP-Tests fuer Basisendpunkte"
|
||||
```
|
||||
|
||||
### Task 2: Message-wall validation matrix
|
||||
|
||||
**Files:**
|
||||
- Modify: `server/backend/internal/campaigns/messagewall/resolver_test.go`
|
||||
|
||||
**Step 1: Write the failing tests**
|
||||
|
||||
Add table-driven validation tests for:
|
||||
- unsupported `version`
|
||||
- invalid `unit`
|
||||
- invalid `fit_mode`
|
||||
- empty slot list
|
||||
- duplicate `slot_id`
|
||||
- out-of-bounds slot
|
||||
|
||||
**Step 2: Run test to verify it fails**
|
||||
|
||||
Run: `go test ./internal/campaigns/messagewall -run 'TestValidate'`
|
||||
Expected: FAIL until the new cases are covered correctly.
|
||||
|
||||
**Step 3: Write minimal implementation**
|
||||
|
||||
Adjust validation only if tests reveal a real mismatch against `docs/LAYOUT-JSON.md`.
|
||||
|
||||
**Step 4: Run test to verify it passes**
|
||||
|
||||
Run: `go test ./internal/campaigns/messagewall -run 'TestValidate'`
|
||||
Expected: PASS.
|
||||
|
||||
**Step 5: Commit**
|
||||
|
||||
```bash
|
||||
git add server/backend/internal/campaigns/messagewall/resolver_test.go server/backend/internal/campaigns/messagewall/resolver.go
|
||||
git commit -m "Pruefe Layout-Validierung systematischer"
|
||||
```
|
||||
|
||||
### Task 3: Backend player status endpoint
|
||||
|
||||
**Files:**
|
||||
- Modify: `server/backend/internal/httpapi/router.go`
|
||||
- Create: `server/backend/internal/httpapi/playerstatus.go`
|
||||
- Create: `server/backend/internal/httpapi/playerstatus_test.go`
|
||||
|
||||
**Step 1: Write the failing tests**
|
||||
|
||||
Add tests for:
|
||||
- valid `POST /api/v1/player/status` returns `200` and `{"status":"accepted"}`
|
||||
- invalid JSON returns the shared error envelope
|
||||
- missing `screen_id` returns `400`
|
||||
- malformed timestamps return `400`
|
||||
|
||||
**Step 2: Run test to verify it fails**
|
||||
|
||||
Run: `go test ./internal/httpapi -run 'TestHandlePlayerStatus'`
|
||||
Expected: FAIL because handler and route do not exist yet.
|
||||
|
||||
**Step 3: Write minimal implementation**
|
||||
|
||||
Implement a small request struct, parse/validate it, and reuse the existing error/JSON helpers. Keep storage out of scope.
|
||||
|
||||
**Step 4: Run test to verify it passes**
|
||||
|
||||
Run: `go test ./internal/httpapi -run 'TestHandlePlayerStatus'`
|
||||
Expected: PASS.
|
||||
|
||||
**Step 5: Commit**
|
||||
|
||||
```bash
|
||||
git add server/backend/internal/httpapi/router.go server/backend/internal/httpapi/playerstatus.go server/backend/internal/httpapi/playerstatus_test.go
|
||||
git commit -m "Lege ersten Player-Status-Endpunkt an"
|
||||
```
|
||||
|
||||
### Task 4: Agent status reporter payload
|
||||
|
||||
**Files:**
|
||||
- Create: `player/agent/internal/statusreporter/reporter.go`
|
||||
- Create: `player/agent/internal/statusreporter/reporter_test.go`
|
||||
- Possibly modify: `player/agent/internal/app/app.go`
|
||||
|
||||
**Step 1: Write the failing tests**
|
||||
|
||||
Add tests for converting `app.HealthSnapshot` into the HTTP payload and for a successful post to an `httptest.Server`.
|
||||
|
||||
**Step 2: Run test to verify it fails**
|
||||
|
||||
Run: `go test ./internal/statusreporter`
|
||||
Expected: FAIL because package/behavior does not exist yet.
|
||||
|
||||
**Step 3: Write minimal implementation**
|
||||
|
||||
Create a small reporter with injected base URL, `http.Client`, and time source as needed. Keep the API narrow.
|
||||
|
||||
**Step 4: Run test to verify it passes**
|
||||
|
||||
Run: `go test ./internal/statusreporter`
|
||||
Expected: PASS.
|
||||
|
||||
**Step 5: Commit**
|
||||
|
||||
```bash
|
||||
git add player/agent/internal/statusreporter/*.go player/agent/internal/app/app.go
|
||||
git commit -m "Fuehre einfachen Status-Reporter fuer den Agenten ein"
|
||||
```
|
||||
|
||||
### Task 5: Agent periodic reporting integration
|
||||
|
||||
**Files:**
|
||||
- Modify: `player/agent/internal/app/app.go`
|
||||
- Modify: `player/agent/internal/app/app_test.go`
|
||||
- Possibly modify: `player/agent/internal/config/config.go`
|
||||
- Possibly modify: `player/agent/internal/config/config_test.go`
|
||||
|
||||
**Step 1: Write the failing tests**
|
||||
|
||||
Add tests that prove:
|
||||
- reporting is triggered from the running app
|
||||
- send failures are logged and do not stop `Run()`
|
||||
- any new interval config gets sane defaults
|
||||
|
||||
**Step 2: Run test to verify it fails**
|
||||
|
||||
Run: `go test ./internal/app ./internal/config`
|
||||
Expected: FAIL until integration exists.
|
||||
|
||||
**Step 3: Write minimal implementation**
|
||||
|
||||
Wire the reporter into the app loop with the smallest possible seam. Avoid broad lifecycle refactors.
|
||||
|
||||
**Step 4: Run test to verify it passes**
|
||||
|
||||
Run: `go test ./internal/app ./internal/config`
|
||||
Expected: PASS.
|
||||
|
||||
**Step 5: Commit**
|
||||
|
||||
```bash
|
||||
git add player/agent/internal/app/*.go player/agent/internal/config/*.go
|
||||
git commit -m "Melde Agent-Status periodisch an das Backend"
|
||||
```
|
||||
|
||||
### Task 6: Documentation update for the new status path
|
||||
|
||||
**Files:**
|
||||
- Modify: `API-MQTT-VERTRAG.md`
|
||||
- Modify: `DEVELOPMENT.md`
|
||||
- Possibly modify: `README.md`
|
||||
- Possibly create: `docs/PLAYER-STATUS-HTTP.md`
|
||||
|
||||
**Step 1: Write the failing documentation check**
|
||||
|
||||
Create a short checklist from the implemented contract and verify which docs are stale.
|
||||
|
||||
**Step 2: Run the verification**
|
||||
|
||||
Manual check against the implemented request/response payload and the chosen scope.
|
||||
Expected: current docs are incomplete for the temporary dev-stage HTTP status path.
|
||||
|
||||
**Step 3: Write minimal documentation updates**
|
||||
|
||||
Document that the current dev slice uses a minimal HTTP status endpoint before the richer long-term API/MQTT model is fully built.
|
||||
|
||||
**Step 4: Run verification**
|
||||
|
||||
Re-read the changed docs and ensure wording matches actual code scope.
|
||||
|
||||
**Step 5: Commit**
|
||||
|
||||
```bash
|
||||
git add API-MQTT-VERTRAG.md DEVELOPMENT.md README.md docs/*.md
|
||||
git commit -m "Dokumentiere ersten HTTP-Statuspfad fuer den Agenten"
|
||||
```
|
||||
|
||||
### Task 7: Final verification
|
||||
|
||||
**Files:**
|
||||
- No planned file changes
|
||||
|
||||
**Step 1: Run backend tests**
|
||||
|
||||
Run: `go test ./...`
|
||||
Workdir: `server/backend`
|
||||
Expected: PASS.
|
||||
|
||||
**Step 2: Run agent tests**
|
||||
|
||||
Run: `go test ./...`
|
||||
Workdir: `player/agent`
|
||||
Expected: PASS.
|
||||
|
||||
**Step 3: Run builds**
|
||||
|
||||
Run:
|
||||
- `go build ./...` in `server/backend`
|
||||
- `go build ./...` in `player/agent`
|
||||
Expected: PASS.
|
||||
|
||||
**Step 4: Run manual integration check**
|
||||
|
||||
Start backend locally, run agent locally with example config, and confirm the backend receives `POST /api/v1/player/status` successfully.
|
||||
|
||||
**Step 5: Commit if needed**
|
||||
|
||||
Only if the verification step itself required code/doc adjustments.
|
||||
Loading…
Add table
Reference in a new issue