This commit is contained in:
2026-04-09 14:55:37 +02:00
parent 8be455ba98
commit 4a85efc270
30 changed files with 4895 additions and 1 deletions
@@ -0,0 +1,18 @@
DROP TABLE IF EXISTS audit_log_attributes;
DROP TABLE IF EXISTS audit_logs;
DROP TABLE IF EXISTS analytics_event_attributes;
DROP TABLE IF EXISTS analytics_events;
DROP TABLE IF EXISTS analytics_event_types;
DROP TABLE IF EXISTS localization_values;
DROP TABLE IF EXISTS localization_keys;
DROP TABLE IF EXISTS experiment_assignments;
DROP TABLE IF EXISTS settlements;
DROP TABLE IF EXISTS bet_intents;
DROP TABLE IF EXISTS outcome_odds;
DROP TABLE IF EXISTS odds_versions;
DROP TABLE IF EXISTS outcomes;
DROP TABLE IF EXISTS markets;
DROP TABLE IF EXISTS event_media;
DROP TABLE IF EXISTS events;
DROP TABLE IF EXISTS sessions;
DROP TABLE IF EXISTS users;
@@ -0,0 +1,190 @@
CREATE EXTENSION IF NOT EXISTS pgcrypto;
CREATE TABLE users (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
external_ref text NOT NULL UNIQUE,
created_at timestamptz NOT NULL DEFAULT now(),
preferred_language text NOT NULL,
device_platform text NOT NULL
);
CREATE TABLE sessions (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
user_id uuid NOT NULL REFERENCES users(id) ON DELETE CASCADE,
started_at timestamptz NOT NULL DEFAULT now(),
ended_at timestamptz,
experiment_variant text NOT NULL,
app_version text NOT NULL,
device_model text,
os_version text,
locale_code text NOT NULL
);
CREATE TABLE events (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
sport_type text NOT NULL,
source_ref text NOT NULL UNIQUE,
title_en text NOT NULL,
title_sv text NOT NULL,
status text NOT NULL,
preview_start_ms bigint NOT NULL,
preview_end_ms bigint NOT NULL,
reveal_start_ms bigint NOT NULL,
reveal_end_ms bigint NOT NULL,
lock_at timestamptz NOT NULL,
settle_at timestamptz NOT NULL
);
CREATE TABLE event_media (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
event_id uuid NOT NULL REFERENCES events(id) ON DELETE CASCADE,
media_type text NOT NULL,
hls_master_url text NOT NULL,
poster_url text,
duration_ms bigint NOT NULL,
preview_start_ms bigint NOT NULL,
preview_end_ms bigint NOT NULL,
reveal_start_ms bigint NOT NULL,
reveal_end_ms bigint NOT NULL,
UNIQUE (event_id, media_type)
);
CREATE TABLE markets (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
event_id uuid NOT NULL REFERENCES events(id) ON DELETE CASCADE,
question_key text NOT NULL,
market_type text NOT NULL,
status text NOT NULL,
lock_at timestamptz NOT NULL,
settlement_rule_key text NOT NULL
);
CREATE TABLE outcomes (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
market_id uuid NOT NULL REFERENCES markets(id) ON DELETE CASCADE,
outcome_code text NOT NULL,
label_key text NOT NULL,
sort_order integer NOT NULL,
UNIQUE (market_id, outcome_code)
);
CREATE TABLE odds_versions (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
market_id uuid NOT NULL REFERENCES markets(id) ON DELETE CASCADE,
version_no integer NOT NULL,
created_at timestamptz NOT NULL DEFAULT now(),
is_current boolean NOT NULL DEFAULT false,
UNIQUE (market_id, version_no)
);
CREATE UNIQUE INDEX odds_versions_current_idx
ON odds_versions (market_id)
WHERE is_current;
CREATE TABLE outcome_odds (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
odds_version_id uuid NOT NULL REFERENCES odds_versions(id) ON DELETE CASCADE,
outcome_id uuid NOT NULL REFERENCES outcomes(id) ON DELETE CASCADE,
decimal_odds numeric(10,4) NOT NULL,
fractional_num integer NOT NULL,
fractional_den integer NOT NULL,
UNIQUE (odds_version_id, outcome_id)
);
CREATE TABLE bet_intents (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
user_id uuid NOT NULL REFERENCES users(id),
session_id uuid NOT NULL REFERENCES sessions(id),
event_id uuid NOT NULL REFERENCES events(id),
market_id uuid NOT NULL REFERENCES markets(id),
outcome_id uuid NOT NULL REFERENCES outcomes(id),
idempotency_key text NOT NULL UNIQUE,
client_sent_at timestamptz NOT NULL,
server_received_at timestamptz NOT NULL DEFAULT now(),
accepted boolean NOT NULL,
acceptance_code text NOT NULL,
accepted_odds_version_id uuid REFERENCES odds_versions(id)
);
CREATE TABLE settlements (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
market_id uuid NOT NULL UNIQUE REFERENCES markets(id) ON DELETE CASCADE,
settled_at timestamptz NOT NULL,
winning_outcome_id uuid NOT NULL REFERENCES outcomes(id)
);
CREATE TABLE experiment_assignments (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
user_id uuid NOT NULL REFERENCES users(id) ON DELETE CASCADE,
session_id uuid NOT NULL REFERENCES sessions(id) ON DELETE CASCADE,
variant text NOT NULL,
assigned_at timestamptz NOT NULL DEFAULT now(),
UNIQUE (session_id)
);
CREATE TABLE localization_keys (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
key_name text NOT NULL UNIQUE,
description text NOT NULL
);
CREATE TABLE localization_values (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
localization_key_id uuid NOT NULL REFERENCES localization_keys(id) ON DELETE CASCADE,
locale_code text NOT NULL,
text_value text NOT NULL,
UNIQUE (localization_key_id, locale_code)
);
CREATE TABLE analytics_event_types (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
event_name text NOT NULL UNIQUE,
description text NOT NULL
);
CREATE TABLE analytics_events (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
analytics_event_type_id uuid NOT NULL REFERENCES analytics_event_types(id),
session_id uuid NOT NULL REFERENCES sessions(id) ON DELETE CASCADE,
user_id uuid NOT NULL REFERENCES users(id) ON DELETE CASCADE,
occurred_at timestamptz NOT NULL DEFAULT now()
);
CREATE TABLE analytics_event_attributes (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
analytics_event_id uuid NOT NULL REFERENCES analytics_events(id) ON DELETE CASCADE,
attribute_key text NOT NULL,
attribute_value text NOT NULL
);
CREATE TABLE audit_logs (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
created_at timestamptz NOT NULL DEFAULT now(),
actor_type text NOT NULL,
actor_id uuid,
action_name text NOT NULL,
target_type text NOT NULL,
target_id uuid,
trace_id text NOT NULL,
note text
);
CREATE TABLE audit_log_attributes (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
audit_log_id uuid NOT NULL REFERENCES audit_logs(id) ON DELETE CASCADE,
attribute_key text NOT NULL,
attribute_value text NOT NULL
);
CREATE INDEX sessions_user_id_idx ON sessions (user_id);
CREATE INDEX sessions_started_at_idx ON sessions (started_at);
CREATE INDEX events_status_idx ON events (status);
CREATE INDEX markets_event_id_idx ON markets (event_id);
CREATE INDEX markets_lock_at_idx ON markets (lock_at);
CREATE INDEX bet_intents_session_id_idx ON bet_intents (session_id);
CREATE INDEX bet_intents_market_id_idx ON bet_intents (market_id);
CREATE INDEX bet_intents_idempotency_key_idx ON bet_intents (idempotency_key);
CREATE INDEX analytics_events_session_id_idx ON analytics_events (session_id);
CREATE INDEX analytics_events_user_id_idx ON analytics_events (user_id);
CREATE INDEX analytics_events_type_id_idx ON analytics_events (analytics_event_type_id);
CREATE INDEX audit_logs_created_at_idx ON audit_logs (created_at);