- packages/engine: 시드 RNG(sfc32), GameDefinition 타입, 무작위 대국·정보 유출 테스트 도구 - packages/shared: WS 프로토콜 스키마, 닉네임·방 코드 규칙, 게임 카탈로그 - packages/games/omok: 한국식·렌주·자유룰, 재귀 금수 판정, 무르기·무승부·시계 (테스트 27개) - apps/server: SQLite 스키마, 게스트·디스코드 로그인, 세션, 방 관리(저장·복구·타이머·재접속), WS 게이트웨이, HTTP API Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
101 lines
2.8 KiB
SQL
101 lines
2.8 KiB
SQL
CREATE TABLE users (
|
|
id TEXT PRIMARY KEY,
|
|
kind TEXT NOT NULL CHECK (kind IN ('guest','member')),
|
|
nickname TEXT NOT NULL,
|
|
avatar_url TEXT,
|
|
use_avatar INTEGER NOT NULL DEFAULT 1,
|
|
settings_json TEXT NOT NULL DEFAULT '{}',
|
|
nick_changed_at INTEGER,
|
|
nick_change_count INTEGER NOT NULL DEFAULT 0,
|
|
created_at INTEGER NOT NULL,
|
|
last_seen_at INTEGER NOT NULL,
|
|
deleted_at INTEGER
|
|
);
|
|
|
|
CREATE TABLE oauth_accounts (
|
|
provider TEXT NOT NULL,
|
|
provider_user_id TEXT NOT NULL,
|
|
user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
username TEXT,
|
|
created_at INTEGER NOT NULL,
|
|
PRIMARY KEY (provider, provider_user_id)
|
|
);
|
|
CREATE INDEX oauth_accounts_user ON oauth_accounts(user_id);
|
|
|
|
CREATE TABLE sessions (
|
|
token_hash TEXT PRIMARY KEY,
|
|
user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
created_at INTEGER NOT NULL,
|
|
expires_at INTEGER NOT NULL,
|
|
last_used_at INTEGER NOT NULL,
|
|
user_agent TEXT
|
|
);
|
|
CREATE INDEX sessions_user ON sessions(user_id);
|
|
|
|
CREATE TABLE rooms (
|
|
id TEXT PRIMARY KEY,
|
|
code TEXT NOT NULL,
|
|
host_id TEXT NOT NULL,
|
|
game_id TEXT NOT NULL,
|
|
status TEXT NOT NULL CHECK (status IN ('lobby','playing','finished','paused','broken','closed')),
|
|
visibility TEXT NOT NULL,
|
|
config_json TEXT NOT NULL,
|
|
created_at INTEGER NOT NULL,
|
|
updated_at INTEGER NOT NULL,
|
|
closed_at INTEGER
|
|
);
|
|
CREATE UNIQUE INDEX rooms_open_code ON rooms(code) WHERE status <> 'closed';
|
|
CREATE INDEX rooms_status ON rooms(status);
|
|
|
|
CREATE TABLE room_state (
|
|
room_id TEXT PRIMARY KEY REFERENCES rooms(id) ON DELETE CASCADE,
|
|
seq INTEGER NOT NULL,
|
|
state_json TEXT NOT NULL,
|
|
updated_at INTEGER NOT NULL
|
|
);
|
|
|
|
CREATE TABLE room_log (
|
|
room_id TEXT NOT NULL,
|
|
seq INTEGER NOT NULL,
|
|
game_no INTEGER NOT NULL,
|
|
actor_id TEXT,
|
|
kind TEXT NOT NULL,
|
|
data_json TEXT NOT NULL,
|
|
at INTEGER NOT NULL,
|
|
PRIMARY KEY (room_id, seq)
|
|
);
|
|
|
|
CREATE TABLE games (
|
|
id TEXT PRIMARY KEY,
|
|
room_id TEXT NOT NULL,
|
|
game_no INTEGER NOT NULL,
|
|
game_id TEXT NOT NULL,
|
|
options_json TEXT NOT NULL,
|
|
seed_hash TEXT NOT NULL,
|
|
seed TEXT,
|
|
started_at INTEGER NOT NULL,
|
|
ended_at INTEGER,
|
|
end_reason TEXT,
|
|
result_json TEXT
|
|
);
|
|
CREATE INDEX games_room ON games(room_id);
|
|
|
|
CREATE TABLE game_players (
|
|
game_pk TEXT NOT NULL REFERENCES games(id) ON DELETE CASCADE,
|
|
user_id TEXT NOT NULL,
|
|
seat INTEGER NOT NULL,
|
|
rank INTEGER,
|
|
score REAL,
|
|
PRIMARY KEY (game_pk, user_id)
|
|
);
|
|
CREATE INDEX game_players_user ON game_players(user_id);
|
|
|
|
CREATE TABLE user_stats (
|
|
user_id TEXT NOT NULL,
|
|
game_id TEXT NOT NULL,
|
|
played INTEGER NOT NULL DEFAULT 0,
|
|
wins INTEGER NOT NULL DEFAULT 0,
|
|
draws INTEGER NOT NULL DEFAULT 0,
|
|
PRIMARY KEY (user_id, game_id)
|
|
);
|