Devlog

Capybara Battle is a solo-built real-time PvP + campaign strategy game. This page is a case study of how the backend is put together — for anyone evaluating the engineering, not the game.

Overview

  • • Solo developer — design, backend, client integration, and ops.
  • • Real-time PvP (Socket.IO), a story campaign mode, gacha/collection, and a shop economy.
  • • Ongoing project — this devlog tracks the architecture as it stands, not a finished product.

Tech Stack

Backend

  • FastAPI
  • Socket.IO
  • Redis
  • PostgreSQL
  • Alembic

Client

  • Flutter
  • BLoC

Infra

  • Blue/green deploy
  • Nginx

Architecture

Client (Flutter)
  │  REST (FastAPI) ── matchmaking, decks, shop, campaign
  │  WebSocket (Socket.IO) ── live match state, pre-match selection
  ▼
Backend (FastAPI)
  ├─ Matchmaking → ELO queue → match found
  ├─ Pre-match selection (Redis, 30s TTL) → LOCK → game_start
  ├─ Game loop (PvP) ──────────┐
  ├─ Campaign engine ──────────┤  shared match engine, isolated rule sets
  └─ Reward / shop / cards     │
  ▼                            ▼
Postgres (durable state)     Redis (ephemeral session state)

PvP and Campaign share the same match engine but never share special-mechanic code — campaign-only rules (wave patterns, terrain buffs) are structurally kept out of the PvP path.

Decisions Worth Explaining

Real-time matchmaking

ELO-based queue over Socket.IO. A match found event hands off into a short pre-match phase instead of dropping players straight into a game — this exists specifically so new players don't fight with a stale default deck.

Pre-match card selection

A 30-second selection window lives in Redis (not Postgres) — it's short-lived, high-write, and doesn't need to survive a restart. Both players can LOCK early to skip the timer; if nobody locks, the match falls back to each player's last saved battle deck so a match never stalls on an AFK player.

Leave penalty, not a ban

Repeatedly leaving pre-match (4 times) triggers a 3-minute soft penalty rather than a hard ban, tracked per-player with a running counter that resets after the penalty is served. Leaving during a penalty resets the timer, which discourages using cancel as a queue-dodge trick.

Campaign vs PvP are isolated

Campaign-only mechanics (wave patterns, terrain buffs, boss scripts) are intentionally kept out of the PvP code path — same match engine, different rule surface, so a PvP balance change can never silently affect campaign difficulty or vice versa.

Numbers

Live metrics (concurrent players, match latency, uptime) aren't published yet — available on request.

Get in Touch

Questions about the architecture or the project — reach out.