PHASE 8 COMPLETE (10/10 tasks): - 8.2: X-Service/X-Resource dispatcher ✅ - 8.10: Phase gate - all 5 services routing ✅ Architecture decisions documented: - Gateway = dumb pipe (Option B) - SQS: gateway validates JWT (code unverified) - MinIO, Temporal: native JWT support - Memory, IAM: service-owned validation - ConfigMap-based config with Stakater Reloader - Real integration tests with cluster services PHASE 3 (Auth) TASKS CREATED (0/3 TODO): - 3.1: SQS JWT validation vs Authentik JWKS - 3.2: MinIO native JWT load-test - 3.3: Temporal JWT jwtKeyProvider configuration Updates: - tasks/8.2-x-service-dispatcher.md: marked GREEN - tasks/8.10-serviceadapter-gate.md: marked GREEN with notes - tasks/3.1-3.3: new Phase 3 auth tasks - tasks/INDEX.md: Phase 8 complete, Phase 3 active
homelab-frontend
A Go API gateway for the homelab cluster. One capability per subdomain, one auth implementation, one routing table.
Replaces Kong OSS entirely — see ADR-0001 for why, and docs/MIGRATION-kong.md for the cutover.
Position in the stack
browser / SDK ──▶ Cloudflare ──▶ ingress-nginx (TLS, edge)
│
▼
┌─────────────────────────────┐
│ homelab-frontend │
│ routing · authn · budgets │
└──────────────┬──────────────┘
│
/v1 /sqs /workflow /cluster
│ │ │ │
▼ ▼ ▼ ▼
llm-serving kmsvc/Kafka temporal atlas
(predictors) (sqs ns) (temporal ns) (riotpiao-backend)
└──── in-cluster Services ────┘
ingress-nginx keeps TLS and the edge. The gateway owns everything after it.
Backend services are reached through the gateway rather than published individually — a single place for authentication, budgets, timeouts and observability, and a single hostname surface to reason about.
Capability map
One host, one path prefix per capability.
Prefix on api.riotpiao.com |
Backs onto | Status |
|---|---|---|
/v1/* |
llm-serving predictors (vLLM, Ollama, TEI) |
migrating off Kong |
/sqs/* |
kmsvc management-service + Kafka/Strimzi (sqs ns) |
future |
/workflow/* |
Temporal (temporal ns) |
future |
/cluster/* |
atlas — cluster topology / Argo delivery (separate repo) | future |
/db/* |
CloudNativePG, MinIO, monitoring/metrics reads | future |
/v1/* is reserved for the OpenAI-compatible surface. An SDK expects
/v1/chat/completions at the base URL, so that prefix cannot be repurposed.
Paths rather than subdomains: one DNS record, one tunnel hostname, one Ingress. Promoting a prefix to its own subdomain later is additive and can run alongside the path — the reverse is not, because clients hardcode hostnames.
atlas lives in its own repo (riotpiao-backend) and keeps its own informers and
RBAC. The gateway routes to it; it does not absorb it. Cluster-read permissions
stay out of the public edge process.
Design rules
- Standard protocol shapes.
POST /v1/chat/completionsselects its model from the request body, like every OpenAI-compatible server. No path-per-model, no bespoke client configuration. Kong OSS could not do this; that limitation does not survive into the replacement. - Bearer tokens, validated against Authentik. JWKS is fetched at runtime and cached, so key rotation needs no runbook and no pinned PEM.
- Policy lives where the state is. GPU slot semaphores, per-caller budgets, queue depth and disconnect propagation are application concerns. They belong here, not in a proxy plugin.
- Streaming is first-class. SSE and WebSocket pass through unbuffered, and a client disconnect cancels the upstream request rather than orphaning it.
- The gateway holds no cluster credentials. It proxies to services that do.
Layout
cmd/gateway/ entrypoint
internal/
auth/ Authentik OIDC, JWKS cache, service-account tokens
llm/ model registry, body-based dispatch, upstream map
queue/ sqs.riotpiao.com surface
workflow/ workflow.riotpiao.com surface
proxy/ reverse proxy, streaming, timeouts, disconnect propagation
config/ upstream + route configuration
observability/ Prometheus metrics, structured logging
deploy/
base/ Kubernetes manifests
argocd/ Argo Application
docs/adr/ architecture decision records
tasks/ task board — see tasks/INDEX.md
testdata/ fixtures for offline tests
Local development
The gateway must be runnable with no cluster, no kubeconfig and no credentials, so that changes can be verified in a closed loop before touching live traffic. Upstreams are configuration, so pointing them at local stubs is the whole mechanism. See tasks/INDEX.md.
Status
Scaffolded 2026-08-19. Nothing is wired yet. Kong is still serving live traffic on
api.riotpiao.com.