Milestone 1 of the ggscale MVP is complete. This is the foundation everything else builds on.
What Shipped
Control plane skeleton. ggscale-server is a single Go binary using the chi router, slog structured JSON logging, and Prometheus metrics at /metrics. It starts in under 200ms and exposes GET /v1/healthz returning {"status":"ok","version":"v1","commit":"<sha>"}.
Postgres + Row-Level Security. Migration 0009_rls.up.sql enables RLS on every tenant-scoped table with a single policy: tenant_id = current_setting('app.tenant_id', true)::bigint. The , true flag makes a missing GUC return NULL, so the policy fails closed. Combined with the HTTP middleware that injects tenant_id into every authenticated request, this gives us defence-in-depth tenant isolation from day one.
K3s + Agones smoke test. The CI e2e job starts the full compose stack including a single-node K3s cluster and an Agones install. The smoke test (TestAgonesAllocation_AssignsHostPort_ReachableViaUDP) allocates a GameServer CRD, waits for Status.State == Ready, reads the dynamic UDP port, and asserts the simple-game-server image echoes a packet back. This is the parity contract the rest of the fleet work builds on.
CI pipeline. Three jobs on ubuntu-24.04: lint-test (golangci-lint, go test -race, govulncheck), docker-build (multi-stage, exported as artifact), and e2e (loads the artifact, starts the k8s compose profile, runs the smoke test). Action versions are SHA-pinned; workflow permissions default to contents: read.
Olric embedded cache. CACHE_BACKEND=olric starts an embedded Olric cluster in-process across the app VMs in each region. Rate limiting and connection-cap state are shared regionally without a separate cache service. CACHE_BACKEND=memory (default) covers dev, single-VM self-host, and integration tests.
Where This Sits in the Roadmap
flowchart LR
M1["Milestone 1: Foundations
(shipped)"] --> M2["Milestone 2: Tenanted API
(in progress)"]
M2 --> M3["Milestone 3: Realtime + Fleet"]
M3 --> M4["Milestone 4: Billing + Compliance"]
M4 --> M5["Milestone 5: Public Beta"]
M1 -. delivers .-> D1["control plane skeleton
Postgres + RLS
K3s + Agones smoke
CI pipeline"]
M2 -. delivers .-> D2["auth, storage, leaderboards
tenant isolation
rate limiting"]
classDef done fill:#d4edda,stroke:#28a745,color:#000
classDef active fill:#fff3cd,stroke:#ffc107,color:#000
class M1 done
class M2 active
What’s Next: Milestone 2
Milestone 2 adds the tenant-gated API surface:
POST /v1/auth/signup,/v1/auth/login,/v1/auth/refresh,/v1/auth/logout/v1/storage/*: tenant-isolated key-value blob storage/v1/leaderboards/*: per-project ranked leaderboardsinternal/tenantHTTP middleware: extractsAuthorization: Bearer <api_key>, hashes SHA-256, looks upapi_keystable, injectstenant_idinto context- HTTP rate limiting (sliding window per API key via Olric/memory token bucket) and WebSocket connection caps
The test-first rule applies to all of Milestone 2: every endpoint has a failing integration test before any implementation lands.