-- +goose Up
-- Consolidated baseline schema for the Scrabble backend. It squashes the former
-- incremental migrations (00001-00014) into one starting point; there is no
-- production data, so the squash carries no data migration. The per-feature
-- narrative that lived in the squashed migrations is preserved in git history and
-- in docs/ARCHITECTURE.md. Every object lives in the `backend` schema.
SET search_path = backend, pg_catalog;
-- Name: backend; Type: SCHEMA; Schema: -; Owner: -
--

CREATE SCHEMA IF NOT EXISTS backend;


SET default_tablespace = '';

SET default_table_access_method = heap;

--
-- Name: account_best_move; Type: TABLE; Schema: backend; Owner: -
--

CREATE TABLE backend.account_best_move (
    account_id uuid NOT NULL,
    variant text NOT NULL,
    score integer NOT NULL,
    tiles jsonb NOT NULL,
    updated_at timestamp with time zone DEFAULT now() NOT NULL
);


--
-- Name: account_roles; Type: TABLE; Schema: backend; Owner: -
--

CREATE TABLE backend.account_roles (
    account_id uuid NOT NULL,
    role text NOT NULL,
    granted_at timestamp with time zone DEFAULT now() NOT NULL
);


--
-- Name: account_stats; Type: TABLE; Schema: backend; Owner: -
--

CREATE TABLE backend.account_stats (
    account_id uuid NOT NULL,
    wins integer DEFAULT 0 NOT NULL,
    losses integer DEFAULT 0 NOT NULL,
    draws integer DEFAULT 0 NOT NULL,
    max_game_points integer DEFAULT 0 NOT NULL,
    max_word_points integer DEFAULT 0 NOT NULL,
    updated_at timestamp with time zone DEFAULT now() NOT NULL,
    moves integer DEFAULT 0 NOT NULL,
    hints_used integer DEFAULT 0 NOT NULL
);


--
-- Name: account_suspensions; Type: TABLE; Schema: backend; Owner: -
--

CREATE TABLE backend.account_suspensions (
    suspension_id uuid NOT NULL,
    account_id uuid NOT NULL,
    blocked_at timestamp with time zone DEFAULT now() NOT NULL,
    blocked_until timestamp with time zone,
    reason_en text,
    reason_ru text,
    reason_id uuid,
    lifted_at timestamp with time zone
);


--
-- Name: accounts; Type: TABLE; Schema: backend; Owner: -
--

CREATE TABLE backend.accounts (
    account_id uuid NOT NULL,
    display_name text DEFAULT ''::text NOT NULL,
    preferred_language text DEFAULT 'en'::text NOT NULL,
    time_zone text DEFAULT 'UTC'::text NOT NULL,
    block_chat boolean DEFAULT false NOT NULL,
    block_friend_requests boolean DEFAULT false NOT NULL,
    created_at timestamp with time zone DEFAULT now() NOT NULL,
    updated_at timestamp with time zone DEFAULT now() NOT NULL,
    away_start time without time zone DEFAULT '00:00:00'::time without time zone NOT NULL,
    away_end time without time zone DEFAULT '07:00:00'::time without time zone NOT NULL,
    hint_balance integer DEFAULT 0 NOT NULL,
    is_guest boolean DEFAULT false NOT NULL,
    notifications_in_app_only boolean DEFAULT true NOT NULL,
    paid_account boolean DEFAULT false NOT NULL,
    merged_into uuid,
    merged_at timestamp with time zone,
    flagged_high_rate_at timestamp with time zone,
    variant_preferences text[] DEFAULT ARRAY['erudit_ru'::text] NOT NULL,
    CONSTRAINT accounts_hint_balance_chk CHECK ((hint_balance >= 0)),
    CONSTRAINT accounts_preferred_language_chk CHECK ((preferred_language = ANY (ARRAY['en'::text, 'ru'::text]))),
    CONSTRAINT accounts_variant_preferences_nonempty_chk CHECK ((cardinality(variant_preferences) >= 1)),
    CONSTRAINT accounts_variant_preferences_subset_chk CHECK ((variant_preferences <@ ARRAY['scrabble_en'::text, 'scrabble_ru'::text, 'erudit_ru'::text]))
);


--
-- Name: ad_campaigns; Type: TABLE; Schema: backend; Owner: -
--

CREATE TABLE backend.ad_campaigns (
    campaign_id uuid NOT NULL,
    name text NOT NULL,
    weight integer NOT NULL,
    is_default boolean DEFAULT false NOT NULL,
    enabled boolean DEFAULT true NOT NULL,
    starts_at timestamp with time zone,
    ends_at timestamp with time zone,
    created_at timestamp with time zone DEFAULT now() NOT NULL,
    updated_at timestamp with time zone DEFAULT now() NOT NULL,
    CONSTRAINT ad_campaigns_default_window_chk CHECK (((NOT is_default) OR ((starts_at IS NULL) AND (ends_at IS NULL)))),
    CONSTRAINT ad_campaigns_weight_chk CHECK (((weight >= 1) AND (weight <= 100))),
    CONSTRAINT ad_campaigns_window_chk CHECK (((starts_at IS NULL) OR (ends_at IS NULL) OR (starts_at <= ends_at)))
);


--
-- Name: ad_messages; Type: TABLE; Schema: backend; Owner: -
--

CREATE TABLE backend.ad_messages (
    message_id uuid NOT NULL,
    campaign_id uuid NOT NULL,
    "position" integer DEFAULT 0 NOT NULL,
    body_en text NOT NULL,
    body_ru text NOT NULL,
    created_at timestamp with time zone DEFAULT now() NOT NULL,
    updated_at timestamp with time zone DEFAULT now() NOT NULL
);


--
-- Name: ad_settings; Type: TABLE; Schema: backend; Owner: -
--

CREATE TABLE backend.ad_settings (
    id boolean DEFAULT true NOT NULL,
    hold_ms integer NOT NULL,
    edge_pause_ms integer NOT NULL,
    scroll_px_per_sec integer NOT NULL,
    fade_out_ms integer NOT NULL,
    gap_ms integer NOT NULL,
    fade_in_ms integer NOT NULL,
    updated_at timestamp with time zone DEFAULT now() NOT NULL,
    CONSTRAINT ad_settings_singleton_chk CHECK (id)
);


