woggioni 7b3b38ccbc
CI / Build and push docker image (push) Successful in 4m20s
Rewrite the backend in Rust with Axum
Replace the Python/kaya server in server/ with a Rust Cargo workspace of
three crates mirroring the old layout: tavolo-platform (lobby API, live-game
store, websocket endpoint, deadline scheduler, stats/Elo, OIDC sessions),
tavolo-scopone (pure scopone scientifico rules plus the platform adapter)
and tavolo-app (composition root and the `tavolo` binary with
serve/migrate/backfill-elo).

The HTTP and WebSocket contracts, error messages, Redis key layout and
Postgres schema are unchanged, so the existing web/ frontend and in-flight
games keep working. Notable differences: sessions are JSON under
tavolo:session: (Python pickle sessions invalidate once), LOGGING_CONFIG is
ignored in favour of RUST_LOG, DATABASE_URL must be Postgres, sqlx migrations
replace aerich, and OpenTelemetry exports Rust process metrics instead of
CPython gc metrics (no Postgres/Redis client instrumentation).

Docker Compose and the Kubernetes manifest now run the single Rust image
(embedded migrations, /static and /assets served by the app); the release CI
keeps building server/Dockerfile. The full test suite (scopone rules,
platform store/deadlines/stats/websockets, OIDC login flow, scopone e2e) is
ported and runs with cargo test --workspace; Redis/Postgres integration tests
are gated on TEST_REDIS_URL/TEST_DATABASE_URL.
2026-10-02 13:54:55 +00:00
2026-09-18 19:18:04 +08:00
2026-10-01 12:38:29 +00:00

tavolo

A platform for multiplayer card games. The first game is scopone scientifico — the four-player, fixed-partnership Italian card game:

  • server/ — backend: Rust + Axum, OIDC login, live games in Redis, match statistics in Postgres. A Cargo workspace of three crates: the game-independent tavolo-platform, the scopone game tavolo-scopone, and the tavolo-app composition root (the tavolo binary: serve, migrate, backfill-elo). See server/README.md.
  • web/ — frontend: Rust + Sycamore compiled to WebAssembly, built with Trunk and styled with Bootstrap 5.3 (MIT, vendored under web/vendor/ so builds work offline) plus the custom felt theme in web/theme.css. Card images are the CC0 woodcut napoletane deck traced from a 1902 Naples print (SONDLecT/woodcut-napoletane).

Run the whole stack

docker compose up --build

Postgres, Redis, a mock OIDC provider (test users alice, bob, carol, dave), the database migrator and the app all come up together. The app — frontend and API — listens on http://127.0.0.1:8080.

Because both the browser and the app talk to the OIDC issuer at http://mockoauth:8180/tavolo, add a host entry once:

echo "127.0.0.1 mockoauth" | sudo tee -a /etc/hosts

Between hands

When a hand ends but the match is not decided, the game pauses on a scoring summary screen: every player sees how each category was won (carte, denara, settebello, primiera, scope — plus napola and asso pigliatutto when enabled) with the running totals and must click "Understood" before the next hand is dealt. If someone is away the next hand is dealt automatically after HAND_ACK_TIMEOUT_SECONDS (default 30s). The match-ending hand is explained on the final screen.

On your turn

Every turn shows a countdown (TURN_TIMEOUT_SECONDS, default 30s). If a player does not move — disconnected or fallen asleep — the server plays a random legal card for them (randomizing among the legal captures when the rules require a capture), so one absent player cannot stall the table.

Development

Backend (from server/):

cd server
cargo test --workspace                  # unit + integration suites
cargo run -p tavolo-app                 # serves on :8080 (Postgres required)
cargo run -p tavolo-app -- migrate      # apply the embedded sqlx migrations

The Redis- and Postgres-backed tests run when TEST_REDIS_URL / TEST_DATABASE_URL point at throwaway services (e.g. from docker compose up postgres redis plus the port mappings) and are skipped otherwise.

Frontend (from web/), with the backend running on :8080:

cd web
trunk serve          # SPA on http://localhost:8000, /api /auth /ws proxied

Trunk proxies /api, /auth and /ws to 127.0.0.1:8080 (see web/Trunk.toml). For the login redirect to land back on the dev server, run the backend with:

OIDC_0_PROVIDER=default \
OIDC_0_ISSUER=http://localhost:8180/tavolo \
OIDC_0_CLIENT_ID=tavolo \
OIDC_0_REDIRECT_URI=http://localhost:8080/auth/default/callback \
OIDC_0_POST_LOGIN_REDIRECT=http://localhost:8000/ \
OIDC_0_POST_LOGOUT_REDIRECT=http://localhost:8000/ \
  cargo run -p tavolo-app

Card images are committed under web/assets/cards/; web/fetch-cards.sh re-downloads them if needed.

S
Description
Scopone scientifico multiplayer backend built on the kaya framework
Readme
6 MiB
Languages
Python 73.5%
Rust 23.5%
CSS 1.9%
Dockerfile 0.6%
JavaScript 0.2%
Other 0.3%