Files
tavolo/server/crates/tavolo-app/migrations/0001_init.sql
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

42 lines
1.5 KiB
SQL

-- Final tavolo schema, expressed idempotently so the migration can be applied
-- to a database created by the Python aerich migrations as well as to a fresh
-- one. The `aerich` bookkeeping table (when present) is left untouched.
CREATE TABLE IF NOT EXISTS "match" (
"id" UUID NOT NULL PRIMARY KEY,
"game_type" VARCHAR(32) NOT NULL,
"started_at" TIMESTAMPTZ NOT NULL,
"finished_at" TIMESTAMPTZ NOT NULL,
"result" JSONB NOT NULL DEFAULT '{}'
);
CREATE INDEX IF NOT EXISTS "idx_match_game_type" ON "match" ("game_type");
CREATE TABLE IF NOT EXISTS "match_player" (
"id" UUID NOT NULL PRIMARY KEY,
"user_sub" VARCHAR(255) NOT NULL,
"display_name" VARCHAR(200) NOT NULL,
"seat" SMALLINT NOT NULL,
"team" VARCHAR(32),
"won" BOOL NOT NULL,
"match_id" UUID NOT NULL REFERENCES "match" ("id") ON DELETE CASCADE,
"score" DOUBLE PRECISION NOT NULL DEFAULT 0,
"elo_delta" SMALLINT,
"details" JSONB NOT NULL DEFAULT '{}',
CONSTRAINT "uid_match_player_match_user" UNIQUE ("match_id", "user_sub")
);
CREATE INDEX IF NOT EXISTS "idx_match_player_user_sub" ON "match_player" ("user_sub");
CREATE TABLE IF NOT EXISTS "player_rating" (
"id" UUID NOT NULL PRIMARY KEY,
"user_sub" VARCHAR(255) NOT NULL,
"game_type" VARCHAR(32) NOT NULL,
"rating" INT NOT NULL,
"matches_played" INT NOT NULL,
"updated_at" TIMESTAMPTZ NOT NULL,
CONSTRAINT "uid_player_rating_user_game" UNIQUE ("user_sub", "game_type")
);
CREATE INDEX IF NOT EXISTS "idx_player_rating_game_rating" ON "player_rating" ("game_type", "rating");