System explainer8 minute read

From bracket to live server.

MatchFound separates the internet-facing tournament website from the machine that controls CS2. The website decides what should happen, PostgreSQL remembers it, and a private Windows or Linux runner makes it real.

Steam identity Durable state Outbound runner No public RCON

01 / Big picture

The system map

Control messages and game traffic take different routes. That separation is the most important idea in the design.

Control path
Untrusted edge01

Player browser

Steam sign-in, tournament UI, bracket, and private join actions.

  • HTTPS requests
  • Authenticated SSE updates
HTTPS + SSE
Public service02

Control plane

Node.js and TypeScript own rules, authorization, scheduling, and APIs.

  • Steam sessions + CSRF
  • Brackets + match state
  • Metrics + audit events
Outbound claim
Private game host04

Windows / Linux runner

A least-privileged agent claims allowlisted jobs over outbound HTTPS.

  • Leases + heartbeats
  • Process + port control
  • Local RCON + log parsing
Local only
Match runtime05

CS2 instances

Isolated match profiles use unique game and private RCON ports.

  • 4 × 1v1 profiles
  • 2 × 5v5 profiles
  • Fast round configuration
Private network03

PostgreSQL

The source of truth for users, tournaments, brackets, jobs, events, and audits.

transactions unique constraints encrypted backups
Game path
PlayersCS2 client
Direct game traffic + short-lived password
Allocated CS2 game port The website is not in the packet path
A

The browser cannot control the server

It can request an allowed action. The control plane validates the session, role, CSRF token, request shape, and current tournament state before recording anything.

B

The public service cannot reach RCON

Production builds contain no game-host shell scripts, CS2 process controller, log monitor, or RCON client. Only the runner on the game host has those capabilities.

C

The runner calls out

The runner sends a heartbeat and claims a time-limited job over HTTPS. Nothing on the public internet opens an inbound control connection to the game host.

02 / End-to-end

How one match happens

The same path works for a 1v1 or a 5v5. The format changes the entry shape, score target, and server profile—not the safety model.

  1. 01Organizer

    Create and schedule

    The organizer chooses 1v1 or 5v5, number of players, start time, score to win, and event rules.

    Control plane
  2. 02Players

    Sign in and register

    Steam OpenID proves identity. MatchFound stores a revocable server-side session; the browser receives only an opaque cookie.

    Steam + sessions
  3. 03Organizer

    Rank, check in, and seed

    The host assigns familiar CS ranks. Rank-aware seeding creates balanced opening pairs while database constraints prevent duplicate entries.

    One transaction
  4. 04Scheduler

    Allocate capacity

    A ready match reserves one compatible instance and creates an idempotent start_match job in the same transaction.

    PostgreSQL
  5. 05Runner

    Claim, configure, and start

    An eligible runner claims a lease, verifies the exact profile and port, starts or reuses the intended process, applies the score target, and reports the result.

    Game host
  6. 06Competitors

    Receive private join details

    Only the two competitors—or two teams—and the organizer can see the IP, password, and one-click steam://connect link.

    Authorized SSE
  7. 07CS2

    Play to the configured score

    The runner turns CS2 output into normalized, sequenced events. Replays and forged events are rejected before they can change the bracket.

    Event stream
  8. 08Control plane

    Advance once and clean up

    The result, winner, bracket advancement, and cleanup job commit atomically. The runner removes players, rotates the password, and closes the dynamic instance.

    Closed loop

03 / Concurrency

“On demand” has a hard ceiling

MatchFound starts and stops configured instances as brackets become ready. It does not promise infinite servers: the runner advertises real capacity, and excess matches wait safely in the queue.

1v1 pool 04

Four simultaneous duels

01020304

Each profile owns a unique game port, RCON port, log path, and process identity.

5v5 pool 02

Two simultaneous team matches

0102

The scheduler chooses only profiles compatible with the match format and required map.

Additional matches queue

When capacity is full, a ready match stays visible and queued. Cleanup releases the instance, then the scheduler assigns the next compatible match without a port collision.

04 / Trust boundaries

Secrets stop where they belong

Each component receives the minimum authority it needs. A compromise at one boundary should not automatically unlock the next one.

Sensitive value Browser Control plane PostgreSQL Runner
Steam Web API key Never Secret manager Never Never
Session token Opaque cookie Hash only Hash only Never
Runner credential Never Hash only Hash only Own host only
RCON password Never Rejected Never Local only
Match password Own match only Authorized response Protected state Configures CS2
AUTH

Identity and authorization

Steam identity, server-side sessions, CSRF defense, strict request schemas, and a centralized role matrix protect every mutation.

STATE

Exactly-once outcomes

Transactions, unique constraints, event sequence numbers, idempotency keys, and optimistic versions prevent double starts and double winners.

EDGE

Minimal public surface

HTTPS serves the control plane. Only allocated CS2 game ports are public; PostgreSQL and RCON stay private.

TRACE

Evidence after the fact

Audit events, structured redacted logs, metrics, and traces connect a user action to its tournament, match, job, host, and result.

05 / Failure handling

Crashes do not become guesses

The database preserves desired state. After a restart, each side compares that desired state with actual CS2 processes instead of blindly repeating the last command.

Reconciliation Desired state
meets actual state
01

Control plane restarts

PostgreSQL retains matches, leases, jobs, events, sessions, and bracket state.

02

Runner restarts

It reports inventory, replays unacknowledged results, and resumes valid leases.

03

CS2 process dies

The runner reports an actionable failure; bounded retries or organizer recovery follow.

04

A message repeats

The same idempotency key or event sequence returns the stored result instead of acting twice.

The rule: never infer truth from a process still running. Read durable state, inspect the real instance, and converge the two.

06 / Today versus target

Local mode is convenient. Production mode is separated.

The app on this PC keeps a development path for LAN testing. Production deliberately removes those shortcuts from the public process.

Running locally

LAN / development mode

  • Website: http://localhost:4310
  • State: local PostgreSQL, with JSON retained for development tools
  • CS2 control: direct local controller is available for convenient testing
  • Audience: trusted machine and private network
Deployment target

Internet production mode

  • Website: public domain behind HTTPS and a trusted proxy
  • State: private managed PostgreSQL with encrypted offsite backups
  • CS2 control: outbound Windows or Linux service; no RCON code in the web artifact
  • Audience: Steam-authenticated tournament entrants

07 / Plain-language glossary

Terms used in the diagram

Control plane

The website and API that decide tournament state. It does not directly control RCON in production.

Runner

A small agent on a supported Windows or Linux CS2 host that performs a narrow allowlist of privileged game-server actions.

Lease

A time-limited claim on a job. If the runner disappears, the lease expires and recovery can proceed safely.

Idempotency

The same request can be retried without starting a second server or advancing the same winner twice.

Reconciliation

Comparing recorded desired state with the real processes and ports, then safely making them agree.

SSE

Server-Sent Events: a reconnectable stream that pushes bracket and server-status changes to an authorized browser.

Keep this sentence

The website decides. The database remembers.
The runner acts. CS2 plays. Events close the loop.

Go to tournaments