is-coursework/report/data-model/sql/create-db.sql

276 lines
10 KiB
PL/PgSQL

CREATE TYPE auth_factor_kind AS ENUM ('TOTP', 'WebAuthn');
CREATE TYPE email_token_status AS ENUM ('VERIFY_EMAIL', 'RESET_PASSWORD');
CREATE TYPE domain_record_type AS ENUM ('A','AAAA','CNAME','TXT','MX','SRV','CAA');
CREATE TYPE item_action AS ENUM ('register','renew');
CREATE TYPE item_term AS ENUM ('monthly','yearly');
CREATE TYPE order_status AS ENUM ('created','pending_payment','paid','cancelled','failed');
CREATE TYPE mapped_payment_status AS ENUM ('CREATED','APPROVED','ON_REFUND','REFUNDED','EXPIRED');
CREATE TYPE domain_member_role AS ENUM ('OWNER','USER');
CREATE TABLE app_user (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
email text NOT NULL UNIQUE,
password_hash text NOT NULL,
email_confirmed boolean NOT NULL DEFAULT false,
is_admin boolean NOT NULL DEFAULT false,
created_at timestamptz NOT NULL DEFAULT now(),
updated_at timestamptz NOT NULL DEFAULT now()
);
CREATE TABLE auth_factor (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
user_id uuid NOT NULL REFERENCES app_user(id) ON DELETE CASCADE,
kind auth_factor_kind NOT NULL,
public_data jsonb NOT NULL,
created_at timestamptz NOT NULL DEFAULT now(),
updated_at timestamptz NOT NULL DEFAULT now()
);
CREATE INDEX auth_factor_user_id_idx ON auth_factor(user_id);
CREATE TABLE email_validation_token (
token text PRIMARY KEY,
user_id uuid NOT NULL REFERENCES app_user(id) ON DELETE CASCADE,
created_at timestamptz NOT NULL DEFAULT now(),
expires_at timestamptz NOT NULL,
status email_token_status NOT NULL
);
CREATE INDEX email_validation_token_expires_at_idx ON email_validation_token(expires_at);
CREATE TABLE expiry_email_pref (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
user_id uuid NOT NULL REFERENCES app_user(id) ON DELETE CASCADE,
days_before integer NOT NULL CHECK (days_before >= 0),
enabled boolean NOT NULL DEFAULT true,
created_at timestamptz NOT NULL DEFAULT now(),
updated_at timestamptz NOT NULL DEFAULT now(),
UNIQUE (user_id, days_before)
);
CREATE TABLE zone2 (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
name text NOT NULL UNIQUE,
price bigint NOT NULL CHECK (price >= 0),
created_at timestamptz NOT NULL DEFAULT now(),
updated_at timestamptz NOT NULL DEFAULT now()
);
CREATE TABLE domain (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
fqdn varchar(63) NOT NULL UNIQUE,
zone2_id uuid NOT NULL REFERENCES zone2(id) ON DELETE RESTRICT,
activated_at timestamptz, -- NULL = не активирован
expires_at timestamptz NOT NULL,
created_at timestamptz NOT NULL DEFAULT now(),
updated_at timestamptz NOT NULL DEFAULT now()
);
CREATE INDEX domain_expires_at_idx ON domain(expires_at);
CREATE TABLE domain_member (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
user_id uuid NOT NULL REFERENCES app_user(id) ON DELETE CASCADE,
domain_id uuid NOT NULL REFERENCES domain(id) ON DELETE CASCADE,
role domain_member_role NOT NULL,
created_at timestamptz NOT NULL DEFAULT now(),
UNIQUE (user_id, domain_id)
);
CREATE TABLE dns_record (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
domain_id uuid NOT NULL REFERENCES domain(id) ON DELETE CASCADE,
type domain_record_type NOT NULL,
name varchar(255) NOT NULL,
value varchar(1024) NOT NULL,
ttl integer NOT NULL CHECK (ttl > 0),
created_at timestamptz NOT NULL DEFAULT now(),
updated_at timestamptz NOT NULL DEFAULT now()
);
CREATE INDEX dns_record_domain_id_idx ON dns_record(domain_id);
CREATE TABLE ns_delegation (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
domain_id uuid NOT NULL UNIQUE REFERENCES domain(id) ON DELETE CASCADE,
ns_servers jsonb NOT NULL,
applied_at timestamptz,
created_at timestamptz NOT NULL DEFAULT now(),
updated_at timestamptz NOT NULL DEFAULT now()
);
CREATE TABLE cart (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
user_id uuid NOT NULL UNIQUE REFERENCES app_user(id) ON DELETE CASCADE,
created_at timestamptz NOT NULL DEFAULT now(),
updated_at timestamptz NOT NULL DEFAULT now()
);
CREATE TABLE cart_item (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
cart_id uuid NOT NULL REFERENCES cart(id) ON DELETE CASCADE,
action item_action NOT NULL,
term item_term NOT NULL,
fqdn text NOT NULL,
price bigint NOT NULL CHECK (price >= 0),
created_at timestamptz NOT NULL DEFAULT now(),
updated_at timestamptz NOT NULL DEFAULT now(),
UNIQUE (cart_id, fqdn, action, term)
);
CREATE TABLE app_order (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
user_id uuid NOT NULL REFERENCES app_user(id) ON DELETE RESTRICT,
status order_status NOT NULL DEFAULT 'created',
total_amount bigint NOT NULL CHECK (total_amount >= 0),
created_at timestamptz NOT NULL DEFAULT now(),
paid_at timestamptz,
updated_at timestamptz NOT NULL DEFAULT now()
);
CREATE INDEX app_order_user_id_idx ON app_order(user_id);
CREATE INDEX app_order_created_at_paid_at_idx ON app_order(created_at, paid_at) WHERE paid_at IS NULL;
CREATE TABLE app_order_item (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
order_id uuid NOT NULL REFERENCES app_order(id) ON DELETE CASCADE,
action item_action NOT NULL,
term item_term NOT NULL,
domain_id uuid NOT NULL REFERENCES domain(id) ON DELETE RESTRICT,
created_at timestamptz NOT NULL DEFAULT now(),
updated_at timestamptz NOT NULL DEFAULT now()
);
CREATE INDEX app_order_item_order_id_idx ON app_order_item(order_id);
CREATE TABLE payment_operation (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
order_id uuid NOT NULL REFERENCES app_order(id) ON DELETE CASCADE,
operation_id varchar(255) UNIQUE,
payment_link varchar(255),
amount bigint NOT NULL CHECK (amount >= 0),
status_raw varchar(255) NOT NULL,
status_mapped mapped_payment_status NOT NULL,
approved_at timestamptz,
created_at timestamptz NOT NULL DEFAULT now(),
expires_at timestamptz,
updated_at timestamptz NOT NULL DEFAULT now(),
with_receipt boolean NOT NULL DEFAULT false,
receipt_payload jsonb,
customer_code varchar(255),
merchant_id varchar(255),
payment_type varchar(255)
);
CREATE INDEX payment_operation_order_id_idx ON payment_operation(order_id);
CREATE TABLE payment_status (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
payment_operation_id uuid NOT NULL REFERENCES payment_operation(id) ON DELETE CASCADE,
status_raw varchar(255) NOT NULL,
status_mapped mapped_payment_status NOT NULL,
raw_payload varchar(255),
created_at timestamptz NOT NULL DEFAULT now()
);
CREATE INDEX payment_status_op_id_idx ON payment_status(payment_operation_id);
CREATE TABLE refund (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
payment_operation_id uuid NOT NULL REFERENCES payment_operation(id) ON DELETE CASCADE,
provider_refund_id varchar(255),
amount bigint NOT NULL CHECK (amount >= 0),
status varchar(255) NOT NULL,
created_at timestamptz NOT NULL DEFAULT now(),
updated_at timestamptz NOT NULL DEFAULT now()
);
CREATE INDEX refund_op_id_idx ON refund(payment_operation_id);
CREATE TABLE webhook_event (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
payment_operation_id uuid REFERENCES payment_operation(id) ON DELETE SET NULL,
payload_hash varchar(255),
raw_payload varchar(255),
webhook_type varchar(255),
operation_id varchar(255),
merchant_id varchar(255),
customer_code varchar(255),
payment_type varchar(255),
amount bigint,
status_after mapped_payment_status,
created_at timestamptz NOT NULL DEFAULT now()
);
CREATE TABLE reserved_name (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
label text NOT NULL UNIQUE,
reason text,
created_at timestamptz NOT NULL DEFAULT now(),
updated_at timestamptz NOT NULL DEFAULT now()
);
CREATE TABLE forbidden_name (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
label text NOT NULL UNIQUE
);
CREATE TABLE event (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
actor_type varchar(64) NOT NULL, -- 'user' | 'admin' | 'system'
actor_id uuid,
action text NOT NULL,
resource text,
ip text,
at timestamptz NOT NULL
);
CREATE INDEX event_at_idx ON event USING BRIN(at);
CREATE INDEX event_actor_idx ON event(actor_type, actor_id);
CREATE TABLE user_session (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
user_id uuid NOT NULL REFERENCES app_user(id) ON DELETE CASCADE,
jwt_id uuid NOT NULL UNIQUE, -- jti
access varchar(255) NOT NULL,
refresh varchar(255) NOT NULL,
ip varchar(40),
user_agent varchar(255),
device varchar(255),
issued_at timestamptz NOT NULL,
expires_at timestamptz NOT NULL,
last_access_at timestamptz
);
CREATE INDEX user_session_user_id_idx ON user_session(user_id);
CREATE INDEX user_session_expires_at_idx ON user_session(expires_at);
CREATE OR REPLACE FUNCTION set_updated_at() RETURNS trigger AS $$
BEGIN
NEW.updated_at := now();
RETURN NEW;
END; $$ LANGUAGE plpgsql;
DO $$
DECLARE
r record;
BEGIN
FOR r IN
SELECT
t.table_name
FROM information_schema.tables AS t
JOIN information_schema.columns AS c
ON c.table_schema = t.table_schema
AND c.table_name = t.table_name
AND c.column_name = 'updated_at'
WHERE t.table_schema NOT IN ('pg_catalog', 'information_schema')
AND t.table_type = 'BASE TABLE'
LOOP
EXECUTE format(
'CREATE TRIGGER %I_set_updated_at
BEFORE UPDATE ON %I
FOR EACH ROW
EXECUTE FUNCTION set_updated_at()',
r.table_name, r.table_name
);
END LOOP;
END $$;