Files
tavolo/server/.env.example
T
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

101 lines
4.4 KiB
Bash

# Database (match statistics). The app assembles the DSN from these
# parts; DATABASE_PORT may be left unset to use the driver default
# (5432 for Postgres). DATABASE_OPTIONS is a raw query string appended
# to the URL (e.g. ssl=require); leave empty for none.
DATABASE_ENGINE=postgres
DATABASE_HOST=localhost
DATABASE_PORT=5432
DATABASE_NAME=tavolo
DATABASE_USER=tavolo
DATABASE_PASSWORD=password
DATABASE_OPTIONS=
# Full-DSN override: when set, the parts above are ignored (managed-DB
# URLs). The Rust server supports Postgres only.
#DATABASE_URL=postgres://tavolo:password@localhost:5432/tavolo
# OIDC providers. Each provider is an indexed block: OIDC_<n>_PROVIDER
# (required; names the provider in the login URL /auth/<provider>/login and
# in its session state), OIDC_<n>_ISSUER, OIDC_<n>_CLIENT_ID,
# OIDC_<n>_CLIENT_SECRET (optional: leave unset for public clients),
# OIDC_<n>_REDIRECT_URI (defaults to
# http://localhost:8080/auth/<provider>/callback), OIDC_<n>_POST_LOGIN_REDIRECT
# and OIDC_<n>_POST_LOGOUT_REDIRECT (default /). Indices must be contiguous
# from 0; add a second provider with an OIDC_1_* block (and so on).
#
# The values below target the dev mock-oauth2-server (it does not validate
# clients, so any client id/secret works). For a real IdP like Keycloak,
# use its values and register the redirect URI there.
OIDC_0_PROVIDER=default
OIDC_0_ISSUER=http://localhost:8180/tavolo
OIDC_0_CLIENT_ID=tavolo
OIDC_0_CLIENT_SECRET=dev-secret
OIDC_0_REDIRECT_URI=http://localhost:8080/auth/default/callback
# A second provider, e.g. Google:
#OIDC_1_PROVIDER=google
#OIDC_1_ISSUER=https://accounts.google.com
#OIDC_1_CLIENT_ID=...
#OIDC_1_CLIENT_SECRET=...
#OIDC_1_REDIRECT_URI=http://localhost:8080/auth/google/callback
# Redis (session and live-game storage). Unset to fall back to in-memory
# stores (only sensible for local development with a single worker).
REDIS_URL=redis://localhost:6379/0
# How long a live game survives in Redis without activity.
GAME_TTL_SECONDS=86400
# Seconds the between-hands scoring summary waits for acknowledgements
# before dealing the next hand anyway.
HAND_ACK_TIMEOUT_SECONDS=30
# Seconds a player has to play before the server plays a random legal card
# for them (covers disconnects and idle players).
TURN_TIMEOUT_SECONDS=30
# Accepted for compatibility with the Python server but ignored: the Rust
# server configures logging through RUST_LOG (tracing env filter syntax).
#LOGGING_CONFIG=/path/to/logging.yaml
#RUST_LOG=tavolo=info,sqlx=warn,redis=warn
# CORS (via kaya-cors' CorsMixin; same semantics as Starlette's
# CORSMiddleware). Disabled unless CORS_ALLOW_ORIGINS or
# CORS_ALLOW_ORIGIN_REGEX is set — the app serves the SPA and the API from
# the same origin, so no CORS headers are needed by default.
# Comma-separated list of origins allowed to make cross-origin requests,
# or "*" for any origin:
#CORS_ALLOW_ORIGINS=https://example.com,https://app.example.com
# Optional regex (fullmatch) allowed origins are additionally checked
# against — handy for dynamic preview URLs:
#CORS_ALLOW_ORIGIN_REGEX=https://tavolo-[a-z0-9-]+\.vercel\.app
# Comma-separated allowed methods, or "*" for all (default GET):
#CORS_ALLOW_METHODS=GET,POST
# Comma-separated allowed request headers, or "*" to mirror back whatever
# the browser requests (default: only the CORS-safelisted headers):
#CORS_ALLOW_HEADERS=Authorization,Content-Type
# Allow cookies/credentials on cross-origin requests (1/true/yes/on):
#CORS_ALLOW_CREDENTIALS=false
# Comma-separated response headers exposed to the browser:
#CORS_EXPOSE_HEADERS=
# Seconds browsers may cache the preflight response (default 600):
#CORS_MAX_AGE=600
# OpenTelemetry (compiled in by default). Off unless OTEL_ENABLED is
# truthy; exports traces (HTTP/WebSocket) and process metrics, plus custom
# tavolo.active_users / tavolo.ongoing_games gauges and logs over OTLP/HTTP.
# The endpoint defaults to the standard OTEL_EXPORTER_OTLP_ENDPOINT
# (localhost:4318) when unset.
#OTEL_ENABLED=true
#OTEL_SERVICE_NAME=tavolo
#OTEL_EXPORTER_OTLP_ENDPOINT=http://otel-collector:4318
#OTEL_EXPORTER_OTLP_HEADERS=Authorization=Bearer token,X-Tenant=one
# Paths excluded from tracing and metrics (default /api/health).
#OTEL_EXCLUDED_PATHS=/api/health
# Metric export interval (ms, default 60000) and session/game count poll
# interval (seconds, default 15).
#OTEL_METRIC_EXPORT_INTERVAL_MILLIS=60000
#OTEL_METRICS_POLL_INTERVAL_SECONDS=15
# App server
APP_HOST=0.0.0.0
APP_PORT=8080