--
-- Name: blocks; Type: TABLE; Schema: backend; Owner: -
--

CREATE TABLE backend.blocks (
    blocker_id uuid NOT NULL,
    blocked_id uuid NOT NULL,
    created_at timestamp with time zone DEFAULT now() NOT NULL,
    CONSTRAINT blocks_distinct_chk CHECK ((blocker_id <> blocked_id))
);


--
-- Name: chat_messages; Type: TABLE; Schema: backend; Owner: -
--

CREATE TABLE backend.chat_messages (
    message_id uuid NOT NULL,
    game_id uuid NOT NULL,
    sender_id uuid NOT NULL,
    kind text DEFAULT 'message'::text NOT NULL,
    body text DEFAULT ''::text NOT NULL,
    sender_ip text,
    created_at timestamp with time zone DEFAULT now() NOT NULL,
    unread_seats smallint DEFAULT 0 NOT NULL,
    CONSTRAINT chat_messages_body_len_chk CHECK ((char_length(body) <= 60)),
    CONSTRAINT chat_messages_kind_chk CHECK ((kind = ANY (ARRAY['message'::text, 'nudge'::text]))),
    CONSTRAINT chat_messages_nudge_empty_chk CHECK (((kind <> 'nudge'::text) OR (body = ''::text)))
);


--
-- Name: complaints; Type: TABLE; Schema: backend; Owner: -
--

CREATE TABLE backend.complaints (
    complaint_id uuid NOT NULL,
    complainant_id uuid NOT NULL,
    game_id uuid NOT NULL,
    variant text NOT NULL,
    dict_version text NOT NULL,
    word text NOT NULL,
    was_valid boolean NOT NULL,
    note text DEFAULT ''::text NOT NULL,
    status text DEFAULT 'open'::text NOT NULL,
    created_at timestamp with time zone DEFAULT now() NOT NULL,
    disposition text DEFAULT ''::text NOT NULL,
    resolution_note text DEFAULT ''::text NOT NULL,
    resolved_at timestamp with time zone,
    applied_in_version text DEFAULT ''::text NOT NULL,
    CONSTRAINT complaints_disposition_chk CHECK ((disposition = ANY (ARRAY[''::text, 'reject'::text, 'accept_add'::text, 'accept_remove'::text]))),
    CONSTRAINT complaints_status_chk CHECK ((status = ANY (ARRAY['open'::text, 'resolved'::text])))
);


--
-- Name: dictionary_state; Type: TABLE; Schema: backend; Owner: -
--

CREATE TABLE backend.dictionary_state (
    id boolean DEFAULT true NOT NULL,
    active_version text NOT NULL,
    updated_at timestamp with time zone DEFAULT now() NOT NULL,
    CONSTRAINT dictionary_state_singleton_chk CHECK (id)
);


--
-- Name: email_confirmations; Type: TABLE; Schema: backend; Owner: -
--

CREATE TABLE backend.email_confirmations (
    confirmation_id uuid NOT NULL,
    account_id uuid NOT NULL,
    email text NOT NULL,
    code_hash text NOT NULL,
    expires_at timestamp with time zone NOT NULL,
    attempts smallint DEFAULT 0 NOT NULL,
    consumed_at timestamp with time zone,
    created_at timestamp with time zone DEFAULT now() NOT NULL,
    CONSTRAINT email_confirmations_attempts_chk CHECK ((attempts >= 0))
);


--
-- Name: feedback_messages; Type: TABLE; Schema: backend; Owner: -
--

CREATE TABLE backend.feedback_messages (
    message_id uuid NOT NULL,
    account_id uuid NOT NULL,
    body text NOT NULL,
    attachment bytea,
    attachment_name text,
    sender_ip text,
    channel text NOT NULL,
    read_at timestamp with time zone,
    archived_at timestamp with time zone,
    reply_body text,
    replied_at timestamp with time zone,
    reply_read_at timestamp with time zone,
    created_at timestamp with time zone DEFAULT now() NOT NULL,
    lang text
);


--
-- Name: friend_codes; Type: TABLE; Schema: backend; Owner: -
--

CREATE TABLE backend.friend_codes (
    code_id uuid NOT NULL,
    account_id uuid NOT NULL,
    code_hash text NOT NULL,
    expires_at timestamp with time zone NOT NULL,
    consumed_at timestamp with time zone,
    created_at timestamp with time zone DEFAULT now() NOT NULL
);


--
-- Name: friendships; Type: TABLE; Schema: backend; Owner: -
--

CREATE TABLE backend.friendships (
    requester_id uuid NOT NULL,
    addressee_id uuid NOT NULL,
    status text DEFAULT 'pending'::text NOT NULL,
    created_at timestamp with time zone DEFAULT now() NOT NULL,
    responded_at timestamp with time zone,
    CONSTRAINT friendships_distinct_chk CHECK ((requester_id <> addressee_id)),
    CONSTRAINT friendships_status_chk CHECK ((status = ANY (ARRAY['pending'::text, 'accepted'::text, 'declined'::text])))
);


--
-- Name: game_drafts; Type: TABLE; Schema: backend; Owner: -
--

CREATE TABLE backend.game_drafts (
    game_id uuid NOT NULL,
    account_id uuid NOT NULL,
    rack_order text DEFAULT ''::text NOT NULL,
    board_tiles jsonb DEFAULT '[]'::jsonb NOT NULL,
    updated_at timestamp with time zone DEFAULT now() NOT NULL
);


--
-- Name: game_hidden; Type: TABLE; Schema: backend; Owner: -
--

CREATE TABLE backend.game_hidden (
    account_id uuid NOT NULL,
    game_id uuid NOT NULL,
    created_at timestamp with time zone DEFAULT now() NOT NULL
);


--
-- Name: game_invitation_invitees; Type: TABLE; Schema: backend; Owner: -
--

CREATE TABLE backend.game_invitation_invitees (
    invitation_id uuid NOT NULL,
    account_id uuid NOT NULL,
    seat smallint NOT NULL,
    response text DEFAULT 'pending'::text NOT NULL,
    responded_at timestamp with time zone,
    CONSTRAINT game_invitation_invitees_response_chk CHECK ((response = ANY (ARRAY['pending'::text, 'accepted'::text, 'declined'::text]))),
    CONSTRAINT game_invitation_invitees_seat_chk CHECK (((seat >= 1) AND (seat <= 3)))
);


