3.6 KiB
ADR-001: Matchmaking control-plane platform
- Status: Accepted
- Date: 2026-08-31
- Scope: Phase 8 matchmaking, ranked play, and per-match server allocation
Decision
Build the matchmaking control plane as independently runnable Go roles backed by PostgreSQL and Redis, deployed on provider-portable Kubernetes:
- API: authenticated REST and revisioned WebSocket state delivery.
- Matcher: queue candidate selection and proposal creation.
- Allocator: Agones
GameServerAllocationand assignment delivery. - Maintenance: expiry, repair, outbox delivery, rating and result processing.
- PostgreSQL: durable identities, sessions, queue ownership, proposals, participants, matches, ratings, results, penalties, audits and outbox.
- Redis: expiring presence and candidate indexes only; it is never an ownership or allocation fence.
- Agones: game-server readiness, allocation and lifecycle.
- Steam Hosted Dedicated Server SDR: production player-to-server routing.
EU and NA are the first regions. Provider-specific networking, edge, secrets, SDR POPs and certificates live in deployment overlays. Application code must not call a cloud-provider allocation API directly.
The existing Godot ENet server remains a supported direct-IP/community-server path. Allocated matches use the same authoritative simulation, but are a separate lifecycle: one match per server process, assignment only after the server is genuinely ready, and shutdown after result delivery.
Boundaries and invariants
- PostgreSQL is the source of truth for ownership, participation fences, legal state transitions and idempotency. Redis indexes may be rebuilt.
- Steam identity is verified by the secure backend. A client-supplied name or Steam ID is never an identity or rating key.
- The backend issues match-scoped, expiring authorisations bound to identity, match, server, slot, protocol and connection generation.
- Agones
Readymeans process-ready only. Assignment-ready additionally requires the allocated manifest, signed roster and backend registration. - ENet/SDR carries simulation traffic; REST/WebSocket carries control-plane traffic. No simulation state is routed through the backend.
- Provider failure must not be represented as a player fault. Result delivery and match-integrity failure remain separate states.
Rejected alternatives
- C#/.NET backend: not consistent with the shipped GDScript-only project and adds no required capability over Go.
- Redis as the durable queue fence: Redis failover can lose an acknowledged write; using it as authority can split a player across proposals.
- Provider-specific allocation SDKs in application code: couples matching policy and correctness to one cloud and prevents the second-provider migration gate.
- A custom game-server scheduler instead of Agones: duplicates readiness, allocation, drain and lifecycle behavior that the project needs to verify.
- Replacing the community ENet path: direct-IP ENet remains necessary for LAN, CI and self-hosted servers and must not become a silent fallback for a failed production SDR assignment.
Consequences
This introduces the first non-Godot service in the project and requires versioned API contracts, database migrations, operational security and concurrency testing. It also gives queue ownership, ratings, reconnects and allocation a durable authority instead of extending the Godot server with cross-match responsibilities. SLOs and wire contracts are separate follow-up decisions (tasks 8.2 and 8.3).