CI / Build and push docker image (push) Successful in 4m20s
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.
42 lines
1.5 KiB
SQL
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");
|