--
-- Name: game_invitations; Type: TABLE; Schema: backend; Owner: -
--

CREATE TABLE backend.game_invitations (
    invitation_id uuid NOT NULL,
    inviter_id uuid NOT NULL,
    variant text NOT NULL,
    turn_timeout_secs integer NOT NULL,
    hints_allowed boolean DEFAULT true NOT NULL,
    hints_per_player smallint DEFAULT 1 NOT NULL,
    dropout_tiles text DEFAULT 'remove'::text NOT NULL,
    multiple_words_per_turn boolean DEFAULT true NOT NULL,
    status text DEFAULT 'pending'::text NOT NULL,
    game_id uuid,
    expires_at timestamp with time zone NOT NULL,
    created_at timestamp with time zone DEFAULT now() NOT NULL,
    updated_at timestamp with time zone DEFAULT now() NOT NULL,
    CONSTRAINT game_invitations_dropout_tiles_chk CHECK ((dropout_tiles = ANY (ARRAY['remove'::text, 'return'::text]))),
    CONSTRAINT game_invitations_hints_per_player_chk CHECK ((hints_per_player >= 0)),
    CONSTRAINT game_invitations_status_chk CHECK ((status = ANY (ARRAY['pending'::text, 'declined'::text, 'cancelled'::text, 'expired'::text, 'started'::text]))),
    CONSTRAINT game_invitations_turn_timeout_chk CHECK ((turn_timeout_secs > 0)),
    CONSTRAINT game_invitations_variant_chk CHECK ((variant = ANY (ARRAY['scrabble_en'::text, 'scrabble_ru'::text, 'erudit_ru'::text])))
);


--
-- Name: game_moves; Type: TABLE; Schema: backend; Owner: -
--

CREATE TABLE backend.game_moves (
    game_id uuid NOT NULL,
    seq integer NOT NULL,
    seat smallint NOT NULL,
    action text NOT NULL,
    score integer DEFAULT 0 NOT NULL,
    running_total integer DEFAULT 0 NOT NULL,
    exchanged_count smallint DEFAULT 0 NOT NULL,
    payload text DEFAULT '{}'::text NOT NULL,
    created_at timestamp with time zone DEFAULT now() NOT NULL,
    CONSTRAINT game_moves_action_chk CHECK ((action = ANY (ARRAY['play'::text, 'pass'::text, 'exchange'::text, 'resign'::text, 'timeout'::text])))
);


--
-- Name: game_players; Type: TABLE; Schema: backend; Owner: -
--

CREATE TABLE backend.game_players (
    game_id uuid NOT NULL,
    seat smallint NOT NULL,
    account_id uuid,
    score integer DEFAULT 0 NOT NULL,
    hints_used smallint DEFAULT 0 NOT NULL,
    is_winner boolean DEFAULT false NOT NULL,
    display_name text DEFAULT ''::text NOT NULL
);


--
-- Name: game_setup_draws; Type: TABLE; Schema: backend; Owner: -
--

CREATE TABLE backend.game_setup_draws (
    game_id uuid NOT NULL,
    round smallint NOT NULL,
    pick_no smallint NOT NULL,
    account_id uuid,
    letter text NOT NULL,
    is_blank boolean DEFAULT false NOT NULL,
    draw_rank smallint NOT NULL,
    created_at timestamp with time zone DEFAULT now() NOT NULL
);


--
-- Name: games; Type: TABLE; Schema: backend; Owner: -
--

CREATE TABLE backend.games (
    game_id uuid NOT NULL,
    variant text NOT NULL,
    dict_version text NOT NULL,
    seed bigint NOT NULL,
    status text DEFAULT 'active'::text NOT NULL,
    players smallint NOT NULL,
    to_move smallint DEFAULT 0 NOT NULL,
    turn_started_at timestamp with time zone DEFAULT now() NOT NULL,
    turn_timeout_secs integer NOT NULL,
    hints_allowed boolean DEFAULT true NOT NULL,
    hints_per_player smallint DEFAULT 1 NOT NULL,
    move_count integer DEFAULT 0 NOT NULL,
    end_reason text,
    created_at timestamp with time zone DEFAULT now() NOT NULL,
    updated_at timestamp with time zone DEFAULT now() NOT NULL,
    finished_at timestamp with time zone,
    open_deadline_at timestamp with time zone,
    dropout_tiles text DEFAULT 'remove'::text NOT NULL,
    multiple_words_per_turn boolean DEFAULT true NOT NULL,
    vs_ai boolean DEFAULT false NOT NULL,
    CONSTRAINT games_dropout_tiles_chk CHECK ((dropout_tiles = ANY (ARRAY['remove'::text, 'return'::text]))),
    CONSTRAINT games_end_reason_chk CHECK (((end_reason IS NULL) OR (end_reason = ANY (ARRAY['out_of_tiles'::text, 'scoreless'::text, 'resign'::text, 'timeout'::text, 'aborted'::text])))),
    CONSTRAINT games_hints_per_player_chk CHECK ((hints_per_player >= 0)),
    CONSTRAINT games_players_chk CHECK (((players >= 2) AND (players <= 4))),
    CONSTRAINT games_status_chk CHECK ((status = ANY (ARRAY['active'::text, 'finished'::text, 'open'::text]))),
    CONSTRAINT games_to_move_chk CHECK (((to_move >= 0) AND (to_move < players))),
    CONSTRAINT games_turn_timeout_chk CHECK ((turn_timeout_secs > 0)),
    CONSTRAINT games_variant_chk CHECK ((variant = ANY (ARRAY['scrabble_en'::text, 'scrabble_ru'::text, 'erudit_ru'::text])))
);


--
-- Name: identities; Type: TABLE; Schema: backend; Owner: -
--

CREATE TABLE backend.identities (
    identity_id uuid NOT NULL,
    account_id uuid NOT NULL,
    kind text NOT NULL,
    external_id text NOT NULL,
    confirmed boolean DEFAULT false NOT NULL,
    created_at timestamp with time zone DEFAULT now() NOT NULL,
    CONSTRAINT identities_kind_chk CHECK ((kind = ANY (ARRAY['telegram'::text, 'email'::text, 'robot'::text])))
);


