A shared home for Hearts, Euchre, and Six Card Golf, with one account across three games, independent game servers, and a responsive hub.
Live at cards.shmem.dev
Play Hearts Β· Play Euchre Β· Play Golf Β· Manage your account
- Three games, one home β jump into Hearts, Euchre, or Golf from the same hub
- Shared accounts β sign in once and move between games with the same profile
- Account management β registration, email verification, password recovery, profile icons, and account deletion
- Independent game servers β each game owns its rules, saves, results, and real-time multiplayer
- Responsive design β a mobile-friendly hub with light and dark themes and each game's own visual identity
- One local command β start the hub, accounts, and game apps together with isolated development data and a local mail inbox
- Hearts β the classic four-player game, with AI opponents, online lobbies, achievements, and saved games. Project README.
- Euchre β partnership trick-taking, with five AI settings, private lobbies, team names, and leaderboards. Project README.
- Six Card Golf β a nine-hole family variant for 2β6 players, with bot opponents, private online rooms, and shared wins. Project README.
The game apps live in their own repositories. This repository contains the hub, shared accounts service, gateway, and integration tooling.
- HTML, CSS, and JavaScript β static hub and account pages, with no frontend framework
- Local fonts and SVG assets β visual styles shared with the game projects
- React + TypeScript + Vite β the game frontends, maintained in their own repositories
- Flask + Gunicorn β the independent accounts API
- SQLAlchemy + PostgreSQL β production account storage; SQLite for the local stack
- Argon2 + cookie sessions β password hashing and shared sign-in
- Alembic β explicit account-owned schema migrations
- Private service interfaces β scoped session validation, public profiles, and game-data cleanup on account deletion
- Node.js β local gateway, build scripts, and multi-service development runner
- Docker + Nginx β container builds, static hosting, API routing, and WebSocket forwarding
- GitHub Actions + GHCR β checks and independent, immutable component releases
- NixOS + Podman β production services managed in the sibling Infra repository
flowchart TD
browser[Browser] --> gateway[Cards gateway]
gateway --> hub[Hub & account pages]
gateway --> accounts[Shared accounts API]
gateway --> hearts[Hearts frontend & game server]
gateway --> euchre[Euchre frontend & game server]
gateway --> golf[Golf frontend & game server]
hearts -.-> accounts
euchre -.-> accounts
golf -.-> accounts
In production, the gateway serves the hub at / and account pages at /user/,
with the games under /hearts/, /euchre/, and /golf/. Account requests use
/api/account/; game APIs and Socket.IO connections route to their own services.
The accounts service owns identities, sessions, profiles, verification, and recovery. Game servers validate sessions through its private interface and own their gameplay data. Account deletion coordinates cleanup across configured games. Each component can be released and restarted independently.
See the accounts service and private account contract for the service boundary.
- Node.js 22.12+, Python 3.11, and uv
- Sibling checkouts named
cards,hearts, andeuchre - A sibling
golfcheckout to include Golf; the runner detects it automatically - A Font Awesome Pro package token to install the game frontends' licensed icons
Code/
βββ cards/
βββ hearts/
βββ euchre/
βββ golf/ # Optional; enables Golf in the shared runner
From the Cards repository, install the integration dependencies and backend environments:
npm ci --ignore-scripts
uv sync --project api --locked --extra dev
uv sync --project ../hearts/game-api --locked --extra dev
uv sync --project ../euchre/api --locked --extra devIf Golf is checked out, install its backend too:
uv sync --project ../golf/api --locked --extra devIn each game repository, copy .env.example to .env, set
FONTAWESOME_PACKAGE_TOKEN, and run npm run web:install. Golf can also reuse
the token from Euchre's .env. Keep tokens untracked. The hub itself needs no
package-install token.
Start the shared stack from Cards, or run the same command in any game repository:
npm run devOpen localhost:3000. The runner starts:
- Cards hub:
3000 - Game frontends: Hearts
3001, Euchre3002, Golf3003when present - Backend services: accounts
5100, Hearts5101, Euchre5102, Golf5103when present - Verification and recovery inbox: localhost:3000/__dev/mail/
Run the stack once and use localhost consistently so the shared session works
across ports. The local hub redirects game links to their frontend ports.
The runner refuses occupied ports; stop overlapping previews first.
Ctrl+C stops the processes it launched. npm run dev:split remains an alias.
SQLite databases, stable local keys, and file-only mail stay in the ignored
cards/.local/split-dev/ directory. Golf has its own golf.sqlite there.
Only this isolated stack's migrations run during startup. Existing developer
databases and saves remain in place and are not imported.
The runner strips inherited database and service settings, does not read production credentials, and sends no provider mail. Local setup does not migrate live data.
npm run dev:webin a game repository starts its frontend preview with separately configured backend destinations.npm run dev:combinedin Cards retains the previous hub/combined-API runner for compatibility work.dev:hubanddev:accountsare also legacy helpers.
See component releases and local integration for the compatibility and rehearsal workflows.
Build and preview the hub and account pages:
npm run build
npm run previewThe build copies public/ into dist/ and versions the hub stylesheet. Game
frontends build separately in their own repositories; this preview does not
start the shared backend stack.
Run Cards' focused checks from the repository root:
uv run --directory api --locked --extra dev pytest -q
npm run test:routing
npm run test:release
npm run test:splitThe split rehearsal uses disposable accounts and databases to check shared
login, Hearts and Euchre frontend proxies, game recovery, account deletion, and
independent service restarts. It verifies that existing developer databases
remain unchanged. Native Nginx routing also runs when NGINX_BIN is configured.
Golf's account and online integration checks live in its own repository:
npm run test:accounts and npm run test:online.
Container rehearsals are opt-in: test:images, test:postgres,
test:production-restore, and test:cutover. Follow their runbooks in docs/
for prerequisites, access requirements, and data isolation.
accounts-vMAJOR.MINOR.PATCHpublishes the shared accounts API.gateway-vMAJOR.MINOR.PATCHpublishes the Cards hub and gateway.game-vMAJOR.MINOR.PATCH/web-vMAJOR.MINOR.PATCHin each game repository publish its server / frontend.
Component workflows publish immutable image candidates with source and digest
records. Publishing does not deploy or update latest. Routine releases use
the deploy workflow, which tests, publishes, rehearses,
and promotes affected components through the host's release journal once the
required infrastructure capability is activated.
Infra owns production service configuration, credentials, runtime database
roles, and release policy. Containers use immutable image pins, and production
migrations run as explicit jobs rather than during service startup. Operator
procedures live in Infra's docs/cards-releases.md, docs/cards-operations.md,
and docs/golf-deployment.md.
The legacy publishing workflow is manual-only, requires acknowledgement, and refuses existing image versions. The guarded combined rollback remains available through Infra; the original split cutover receipt records the initial ownership handoff.
api/ Shared accounts service, migrations, and tests
public/ Hub, account pages, themes, fonts, and logos
scripts/ Build, development, integration, and release tooling
deploy/ Gateway image, Nginx routes, and rehearsal configurations
docs/ Service contracts, compatibility notes, and runbooks
release/ Component definitions and historical release receipts
skills/ Application deployment workflow and operator reference
Game logos and fonts are reused from Hearts, Euchre, and Golf. EB Garamond,
Terminal Dosis, and Fraunces are bundled locally with their SIL Open Font License
notices in public/assets/fonts/. Phosphor and Font Awesome notices live in
public/assets/ and public/assets/icons/. Navigation icons are bundled SVGs
from the games' licensed Font Awesome set.