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.