--
-- Name: robot_blocks; Type: TABLE; Schema: backend; Owner: -
--

CREATE TABLE backend.robot_blocks (
    id uuid NOT NULL,
    blocker_id uuid NOT NULL,
    game_id uuid NOT NULL,
    seat smallint NOT NULL,
    robot_id uuid NOT NULL,
    display_name text NOT NULL,
    created_at timestamp with time zone DEFAULT now() NOT NULL
);


--
-- Name: robot_friend_requests; Type: TABLE; Schema: backend; Owner: -
--

CREATE TABLE backend.robot_friend_requests (
    id uuid NOT NULL,
    requester_id uuid NOT NULL,
    game_id uuid NOT NULL,
    seat smallint NOT NULL,
    robot_id uuid NOT NULL,
    display_name text NOT NULL,
    created_at timestamp with time zone DEFAULT now() NOT NULL
);


--
-- Name: sessions; Type: TABLE; Schema: backend; Owner: -
--

CREATE TABLE backend.sessions (
    session_id uuid NOT NULL,
    account_id uuid NOT NULL,
    token_hash text NOT NULL,
    status text DEFAULT 'active'::text NOT NULL,
    created_at timestamp with time zone DEFAULT now() NOT NULL,
    last_seen_at timestamp with time zone,
    revoked_at timestamp with time zone,
    CONSTRAINT sessions_status_chk CHECK ((status = ANY (ARRAY['active'::text, 'revoked'::text])))
);


--
-- Name: suspension_reasons; Type: TABLE; Schema: backend; Owner: -
--

CREATE TABLE backend.suspension_reasons (
    reason_id uuid NOT NULL,
    text_en text NOT NULL,
    text_ru text NOT NULL,
    created_at timestamp with time zone DEFAULT now() NOT NULL,
    updated_at timestamp with time zone DEFAULT now() NOT NULL
);


--
-- Name: account_best_move account_best_move_pkey; Type: CONSTRAINT; Schema: backend; Owner: -
--

ALTER TABLE ONLY backend.account_best_move
    ADD CONSTRAINT account_best_move_pkey PRIMARY KEY (account_id, variant);


--
-- Name: account_roles account_roles_pkey; Type: CONSTRAINT; Schema: backend; Owner: -
--

ALTER TABLE ONLY backend.account_roles
    ADD CONSTRAINT account_roles_pkey PRIMARY KEY (account_id, role);


--
-- Name: account_stats account_stats_pkey; Type: CONSTRAINT; Schema: backend; Owner: -
--

ALTER TABLE ONLY backend.account_stats
    ADD CONSTRAINT account_stats_pkey PRIMARY KEY (account_id);


--
-- Name: account_suspensions account_suspensions_pkey; Type: CONSTRAINT; Schema: backend; Owner: -
--

ALTER TABLE ONLY backend.account_suspensions
    ADD CONSTRAINT account_suspensions_pkey PRIMARY KEY (suspension_id);


--
-- Name: accounts accounts_pkey; Type: CONSTRAINT; Schema: backend; Owner: -
--

ALTER TABLE ONLY backend.accounts
    ADD CONSTRAINT accounts_pkey PRIMARY KEY (account_id);


--
-- Name: ad_campaigns ad_campaigns_pkey; Type: CONSTRAINT; Schema: backend; Owner: -
--

ALTER TABLE ONLY backend.ad_campaigns
    ADD CONSTRAINT ad_campaigns_pkey PRIMARY KEY (campaign_id);


--
-- Name: ad_messages ad_messages_pkey; Type: CONSTRAINT; Schema: backend; Owner: -
--

ALTER TABLE ONLY backend.ad_messages
    ADD CONSTRAINT ad_messages_pkey PRIMARY KEY (message_id);


--
-- Name: ad_settings ad_settings_pkey; Type: CONSTRAINT; Schema: backend; Owner: -
--

ALTER TABLE ONLY backend.ad_settings
    ADD CONSTRAINT ad_settings_pkey PRIMARY KEY (id);


--
-- Name: blocks blocks_pkey; Type: CONSTRAINT; Schema: backend; Owner: -
--

ALTER TABLE ONLY backend.blocks
    ADD CONSTRAINT blocks_pkey PRIMARY KEY (blocker_id, blocked_id);


--
-- Name: chat_messages chat_messages_pkey; Type: CONSTRAINT; Schema: backend; Owner: -
--

ALTER TABLE ONLY backend.chat_messages
    ADD CONSTRAINT chat_messages_pkey PRIMARY KEY (message_id);


--
-- Name: complaints complaints_pkey; Type: CONSTRAINT; Schema: backend; Owner: -
--

ALTER TABLE ONLY backend.complaints
    ADD CONSTRAINT complaints_pkey PRIMARY KEY (complaint_id);


--
-- Name: dictionary_state dictionary_state_pkey; Type: CONSTRAINT; Schema: backend; Owner: -
--

ALTER TABLE ONLY backend.dictionary_state
    ADD CONSTRAINT dictionary_state_pkey PRIMARY KEY (id);


--
-- Name: email_confirmations email_confirmations_pkey; Type: CONSTRAINT; Schema: backend; Owner: -
--

ALTER TABLE ONLY backend.email_confirmations
    ADD CONSTRAINT email_confirmations_pkey PRIMARY KEY (confirmation_id);


--
-- Name: feedback_messages feedback_messages_pkey; Type: CONSTRAINT; Schema: backend; Owner: -
--

ALTER TABLE ONLY backend.feedback_messages
    ADD CONSTRAINT feedback_messages_pkey PRIMARY KEY (message_id);


--
-- Name: friend_codes friend_codes_pkey; Type: CONSTRAINT; Schema: backend; Owner: -
--

ALTER TABLE ONLY backend.friend_codes
    ADD CONSTRAINT friend_codes_pkey PRIMARY KEY (code_id);


--
-- Name: friendships friendships_pkey; Type: CONSTRAINT; Schema: backend; Owner: -
--

ALTER TABLE ONLY backend.friendships
    ADD CONSTRAINT friendships_pkey PRIMARY KEY (requester_id, addressee_id);


--
-- Name: game_drafts game_drafts_pkey; Type: CONSTRAINT; Schema: backend; Owner: -
--

ALTER TABLE ONLY backend.game_drafts
    ADD CONSTRAINT game_drafts_pkey PRIMARY KEY (game_id, account_id);


