Repo is now a monorepo:
- server/: the kaya backend, unchanged in behaviour, plus:
- GET /api/me for SPA session detection
- last_move recorded on every play and broadcast in the game state, so
clients can show who played which card the moment they play it
- legal_moves per hand card for the player on turn (rules stay
server-side)
- static catch-all route serving the compiled SPA with index.html
fallback; Tortoise context now bound only for /api/* requests
- configurable OIDC post-login/logout redirects for dev against trunk
- web/: Sycamore 0.9 + WASM frontend (trunk): login via the OIDC flow,
lobby (create match / join by code), live game page over websocket with
card images (CC0 woodcut napoletane deck), capture picker, move banner,
game-over overlay, match history and leaderboard pages
- server/Dockerfile gains a rust+trunk stage building web/dist; the single
app image serves the SPA; compose builds from the repo root with
overridable ports/OIDC env
Verified end-to-end against the compose stack: four OIDC logins, game
creation, three joins by code, websocket play with broadcasts to all
players and out-of-turn rejection. 51 backend tests, mypy and cargo tests
all green.
108 lines
3.5 KiB
YAML
108 lines
3.5 KiB
YAML
services:
|
|
postgres:
|
|
image: postgres:18-alpine
|
|
environment:
|
|
POSTGRES_DB: scopa
|
|
POSTGRES_USER: scopa
|
|
POSTGRES_PASSWORD: scopa
|
|
ports:
|
|
- "5432:5432"
|
|
volumes:
|
|
- pgdata:/var/lib/postgresql
|
|
healthcheck:
|
|
test: ["CMD-SHELL", "pg_isready -U scopa"]
|
|
interval: 5s
|
|
timeout: 3s
|
|
retries: 10
|
|
|
|
# Mock OIDC provider (navikt/mock-oauth2-server). Zero manual setup:
|
|
# interactive login accepts any username (no password). Pre-configured
|
|
# players: alice, bob, carol, dave; any other username works too.
|
|
# The mock does not validate clients, so any client id/secret works.
|
|
#
|
|
# It listens on 8180 both inside and outside the network so the OIDC
|
|
# issuer URL (http://mockoauth:8180/scopa) is identical for
|
|
# container-to-container calls and for browser redirects (via the
|
|
# /etc/hosts entry documented in the README).
|
|
mockoauth:
|
|
# Derived image baking dev/mockoauth/config.json in (see
|
|
# dev/mockoauth/Dockerfile) — a bind mount would not work against
|
|
# containerized docker daemons.
|
|
build: ./server/dev/mockoauth
|
|
environment:
|
|
SERVER_PORT: "8180"
|
|
LOG_LEVEL: INFO
|
|
ports:
|
|
- "8180:8180"
|
|
|
|
# The JRE image has no usable healthcheck tooling; gate the app on the
|
|
# discovery endpoint being served instead.
|
|
mockoauth-init:
|
|
image: curlimages/curl
|
|
depends_on:
|
|
- mockoauth
|
|
entrypoint: >
|
|
/bin/sh -c "
|
|
until curl -sf http://mockoauth:8180/scopa/.well-known/openid-configuration > /dev/null; do
|
|
echo 'waiting for mockoauth...'; sleep 2;
|
|
done
|
|
"
|
|
|
|
# Sessions + live game state. No volume: sessions are disposable (worst
|
|
# case, users log in again) and games in progress have a TTL.
|
|
redis:
|
|
image: redis:8-alpine
|
|
ports:
|
|
- "6379:6379"
|
|
healthcheck:
|
|
test: ["CMD", "redis-cli", "ping"]
|
|
interval: 5s
|
|
timeout: 3s
|
|
retries: 10
|
|
|
|
# One-shot: applies pending aerich migrations before the app starts
|
|
# (build cache makes the second build of the same Dockerfile instant).
|
|
db-migrate:
|
|
build:
|
|
context: .
|
|
dockerfile: server/Dockerfile
|
|
# aerich reads [tool.aerich] from /app/pyproject.toml (default config
|
|
# file) and finds migrations in ./migrations relative to working_dir.
|
|
working_dir: /app
|
|
command: ["aerich", "upgrade"]
|
|
environment:
|
|
DATABASE_URL: postgres://scopa:scopa@postgres:5432/scopa
|
|
depends_on:
|
|
postgres:
|
|
condition: service_healthy
|
|
|
|
scopa:
|
|
build:
|
|
context: .
|
|
dockerfile: server/Dockerfile
|
|
depends_on:
|
|
postgres:
|
|
condition: service_healthy
|
|
db-migrate:
|
|
condition: service_completed_successfully
|
|
mockoauth-init:
|
|
condition: service_completed_successfully
|
|
redis:
|
|
condition: service_healthy
|
|
environment:
|
|
DATABASE_URL: postgres://scopa:scopa@postgres:5432/scopa
|
|
# By default the app and browsers reach the mock IdP under the same
|
|
# name (see README /etc/hosts note); override OIDC_ISSUER and
|
|
# OIDC_REDIRECT_URI to use a real provider or a different host port.
|
|
OIDC_ISSUER: ${OIDC_ISSUER:-http://mockoauth:8180/scopa}
|
|
# The mock OIDC server does not validate clients: any id/secret works.
|
|
OIDC_CLIENT_ID: scopa
|
|
OIDC_CLIENT_SECRET: ${OIDC_CLIENT_SECRET:-dev-secret}
|
|
OIDC_REDIRECT_URI: ${OIDC_REDIRECT_URI:-http://localhost:8080/auth/callback}
|
|
REDIS_URL: redis://redis:6379/0
|
|
ports:
|
|
- "127.0.0.1:${APP_PORT:-8080}:8080"
|
|
|
|
volumes:
|
|
pgdata:
|