feat(api): viewer read-only API — epic E4 (TASK-33…40) #4

Merged
geekiot merged 9 commits from feat/api into main 2026-08-09 18:12:24 +05:00
Owner

What

Complete viewer REST API per docs/spec/05-api/viewer-api.md and the OpenAPI
contract docs/contracts/api/viewer-api.openapi.yaml — 8 endpoints, read-only
(CON-002, NFR-031, D-18): metadata from PostgreSQL, events from JSONL journals
in the named volume (D-62). No game logic, no calls into game-core.

Endpoints (base path /api/v1, D-72)

  • GET /health — liveness probe;
  • GET /sessions/current — active session or next_scheduled_at from
    SessionScheduled.planned_at (FR-040, D-84);
  • GET /sessions — finished sessions, offset pagination, newest first;
  • GET /sessions/{id} — metadata, roster with roles (D-43), events_count;
  • GET /sessions/{id}/events — event page via after/limit cursor,
    last_seq, session_status (polling stop signal, D-73); single mechanism
    for live and replay (FR-031, ADR-004), no visibility filtering (D-43);
  • GET /players, GET /players/{id} — catalog-consistent attributes (FR-020),
    public memory (D-52), stats history (D-66);
  • GET /stats/overview — six D-20 metrics (draft D-74, TODO in code);
  • GET /sessions/test — journal fixture data/fixtures/test-session.jsonl
    under the /sessions/{id}/events contract (FR-044, D-63, D-75).

Key decisions

  • JournalReader (TASK-34): cursor paging with seq > after, parsing only via
    domain JournalLine.from_json (CON-003), tolerant of a live file being
    appended (broken tail line skipped, D-62); reused by /sessions/test
    unchanged (D-75).
  • Repositories are SELECT-only over schema 0001/0002; OpenAPI contract
    serialization happens in the route layer.
  • Errors unified with admin-api: {"error": {code, message}} — 400 (invalid
    parameters), 404 (not found), 500 without internals plus an ERROR log entry
    (NFR-040); request metrics middleware (method/path/status/latency_ms) in
    structured JSON logs (D-82).

Tests and checks

  • 61 new tests (391 → 452 passed, 1 skipped): contract tests for all
    endpoints, error-code table, p95 reader benchmark (NFR-012 ≤ 500 ms),
    fixture coverage of every event type.
  • ruff check, ruff format --check, ty check, uv run pytest,
    nix flake check — all green.

Traceability

FR-030, FR-031, FR-040, FR-043, FR-044; D-16, D-43, D-51, D-52, D-53, D-62,
D-63, D-66, D-72, D-73, D-75; NFR-012, NFR-031, NFR-040; ADR-004.

Open notes: TODO(D-74) in StatsRepository (the /stats/overview field
composition is finalized together with the frontend epic E5 / TASK-48).

## What Complete viewer REST API per `docs/spec/05-api/viewer-api.md` and the OpenAPI contract `docs/contracts/api/viewer-api.openapi.yaml` — 8 endpoints, read-only (CON-002, NFR-031, D-18): metadata from PostgreSQL, events from JSONL journals in the named volume (D-62). No game logic, no calls into game-core. ## Endpoints (base path `/api/v1`, D-72) - `GET /health` — liveness probe; - `GET /sessions/current` — active session or `next_scheduled_at` from SessionScheduled.planned_at (FR-040, D-84); - `GET /sessions` — finished sessions, offset pagination, newest first; - `GET /sessions/{id}` — metadata, roster with roles (D-43), `events_count`; - `GET /sessions/{id}/events` — event page via `after`/`limit` cursor, `last_seq`, `session_status` (polling stop signal, D-73); single mechanism for live and replay (FR-031, ADR-004), no visibility filtering (D-43); - `GET /players`, `GET /players/{id}` — catalog-consistent attributes (FR-020), public memory (D-52), stats history (D-66); - `GET /stats/overview` — six D-20 metrics (draft D-74, TODO in code); - `GET /sessions/test` — journal fixture `data/fixtures/test-session.jsonl` under the `/sessions/{id}/events` contract (FR-044, D-63, D-75). ## Key decisions - `JournalReader` (TASK-34): cursor paging with `seq > after`, parsing only via domain `JournalLine.from_json` (CON-003), tolerant of a live file being appended (broken tail line skipped, D-62); reused by `/sessions/test` unchanged (D-75). - Repositories are SELECT-only over schema 0001/0002; OpenAPI contract serialization happens in the route layer. - Errors unified with admin-api: `{"error": {code, message}}` — 400 (invalid parameters), 404 (not found), 500 without internals plus an ERROR log entry (NFR-040); request metrics middleware (method/path/status/latency_ms) in structured JSON logs (D-82). ## Tests and checks - 61 new tests (391 → 452 passed, 1 skipped): contract tests for all endpoints, error-code table, p95 reader benchmark (NFR-012 ≤ 500 ms), fixture coverage of every event type. - `ruff check`, `ruff format --check`, `ty check`, `uv run pytest`, `nix flake check` — all green. ## Traceability FR-030, FR-031, FR-040, FR-043, FR-044; D-16, D-43, D-51, D-52, D-53, D-62, D-63, D-66, D-72, D-73, D-75; NFR-012, NFR-031, NFR-040; ADR-004. Open notes: `TODO(D-74)` in `StatsRepository` (the `/stats/overview` field composition is finalized together with the frontend epic E5 / TASK-48).
geekiot deleted branch feat/api 2026-08-09 18:12:24 +05:00
Sign in to join this conversation.
No reviewers
No labels
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.

Dependencies

No dependencies set

Reference
geekiot/mafia-agents!4
No description provided.