--
-- Name: game_hidden game_hidden_pkey; Type: CONSTRAINT; Schema: backend; Owner: -
--

ALTER TABLE ONLY backend.game_hidden
    ADD CONSTRAINT game_hidden_pkey PRIMARY KEY (account_id, game_id);


--
-- Name: game_invitation_invitees game_invitation_invitees_pkey; Type: CONSTRAINT; Schema: backend; Owner: -
--

ALTER TABLE ONLY backend.game_invitation_invitees
    ADD CONSTRAINT game_invitation_invitees_pkey PRIMARY KEY (invitation_id, account_id);


--
-- Name: game_invitations game_invitations_pkey; Type: CONSTRAINT; Schema: backend; Owner: -
--

ALTER TABLE ONLY backend.game_invitations
    ADD CONSTRAINT game_invitations_pkey PRIMARY KEY (invitation_id);


--
-- Name: game_moves game_moves_pkey; Type: CONSTRAINT; Schema: backend; Owner: -
--

ALTER TABLE ONLY backend.game_moves
    ADD CONSTRAINT game_moves_pkey PRIMARY KEY (game_id, seq);


--
-- Name: game_players game_players_account_key; Type: CONSTRAINT; Schema: backend; Owner: -
--

ALTER TABLE ONLY backend.game_players
    ADD CONSTRAINT game_players_account_key UNIQUE (game_id, account_id);


--
-- Name: game_players game_players_pkey; Type: CONSTRAINT; Schema: backend; Owner: -
--

ALTER TABLE ONLY backend.game_players
    ADD CONSTRAINT game_players_pkey PRIMARY KEY (game_id, seat);


--
-- Name: game_setup_draws game_setup_draws_pkey; Type: CONSTRAINT; Schema: backend; Owner: -
--

ALTER TABLE ONLY backend.game_setup_draws
    ADD CONSTRAINT game_setup_draws_pkey PRIMARY KEY (game_id, round, pick_no);


--
-- Name: games games_pkey; Type: CONSTRAINT; Schema: backend; Owner: -
--

ALTER TABLE ONLY backend.games
    ADD CONSTRAINT games_pkey PRIMARY KEY (game_id);


--
-- Name: identities identities_kind_external_id_key; Type: CONSTRAINT; Schema: backend; Owner: -
--

ALTER TABLE ONLY backend.identities
    ADD CONSTRAINT identities_kind_external_id_key UNIQUE (kind, external_id);


--
-- Name: identities identities_pkey; Type: CONSTRAINT; Schema: backend; Owner: -
--

ALTER TABLE ONLY backend.identities
    ADD CONSTRAINT identities_pkey PRIMARY KEY (identity_id);


--
-- Name: robot_blocks robot_blocks_blocker_id_game_id_seat_key; Type: CONSTRAINT; Schema: backend; Owner: -
--

ALTER TABLE ONLY backend.robot_blocks
    ADD CONSTRAINT robot_blocks_blocker_id_game_id_seat_key UNIQUE (blocker_id, game_id, seat);


--
-- Name: robot_blocks robot_blocks_pkey; Type: CONSTRAINT; Schema: backend; Owner: -
--

ALTER TABLE ONLY backend.robot_blocks
    ADD CONSTRAINT robot_blocks_pkey PRIMARY KEY (id);


--
-- Name: robot_friend_requests robot_friend_requests_pkey; Type: CONSTRAINT; Schema: backend; Owner: -
--

ALTER TABLE ONLY backend.robot_friend_requests
    ADD CONSTRAINT robot_friend_requests_pkey PRIMARY KEY (id);


--
-- Name: robot_friend_requests robot_friend_requests_requester_id_game_id_seat_key; Type: CONSTRAINT; Schema: backend; Owner: -
--

ALTER TABLE ONLY backend.robot_friend_requests
    ADD CONSTRAINT robot_friend_requests_requester_id_game_id_seat_key UNIQUE (requester_id, game_id, seat);


--
-- Name: sessions sessions_pkey; Type: CONSTRAINT; Schema: backend; Owner: -
--

ALTER TABLE ONLY backend.sessions
    ADD CONSTRAINT sessions_pkey PRIMARY KEY (session_id);


--
-- Name: sessions sessions_token_hash_key; Type: CONSTRAINT; Schema: backend; Owner: -
--

ALTER TABLE ONLY backend.sessions
    ADD CONSTRAINT sessions_token_hash_key UNIQUE (token_hash);


--
-- Name: suspension_reasons suspension_reasons_pkey; Type: CONSTRAINT; Schema: backend; Owner: -
--

ALTER TABLE ONLY backend.suspension_reasons
    ADD CONSTRAINT suspension_reasons_pkey PRIMARY KEY (reason_id);


--
-- Name: account_suspensions_account_idx; Type: INDEX; Schema: backend; Owner: -
--

CREATE INDEX account_suspensions_account_idx ON backend.account_suspensions USING btree (account_id, blocked_at DESC);


--
-- Name: ad_campaigns_default_idx; Type: INDEX; Schema: backend; Owner: -
--

CREATE UNIQUE INDEX ad_campaigns_default_idx ON backend.ad_campaigns USING btree (is_default) WHERE is_default;


--
-- Name: ad_messages_campaign_idx; Type: INDEX; Schema: backend; Owner: -
--

CREATE INDEX ad_messages_campaign_idx ON backend.ad_messages USING btree (campaign_id, "position");


--
-- Name: blocks_blocked_idx; Type: INDEX; Schema: backend; Owner: -
--

CREATE INDEX blocks_blocked_idx ON backend.blocks USING btree (blocked_id);


--
-- Name: chat_messages_game_idx; Type: INDEX; Schema: backend; Owner: -
--

CREATE INDEX chat_messages_game_idx ON backend.chat_messages USING btree (game_id, created_at);


--
-- Name: chat_messages_nudge_idx; Type: INDEX; Schema: backend; Owner: -
--

CREATE INDEX chat_messages_nudge_idx ON backend.chat_messages USING btree (game_id, sender_id, created_at) WHERE (kind = 'nudge'::text);


--
-- Name: chat_messages_unread_idx; Type: INDEX; Schema: backend; Owner: -
--

