Admin Bot 4953580a8d
CI / Vet, test, build (push) Canceled after 11s
CI / Build and push image (push) Canceled after 0s
test: real integration tests calling actual service operations
REAL tests that call actual services, not fake routing checks:
- Get real JWT from Authentik (client_credentials flow)
- Call SQS list-queues and send-message
- Call MinIO/S3 list-objects with JWT
- Call Authentik API with JWT
- Call Memory query operations
- Call Temporal (gRPC not yet implemented)

Tests gracefully skip if services unreachable (502/504).
Tests warn if operations partially integrated (e.g., MinIO JWT not validated).
Tests document current JWT integration state vs. what's still TODO.

Configuration:
  GATEWAY_URL=https://api.riotpiao.com
  AUTHENTIK_CLIENT_ID=<from OAuth2 provider>
  AUTHENTIK_CLIENT_SECRET=<from OAuth2 provider>
  TEST_TIMEOUT=30

Run: ./scripts/test-integration.sh

Documentation:
- INTEGRATION_TESTS.md lists what's working vs. TODO
- Phase 3: Implement actual JWT validation in services
- Phase 9: Add gRPC proxying for Temporal
2026-08-27 11:20:21 -07:00

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

  1. Standard protocol shapes. POST /v1/chat/completions selects 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.
  2. Bearer tokens, validated against Authentik. JWKS is fetched at runtime and cached, so key rotation needs no runbook and no pinned PEM.
  3. 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.
  4. Streaming is first-class. SSE and WebSocket pass through unbuffered, and a client disconnect cancels the upstream request rather than orphaning it.
  5. 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.

S
Description
No description provided
Readme
976 KiB
Languages
Go 96.9%
Shell 2.6%
Dockerfile 0.5%