Why this project exists
jack7 is a multiplayer shedding card game — the UK "BlackJack" variant of the Crazy Eights / Switch family. I grew up playing it with family and friends, and the existing digital versions were either dead, riddled with ads, or got the rules wrong. I wanted to build the definitive version: correct rules, polished feel, and a design that respects the tabletop experience.
It's also a playground for game server architecture, real-time networking, and native iOS development — skills I've been developing alongside my day job building enterprise mobile and web platforms.
What I built
Authoritative Go game server
The server owns all game logic. Clients are thin viewers — they send intents and render state. This prevents cheating, keeps a single source of truth, and makes it easy to add new clients later.
The game engine implements the full UK BlackJack rule set:
- Power cards: 2s (pickup 2), 8s (skip), Black Jacks (pickup 7), Red Jacks (cancel), Queens (naked queen), Kings (reverse), Aces (suit change), Jokers (wild with declared identity)
- Runs: chain multiple cards per turn by rank-match → sequence → pivot
- Stacking: pickup cards stack (2+2=4, 2+Black Jack=9), skips stack, mid-run effect swallowing when you play past a power card
- Cards-call state machine: 3-state (None/Pending/Armed) with off-turn calling, idempotent re-calls, and cycle-forward — prevents tap-spam desyncs and enables legal win windows
- Per-game audit log: every action captured server-side with typed effect tags, rendered in the iOS app via
GameLogView
The server runs on Hetzner via Coolify, deployed automatically on every push to main through GitHub Actions → GHCR → Coolify webhook. It serves the game over WebSocket and the public website (landing, privacy, terms, roadmap) from the same Go binary — all pages rendered from embedded markdown.
Infrastructure includes an admin dashboard with live Chart.js metrics, structured JSON logging (slog), stats history with JSONL persistence, and a protocol-version handshake that gates force-upgrade for incompatible clients.
Polished SwiftUI iOS app
The iOS app is native SwiftUI with an MVVM architecture. It's a thin client — no game logic duplicated, just state rendering and intent sending.
Key features:
- Event-queue architecture: separates logical game state from visual state for smooth, independent animations
- Card-flight animations: cards animate from hand to discard pile with proper z-ordering
- Sound design: select, place, stacked pickup, deck shuffle, riffle on hand reorder
- Haptics: select, place, heavy power thump, per-card staggered pickup, rigid skip, medium reverse, success on win
- Drag-to-reorder: rearrange your hand with a riffle sound effect
- Strict Joker UI: identity picker, resolution pill, masked power burst animation
- Force-upgrade: version-gated upgrade screen + recommended-update banner, driven by server protocol version
- Reconnection: exponential backoff with state rebuild on reconnect, "Reconnecting…" overlay
- Accessibility: VoiceOver labels ("Seven of Hearts"), Dynamic Type, 44pt touch targets, colorblind-friendly suit differentiation
The design system is a custom felt-and-gold palette (J7Colours, J7Cards, J7Components, J7Ornaments) inspired by the green baize of a card table.
Virtual lobby bots
A host can add or remove AI bot players in the lobby, letting you fill a table without waiting for human opponents. The bot decision engine makes legal plays respecting the full rules — it understands runs, stacking, Joker identity, and naked queens.
CI/CD pipeline
Every push to main that touches server/** triggers:
go test ./...go build- Multi-stage Docker build → ~10 MB final image
- Push to
ghcr.io/ambacelar/jack7/server:latest - Coolify webhook triggers pull + redeploy
What's next
I've designed a 1,268-line spec for ranked matchmaking with ELO/MMR, Apple Sign-In, StoreKit 2 subscription validation (com.jack7.ranked.yearly), PostgreSQL persistence, leaderboards, and player profiles. This is the monetisation layer — ranked play as a premium feature — but it waits until the casual game has enough traction and polish to justify the investment.