CREATE INDEX chat_messages_unread_idx ON backend.chat_messages USING btree (game_id) WHERE (unread_seats <> 0);


--
-- Name: complaints_status_idx; Type: INDEX; Schema: backend; Owner: -
--

CREATE INDEX complaints_status_idx ON backend.complaints USING btree (status);


--
-- Name: email_confirmations_account_idx; Type: INDEX; Schema: backend; Owner: -
--

CREATE INDEX email_confirmations_account_idx ON backend.email_confirmations USING btree (account_id);


--
-- Name: feedback_messages_account_idx; Type: INDEX; Schema: backend; Owner: -
--

CREATE INDEX feedback_messages_account_idx ON backend.feedback_messages USING btree (account_id, created_at DESC);


--
-- Name: feedback_messages_created_idx; Type: INDEX; Schema: backend; Owner: -
--

CREATE INDEX feedback_messages_created_idx ON backend.feedback_messages USING btree (created_at DESC);


--
-- Name: friend_codes_account_idx; Type: INDEX; Schema: backend; Owner: -
--

CREATE INDEX friend_codes_account_idx ON backend.friend_codes USING btree (account_id);


--
-- Name: friend_codes_code_hash_idx; Type: INDEX; Schema: backend; Owner: -
--

CREATE INDEX friend_codes_code_hash_idx ON backend.friend_codes USING btree (code_hash);


--
-- Name: friendships_addressee_idx; Type: INDEX; Schema: backend; Owner: -
--

CREATE INDEX friendships_addressee_idx ON backend.friendships USING btree (addressee_id);


--
-- Name: game_invitation_invitees_account_idx; Type: INDEX; Schema: backend; Owner: -
--

CREATE INDEX game_invitation_invitees_account_idx ON backend.game_invitation_invitees USING btree (account_id);


--
-- Name: game_invitations_inviter_idx; Type: INDEX; Schema: backend; Owner: -
--

CREATE INDEX game_invitations_inviter_idx ON backend.game_invitations USING btree (inviter_id);


--
-- Name: game_players_account_idx; Type: INDEX; Schema: backend; Owner: -
--

CREATE INDEX game_players_account_idx ON backend.game_players USING btree (account_id);


--
-- Name: games_active_idx; Type: INDEX; Schema: backend; Owner: -
--

CREATE INDEX games_active_idx ON backend.games USING btree (turn_started_at) WHERE (status = 'active'::text);


--
-- Name: games_open_idx; Type: INDEX; Schema: backend; Owner: -
--

CREATE INDEX games_open_idx ON backend.games USING btree (open_deadline_at) WHERE (status = 'open'::text);


--
-- Name: games_open_match_idx; Type: INDEX; Schema: backend; Owner: -
--

CREATE INDEX games_open_match_idx ON backend.games USING btree (variant, multiple_words_per_turn, created_at) WHERE (status = 'open'::text);


--
-- Name: identities_account_idx; Type: INDEX; Schema: backend; Owner: -
--

CREATE INDEX identities_account_idx ON backend.identities USING btree (account_id);


--
-- Name: robot_blocks_blocker_idx; Type: INDEX; Schema: backend; Owner: -
--

CREATE INDEX robot_blocks_blocker_idx ON backend.robot_blocks USING btree (blocker_id);


--
-- Name: robot_friend_requests_requester_idx; Type: INDEX; Schema: backend; Owner: -
--

CREATE INDEX robot_friend_requests_requester_idx ON backend.robot_friend_requests USING btree (requester_id);


--
-- Name: sessions_account_idx; Type: INDEX; Schema: backend; Owner: -
--

CREATE INDEX sessions_account_idx ON backend.sessions USING btree (account_id);


--
-- Name: account_best_move account_best_move_account_id_fkey; Type: FK CONSTRAINT; Schema: backend; Owner: -
--

ALTER TABLE ONLY backend.account_best_move
    ADD CONSTRAINT account_best_move_account_id_fkey FOREIGN KEY (account_id) REFERENCES backend.accounts(account_id) ON DELETE CASCADE;


--
-- Name: account_roles account_roles_account_id_fkey; Type: FK CONSTRAINT; Schema: backend; Owner: -
--

ALTER TABLE ONLY backend.account_roles
    ADD CONSTRAINT account_roles_account_id_fkey FOREIGN KEY (account_id) REFERENCES backend.accounts(account_id) ON DELETE CASCADE;


--
-- Name: account_stats account_stats_account_id_fkey; Type: FK CONSTRAINT; Schema: backend; Owner: -
--

ALTER TABLE ONLY backend.account_stats
    ADD CONSTRAINT account_stats_account_id_fkey FOREIGN KEY (account_id) REFERENCES backend.accounts(account_id) ON DELETE CASCADE;


--
-- Name: account_suspensions account_suspensions_account_id_fkey; Type: FK CONSTRAINT; Schema: backend; Owner: -
--

ALTER TABLE ONLY backend.account_suspensions
    ADD CONSTRAINT account_suspensions_account_id_fkey FOREIGN KEY (account_id) REFERENCES backend.accounts(account_id) ON DELETE CASCADE;


--
-- Name: account_suspensions account_suspensions_reason_id_fkey; Type: FK CONSTRAINT; Schema: backend; Owner: -
--

ALTER TABLE ONLY backend.account_suspensions
    ADD CONSTRAINT account_suspensions_reason_id_fkey FOREIGN KEY (reason_id) REFERENCES backend.suspension_reasons(reason_id) ON DELETE SET NULL;


--
-- Name: accounts accounts_merged_into_fkey; Type: FK CONSTRAINT; Schema: backend; Owner: -
--

ALTER TABLE ONLY backend.accounts
    ADD CONSTRAINT accounts_merged_into_fkey FOREIGN KEY (merged_into) REFERENCES backend.accounts(account_id) ON DELETE SET NULL;


--
-- Name: ad_messages ad_messages_campaign_id_fkey; Type: FK CONSTRAINT; Schema: backend; Owner: -
--

ALTER TABLE ONLY backend.ad_messages
    ADD CONSTRAINT ad_messages_campaign_id_fkey FOREIGN KEY (campaign_id) REFERENCES backend.ad_campaigns(campaign_id) ON DELETE CASCADE;


--
-- Name: blocks blocks_blocked_id_fkey; Type: FK CONSTRAINT; Schema: backend; Owner: -
--

