Skip to content

feat(gateway): forward /api/games to the games service - #188

Merged
Bakhomious merged 9 commits into
mainfrom
step/games-gateway
Oct 30, 2026
Merged

Bakhomious merged 9 commits into
mainfrom
step/games-gateway

Conversation

@Bakhomious

@Bakhomious Bakhomious commented Oct 30, 2026 •

Copy link
Copy Markdown
Contributor

Brief

Goal: the app reaches the games list through the gateway, at GET /api/games/recent, behind both of the gateway's locks. The ninth of games-exophase's eleven steps (decision 300).

Scope:

  • The gateway requires a games peer, as it does every other, and forwards /api/games and every path under it to games, as /games…, behind the Tailscale and session locks, with the session cookie hidden from games (session.Hide).
  • mise run up: the gateway's BAKHYARD_PEERS names games on 8090, and the gateway starts once games is healthy.
  • The end-to-end tests' gateway names games, where nothing listens, as it does the other services.
  • Docs: setup.md, plan §4's services table and process-compose bullet, the §0 row and the §8.2 bullet.
  • Decision 309, with the §8.2 bullets homelab-games and homelab-games-covers: the laptop runs games without covers until there's a Twitch app, as you chose when you couldn't log in to Twitch. codedogapp/homelab#44 was reworked to match.

Out of scope: the Games page (games-page); the Home asking games, which answers no attention contract; the laptop, which codedogapp/homelab#44 sets up.

Order: this PR merges only after codedogapp/homelab#44 (merged and applied: the laptop's gateway runs with its games peer), so that the laptop's gateway has its games peer before it requires one; a gateway without it would exit 1 and take the whole app down. Since #190 and #193 have merged, it's also the feature's last PR, so it sets games-exophase's §0 row to Done, noting that the laptop's covers wait for a Twitch app.

Acceptance criteria

  1. With a session, GET /api/games/recent reaches games as GET /games/recent; any method and path under /api/games gets to games, which answers for its own paths and methods.
  2. Without a session, /api/games/recent gets 401; without the Tailscale identity, the gateway refuses it as it refuses the other paths.
  3. games never gets the session cookie.
  4. Without a games peer in BAKHYARD_PEERS, the gateway exits 1 with BAKHYARD_PEERS has no peer "games", beside any other peer it lacks.
  5. While games is down, /api/games/recent gets a 503 with games is unavailable.
  6. mise run up starts the gateway once games is healthy, and the gateway forwards to it on 8090.
  7. The end-to-end tests' gateway starts with games among its peers.
  8. mise run check is green.

QA

  • BAKHYARD_E2E_PORT=8380 mise run check is green on 1a3cad5, with main at 7f6919e merged in: golangci-lint 0 issues, govulncheck clean, Go coverage 97.1%, Vitest 1341 passed, the end-to-end tests 438 passed and 8 skipped, with the Playwright gateway naming games. On the previous head, 269341e, the first run failed only in the planner's TestStopEndsTheQuestions, a 10 s timeout while another session ran its checks; the rerun AGENTS.md allows was green. Its process-compose up --dry-run takes the new gateway block.
  • Unit tests, one or more for each criterion:
    • /api/games/recent and POST /api/games reach games as /games/recent and /games;
    • 401 without a session, 403 without the Tailscale identity, with or without a session;
    • games gets theme=dark and never the session cookie, and the session is renewed;
    • 503 while nothing listens where games is;
    • the error names games when BAKHYARD_PEERS lacks it, alone or with web;
    • the open end-to-end gateway forwards /api/games/recent too.
  • Live, on my own ports, with the real bin/games (no Exophase setting) behind bin/e2e/gateway:
    • GET /api/games/recent got games' own 404 Exophase is not set up, HEAD a 404, and POST games' 405; /games, the page's path, still went to web.
    • With games stopped: 503 {"code":"unavailable","message":"games is unavailable"}, and the gateway logged upstream unavailable upstream=games.
    • Without games in BAKHYARD_PEERS, the gateway exited 1 with BAKHYARD_PEERS has no peer "games".
  • Hand mutants, 6 of 6 caught: no games route; games' route to home's service; the route named game; games behind the Tailscale lock alone, without a session; the games peer optional; the peer named game.
  • The gateway sets no write timeout and its proxy no response-header timeout, so games' first request, which waits for Exophase and the covers, isn't cut short.

Review

No blocking findings. The change follows time-gateway (#151) and github-gateway (#179) line for line: a peer, a route behind both locks, process-compose's wait, the Playwright peer, and the tests' peer lists.

Non-blocking:

  • Each new peer touches five test files that spell out BAKHYARD_PEERS; a helper that builds it from the peers' names, as withPeers does, would shrink that. That's a refactor for a step of its own.
  • feat(gateway): forward /api/github to the github service #179 edits the same lines for github. Whichever merges second keeps both, in the names' order: games, github, home, ….

The app reaches the games I played lately at GET /api/games/recent,
behind both of the gateway's locks, as it reaches the other services.
games is one of the gateway's peers, which BAKHYARD_PEERS must name,
and mise run up starts the gateway once games is ready.

The laptop's gateway gets its games peer from codedogapp/homelab#44,
which must merge first: a gateway without it would not start.
@Bakhomious
Bakhomious merged commit 201175a into main Oct 30, 2026
2 checks passed
@Bakhomious
Bakhomious deleted the step/games-gateway branch October 30, 2026 10:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant