Files
homelab-frontend/tasks/INDEX.md
T
Story Crater BotandClaude Opus 5 058f11cf2b
CI / Test (push) Canceled after 0s
CI / Vet (push) Canceled after 0s
CI / Build (push) Canceled after 0s
CI / Security (govulncheck) (push) Canceled after 0s
chore: initial commit of Go API gateway
Baseline for the Kong replacement on api.riotpiao.com. Brings the working
tree under version control for the first time: gateway source, the task
board that drives the agent runs, test fixtures, and K8s manifests.

Anchor the gateway ignore rule to the repo root. Unanchored, "gateway"
also matched the cmd/gateway/ source directory, so the program entrypoint
was excluded from every commit.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-08-19 20:54:34 -07:00

8.0 KiB
Raw Blame History

Task board — homelab-frontend

The Go API gateway replacing Kong OSS on api.riotpiao.com.

Contract: REQUIREMENTS.md. Why: ADR-0001. What Kong does today and the cutover order: docs/MIGRATION-kong.md.

Rules carried from the ADR and requirements

  • G1 — ingress-nginx owns TLS. The gateway never terminates TLS.
  • G2 — the gateway holds no Kubernetes credentials. Config comes from git, not a CRD.
  • G3 — public surfaces use standard protocol shapes. If an OpenAI SDK can't call it unmodified, it's wrong.
  • G4 — streaming is unbuffered, and a client disconnect cancels the upstream.
  • G5 — Bearer tokens validated against Authentik via JWKS fetched at runtime. No pinned keys.
  • G6 — every timeout, body cap and concurrency limit is explicit in config.
  • G7 — deployment flows through git and Argo. No kubectl apply, no helm upgrade.

How to work these

Each task is self-contained — it states what must be true, not how to build it. Reason out the implementation; the acceptance criteria are the contract.

Stages follow red-green-refactor. A task marked RED means the test comes first and must fail for the right reason before any implementation exists.

Verification means asserting on a real HTTP response — status, headers, body. "It compiles" and "it starts" are not verification. Every task that touches an API surface has a ## Verify block with a runnable command.

Kong is serving live traffic throughout phases 05. Nothing in those phases may change cluster state.

Phase 0 — Foundations

Task Description
0.1 Go module, entrypoint, graceful shutdown
0.2 Declarative route/upstream config from git, fail-loud validation
0.3 /healthz and /readyz
0.4 Run with no cluster, no kubeconfig, no credentials — stub upstreams
0.5 Structured logs, no secrets or bodies
0.6 CI: build, vet, test, govulncheck

Phase 1 — Proxy core

Task Description
1.1 Reverse proxy to a configured upstream, connection reuse
1.2 SSE and chunked responses pass through unbuffered
1.3 Client disconnect cancels the upstream request
1.4 Explicit connect/read/write timeouts per route
1.5 Hop-by-hop stripping, X-Forwarded-* from nginx
1.6 WebSocket upgrade — agent-pod/console needs it
1.7 Per-route request body limits

Phase 2 — LLM surfaces (/v1/* and /llm/*)

Two protocol dialects over the same models and the same slot controller. Wire formats are documented in docs/API-llm.md.

OpenAI dialect — /v1/*

Task Description
2.1 Model → upstream map from config
2.2 POST /v1/chat/completions routes on the body's model — the reason this project exists
2.3 Unknown/missing model → RFC 9457 problem+json listing valid values
2.4 Keep /v1/{reasoning,ornith,qwen}/chat/completions working during cutover
2.5 GET /v1/models derived from config, never hardcoded
2.6 POST /v1/embeddings — no rewrite needed
2.7 POST /v1/rerank → upstream /rerank
2.8 Gateway and Kong return equivalent responses for every migrated route

Anthropic dialect — /llm/*

Task Description
2.9 Dialect-neutral internal request both surfaces translate into
2.10 POST /llm/v1/messages request → canonical; system, blocks, required max_tokens
2.11 Upstream response → Messages shape; reasoning_content becomes a thinking block
2.12 Named-event SSE with block indices — the hardest task in the phase
2.13 Anthropic error shape, not RFC 9457 — same rejection, two renderings
2.14 Custom event: queue before message_start — deliberate non-standard extension
2.15 Enforce what is deliberately unimplemented: tools, images, caching, batch

Phase 3 — Authentication (Authentik)

Task Description
3.1 Fetch and cache Authentik JWKS, handle rotation without a runbook
3.2 Validate Authorization: Bearer — the thing Kong OSS could not do
3.3 Service account + client_credentials provider in Authentik
3.4 Auth defaults off; enabling it is deliberate
3.5 A queue token must not invoke a GPU
3.6 Move pi off the apikey header onto Bearer

Phase 4 — Limits and budgets

Task Description
4.1 Cap concurrent reasoning requests below 8 slots, bounded queue
4.2 Request budget per identified caller per window
4.3 RFC 9457 rejections with Retry-After

Phase 5 — Observability

Task Description
5.1 Match the retiring Kong plugin: rate, latency, status, bandwidth, upstream health
5.2 In-flight per upstream, queue depth, slot occupancy, rejections by reason
5.3 ServiceMonitor so Prometheus scrapes it

Phase 6 — Deploy and cutover

Task Description
6.1 Distroless, non-root, read-only rootfs, no shell, SHA tags
6.2 Deployment, Service, NetworkPolicy
6.3 Argo Application in the homelab-root GitOps repo
6.4 Deploy unexposed, verify in-cluster against the real upstreams
6.5 Repoint the nginx Ingress from kong-proxy to the gateway — reversible
6.6 Delete kong Ingresses, plugins, Helm release. Irreversible

Phase 7 — Additional capability prefixes

Deliberately after cutover. Each is additive and must not disturb /v1/*.

Task Description
7.1 /cluster/* → atlas (riotpiao-backend)
7.2 /sqs/* → kmsvc management-service, Kafka
7.3 /workflow/* → Temporal
7.4 /db/* → CloudNativePG, MinIO, monitoring reads

Progress

Status as of 2026-08-19: scaffolded, nothing implemented. Kong is still serving all live traffic on api.riotpiao.com, currently unauthenticated.

50 tasks. Suggested first slice: 0.1 → 0.2 → 0.4 → 1.1 → 1.2 → 2.1 → 2.2. That reaches the single capability Kong could not provide — body-based model dispatch — with a verification loop that needs no cluster.

The Anthropic dialect (2.9-2.15) can be worked in parallel with the OpenAI dialect once 2.9 lands, since both translate into the same canonical request. Do not build either surface's admission control separately — 4.1 owns it for both.

Decided 2026-08-19: authentication is Authorization: Bearer on both surfaces. A stock Anthropic SDK sends x-api-key and will get a 401; that is accepted because the /llm client is first-party. The 401 must say so rather than being bare.