ALTER TABLE ONLY backend.blocks
    ADD CONSTRAINT blocks_blocked_id_fkey FOREIGN KEY (blocked_id) REFERENCES backend.accounts(account_id) ON DELETE CASCADE;


--
-- Name: blocks blocks_blocker_id_fkey; Type: FK CONSTRAINT; Schema: backend; Owner: -
--

ALTER TABLE ONLY backend.blocks
    ADD CONSTRAINT blocks_blocker_id_fkey FOREIGN KEY (blocker_id) REFERENCES backend.accounts(account_id) ON DELETE CASCADE;


--
-- Name: chat_messages chat_messages_game_id_fkey; Type: FK CONSTRAINT; Schema: backend; Owner: -
--

ALTER TABLE ONLY backend.chat_messages
    ADD CONSTRAINT chat_messages_game_id_fkey FOREIGN KEY (game_id) REFERENCES backend.games(game_id) ON DELETE CASCADE;


--
-- Name: chat_messages chat_messages_sender_id_fkey; Type: FK CONSTRAINT; Schema: backend; Owner: -
--

ALTER TABLE ONLY backend.chat_messages
    ADD CONSTRAINT chat_messages_sender_id_fkey FOREIGN KEY (sender_id) REFERENCES backend.accounts(account_id);


--
-- Name: complaints complaints_complainant_id_fkey; Type: FK CONSTRAINT; Schema: backend; Owner: -
--

ALTER TABLE ONLY backend.complaints
    ADD CONSTRAINT complaints_complainant_id_fkey FOREIGN KEY (complainant_id) REFERENCES backend.accounts(account_id);


--
-- Name: complaints complaints_game_id_fkey; Type: FK CONSTRAINT; Schema: backend; Owner: -
--

ALTER TABLE ONLY backend.complaints
    ADD CONSTRAINT complaints_game_id_fkey FOREIGN KEY (game_id) REFERENCES backend.games(game_id) ON DELETE CASCADE;


--
-- Name: email_confirmations email_confirmations_account_id_fkey; Type: FK CONSTRAINT; Schema: backend; Owner: -
--

ALTER TABLE ONLY backend.email_confirmations
    ADD CONSTRAINT email_confirmations_account_id_fkey FOREIGN KEY (account_id) REFERENCES backend.accounts(account_id) ON DELETE CASCADE;


--
-- Name: feedback_messages feedback_messages_account_id_fkey; Type: FK CONSTRAINT; Schema: backend; Owner: -
--

ALTER TABLE ONLY backend.feedback_messages
    ADD CONSTRAINT feedback_messages_account_id_fkey FOREIGN KEY (account_id) REFERENCES backend.accounts(account_id) ON DELETE CASCADE;


--
-- Name: friend_codes friend_codes_account_id_fkey; Type: FK CONSTRAINT; Schema: backend; Owner: -
--

ALTER TABLE ONLY backend.friend_codes
    ADD CONSTRAINT friend_codes_account_id_fkey FOREIGN KEY (account_id) REFERENCES backend.accounts(account_id) ON DELETE CASCADE;


--
-- Name: friendships friendships_addressee_id_fkey; Type: FK CONSTRAINT; Schema: backend; Owner: -
--

ALTER TABLE ONLY backend.friendships
    ADD CONSTRAINT friendships_addressee_id_fkey FOREIGN KEY (addressee_id) REFERENCES backend.accounts(account_id) ON DELETE CASCADE;


--
-- Name: friendships friendships_requester_id_fkey; Type: FK CONSTRAINT; Schema: backend; Owner: -
--

ALTER TABLE ONLY backend.friendships
    ADD CONSTRAINT friendships_requester_id_fkey FOREIGN KEY (requester_id) REFERENCES backend.accounts(account_id) ON DELETE CASCADE;


--
-- Name: game_drafts game_drafts_account_id_fkey; Type: FK CONSTRAINT; Schema: backend; Owner: -
--

ALTER TABLE ONLY backend.game_drafts
    ADD CONSTRAINT game_drafts_account_id_fkey FOREIGN KEY (account_id) REFERENCES backend.accounts(account_id) ON DELETE CASCADE;


--
-- Name: game_drafts game_drafts_game_id_fkey; Type: FK CONSTRAINT; Schema: backend; Owner: -
--

ALTER TABLE ONLY backend.game_drafts
    ADD CONSTRAINT game_drafts_game_id_fkey FOREIGN KEY (game_id) REFERENCES backend.games(game_id) ON DELETE CASCADE;


--
-- Name: game_hidden game_hidden_account_id_fkey; Type: FK CONSTRAINT; Schema: backend; Owner: -
--

ALTER TABLE ONLY backend.game_hidden
    ADD CONSTRAINT game_hidden_account_id_fkey FOREIGN KEY (account_id) REFERENCES backend.accounts(account_id) ON DELETE CASCADE;


--
-- Name: game_hidden game_hidden_game_id_fkey; Type: FK CONSTRAINT; Schema: backend; Owner: -
--

ALTER TABLE ONLY backend.game_hidden
    ADD CONSTRAINT game_hidden_game_id_fkey FOREIGN KEY (game_id) REFERENCES backend.games(game_id) ON DELETE CASCADE;


--
-- Name: game_invitation_invitees game_invitation_invitees_account_id_fkey; Type: FK CONSTRAINT; Schema: backend; Owner: -
--

ALTER TABLE ONLY backend.game_invitation_invitees
    ADD CONSTRAINT game_invitation_invitees_account_id_fkey FOREIGN KEY (account_id) REFERENCES backend.accounts(account_id) ON DELETE CASCADE;


--
-- Name: game_invitation_invitees game_invitation_invitees_invitation_id_fkey; Type: FK CONSTRAINT; Schema: backend; Owner: -
--

ALTER TABLE ONLY backend.game_invitation_invitees
    ADD CONSTRAINT game_invitation_invitees_invitation_id_fkey FOREIGN KEY (invitation_id) REFERENCES backend.game_invitations(invitation_id) ON DELETE CASCADE;


--
-- Name: game_invitations game_invitations_game_id_fkey; Type: FK CONSTRAINT; Schema: backend; Owner: -
--

ALTER TABLE ONLY backend.game_invitations
    ADD CONSTRAINT game_invitations_game_id_fkey FOREIGN KEY (game_id) REFERENCES backend.games(game_id) ON DELETE SET NULL;


--
-- Name: game_invitations game_invitations_inviter_id_fkey; Type: FK CONSTRAINT; Schema: backend; Owner: -
--

ALTER TABLE ONLY backend.game_invitations
    ADD CONSTRAINT game_invitations_inviter_id_fkey FOREIGN KEY (inviter_id) REFERENCES backend.accounts(account_id) ON DELETE CASCADE;


--
-- Name: game_moves game_moves_game_id_fkey; Type: FK CONSTRAINT; Schema: backend; Owner: -
--

ALTER TABLE ONLY backend.game_moves
    ADD CONSTRAINT game_moves_game_id_fkey FOREIGN KEY (game_id) REFERENCES backend.games(game_id) ON DELETE CASCADE;


--
-- Name: game_players game_players_account_id_fkey; Type: FK CONSTRAINT; Schema: backend; Owner: -
--

ALTER TABLE ONLY backend.game_players
    ADD CONSTRAINT game_players_account_id_fkey FOREIGN KEY (account_id) REFERENCES backend.accounts(account_id);


--
-- Name: game_players game_players_game_id_fkey; Type: FK CONSTRAINT; Schema: backend; Owner: -
--

ALTER TABLE ONLY backend.game_players
    ADD CONSTRAINT game_players_game_id_fkey FOREIGN KEY (game_id) REFERENCES backend.games(game_id) ON DELETE CASCADE;


--
-- Name: game_setup_draws game_setup_draws_account_id_fkey; Type: FK CONSTRAINT; Schema: backend; Owner: -
--

ALTER TABLE ONLY backend.game_setup_draws
    ADD CONSTRAINT game_setup_draws_account_id_fkey FOREIGN KEY (account_id) REFERENCES backend.accounts(account_id) ON DELETE CASCADE;


--
-- Name: game_setup_draws game_setup_draws_game_id_fkey; Type: FK CONSTRAINT; Schema: backend; Owner: -
--

ALTER TABLE ONLY backend.game_setup_draws
    ADD CONSTRAINT game_setup_draws_game_id_fkey FOREIGN KEY (game_id) REFERENCES backend.games(game_id) ON DELETE CASCADE;


--
-- Name: identities identities_account_id_fkey; Type: FK CONSTRAINT; Schema: backend; Owner: -
--

ALTER TABLE ONLY backend.identities
    ADD CONSTRAINT identities_account_id_fkey FOREIGN KEY (account_id) REFERENCES backend.accounts(account_id) ON DELETE CASCADE;


--
-- Name: robot_blocks robot_blocks_blocker_id_fkey; Type: FK CONSTRAINT; Schema: backend; Owner: -
--

ALTER TABLE ONLY backend.robot_blocks
    ADD CONSTRAINT robot_blocks_blocker_id_fkey FOREIGN KEY (blocker_id) REFERENCES backend.accounts(account_id) ON DELETE CASCADE;


--
-- Name: robot_blocks robot_blocks_game_id_fkey; Type: FK CONSTRAINT; Schema: backend; Owner: -
--

ALTER TABLE ONLY backend.robot_blocks
    ADD CONSTRAINT robot_blocks_game_id_fkey FOREIGN KEY (game_id) REFERENCES backend.games(game_id) ON DELETE CASCADE;


--
-- Name: robot_blocks robot_blocks_robot_id_fkey; Type: FK CONSTRAINT; Schema: backend; Owner: -
--

ALTER TABLE ONLY backend.robot_blocks
    ADD CONSTRAINT robot_blocks_robot_id_fkey FOREIGN KEY (robot_id) REFERENCES backend.accounts(account_id) ON DELETE CASCADE;


--
-- Name: robot_friend_requests robot_friend_requests_game_id_fkey; Type: FK CONSTRAINT; Schema: backend; Owner: -
--

ALTER TABLE ONLY backend.robot_friend_requests
    ADD CONSTRAINT robot_friend_requests_game_id_fkey FOREIGN KEY (game_id) REFERENCES backend.games(game_id) ON DELETE CASCADE;


--
-- Name: robot_friend_requests robot_friend_requests_requester_id_fkey; Type: FK CONSTRAINT; Schema: backend; Owner: -
--

ALTER TABLE ONLY backend.robot_friend_requests
    ADD CONSTRAINT robot_friend_requests_requester_id_fkey FOREIGN KEY (requester_id) REFERENCES backend.accounts(account_id) ON DELETE CASCADE;


--
-- Name: robot_friend_requests robot_friend_requests_robot_id_fkey; Type: FK CONSTRAINT; Schema: backend; Owner: -
--

ALTER TABLE ONLY backend.robot_friend_requests
    ADD CONSTRAINT robot_friend_requests_robot_id_fkey FOREIGN KEY (robot_id) REFERENCES backend.accounts(account_id) ON DELETE CASCADE;


--
-- Name: sessions sessions_account_id_fkey; Type: FK CONSTRAINT; Schema: backend; Owner: -
--

ALTER TABLE ONLY backend.sessions
    ADD CONSTRAINT sessions_account_id_fkey FOREIGN KEY (account_id) REFERENCES backend.accounts(account_id) ON DELETE CASCADE;


-- Seed data carried over from the squashed migrations (a schema-only dump omits it):
-- the default house ad campaign, its message and the banner display timings.
INSERT INTO ad_campaigns (campaign_id, name, weight, is_default, enabled)
VALUES ('00000000-0000-0000-0000-0000000000ad', 'Default (house)', 100, true, true);
INSERT INTO ad_messages (message_id, campaign_id, position, body_en, body_ru)
VALUES (
    '00000000-0000-0000-0000-0000000000a1', '00000000-0000-0000-0000-0000000000ad', 0,
    'Tip: a play using all 7 tiles earns a +50 bonus.',
    'Совет: ход всеми 7 фишками приносит бонус +50 очков.'
);
INSERT INTO ad_settings (id, hold_ms, edge_pause_ms, scroll_px_per_sec, fade_out_ms, gap_ms, fade_in_ms)
VALUES (true, 60000, 5000, 40, 1000, 250, 1000);


-- +goose Down
DROP SCHEMA IF EXISTS backend CASCADE;
