125 lines
5.4 KiB
SQL
125 lines
5.4 KiB
SQL
ALTER TABLE users
|
|
ADD COLUMN deleted_by uuid REFERENCES users(id) ON DELETE SET NULL,
|
|
ADD COLUMN deletion_reason text NOT NULL DEFAULT '',
|
|
ADD COLUMN restored_at timestamptz;
|
|
|
|
ALTER TABLE card_batches
|
|
ADD COLUMN membership_plan_id uuid REFERENCES membership_plans(id) ON DELETE SET NULL,
|
|
ADD COLUMN edition text NOT NULL DEFAULT '' CHECK (char_length(edition) <= 64),
|
|
ADD COLUMN max_uses integer NOT NULL DEFAULT 1 CHECK (max_uses > 0);
|
|
|
|
ALTER TABLE card_batches DROP CONSTRAINT card_batches_card_type_check;
|
|
ALTER TABLE card_batches ADD CONSTRAINT card_batches_card_type_check CHECK (card_type IN ('registration','renewal','membership'));
|
|
|
|
ALTER TABLE cards
|
|
ADD COLUMN label text NOT NULL DEFAULT '' CHECK (char_length(label) <= 128);
|
|
|
|
CREATE TABLE notification_channel_configs (
|
|
channel text PRIMARY KEY CHECK (channel IN ('smtp','telegram')),
|
|
enabled boolean NOT NULL DEFAULT false,
|
|
settings jsonb NOT NULL DEFAULT '{}'::jsonb CHECK (jsonb_typeof(settings)='object'),
|
|
secret_cipher bytea,
|
|
updated_by uuid REFERENCES users(id) ON DELETE SET NULL,
|
|
updated_at timestamptz NOT NULL DEFAULT now()
|
|
);
|
|
|
|
INSERT INTO notification_channel_configs(channel) VALUES ('smtp'),('telegram');
|
|
|
|
CREATE TABLE notification_templates (
|
|
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
template_key text NOT NULL CHECK (template_key ~ '^[a-z0-9][a-z0-9._-]{0,127}$'),
|
|
channel text NOT NULL CHECK (channel IN ('email','telegram')),
|
|
subject text NOT NULL DEFAULT '' CHECK (char_length(subject) <= 300),
|
|
body text NOT NULL CHECK (char_length(body) BETWEEN 1 AND 20000),
|
|
enabled boolean NOT NULL DEFAULT true,
|
|
updated_by uuid REFERENCES users(id) ON DELETE SET NULL,
|
|
created_at timestamptz NOT NULL DEFAULT now(),
|
|
updated_at timestamptz NOT NULL DEFAULT now(),
|
|
UNIQUE(template_key,channel)
|
|
);
|
|
|
|
CREATE TABLE notification_delivery_attempts (
|
|
id bigserial PRIMARY KEY,
|
|
delivery_id uuid NOT NULL REFERENCES notification_deliveries(id) ON DELETE CASCADE,
|
|
attempt integer NOT NULL CHECK (attempt > 0),
|
|
status text NOT NULL CHECK (status IN ('sent','failed','skipped')),
|
|
error_code text NOT NULL DEFAULT '',
|
|
error_summary text NOT NULL DEFAULT '',
|
|
created_at timestamptz NOT NULL DEFAULT now(),
|
|
UNIQUE(delivery_id,attempt)
|
|
);
|
|
|
|
CREATE TABLE telegram_runtime_state (
|
|
singleton boolean PRIMARY KEY DEFAULT true CHECK (singleton),
|
|
update_offset bigint NOT NULL DEFAULT 0,
|
|
updated_at timestamptz NOT NULL DEFAULT now()
|
|
);
|
|
INSERT INTO telegram_runtime_state(singleton) VALUES(true);
|
|
|
|
CREATE TABLE user_ip_history (
|
|
id bigserial PRIMARY KEY,
|
|
user_id uuid NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
ip_hash text NOT NULL CHECK (char_length(ip_hash)=64),
|
|
country text NOT NULL DEFAULT '',
|
|
region text NOT NULL DEFAULT '',
|
|
carrier text NOT NULL DEFAULT '',
|
|
asn bigint,
|
|
first_seen_at timestamptz NOT NULL DEFAULT now(),
|
|
last_seen_at timestamptz NOT NULL DEFAULT now(),
|
|
seen_count bigint NOT NULL DEFAULT 1 CHECK (seen_count > 0),
|
|
UNIQUE(user_id,ip_hash)
|
|
);
|
|
CREATE INDEX user_ip_history_user_time_idx ON user_ip_history(user_id,last_seen_at DESC);
|
|
|
|
CREATE TABLE security_list_entries (
|
|
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
subject_type text NOT NULL CHECK (subject_type IN ('ip','cidr','device','user')),
|
|
mode text NOT NULL CHECK (mode IN ('allow','deny')),
|
|
subject_value text NOT NULL CHECK (char_length(subject_value) BETWEEN 1 AND 512),
|
|
reason text NOT NULL CHECK (char_length(btrim(reason)) BETWEEN 1 AND 1000),
|
|
expires_at timestamptz,
|
|
created_by uuid NOT NULL REFERENCES users(id),
|
|
created_at timestamptz NOT NULL DEFAULT now(),
|
|
revoked_at timestamptz,
|
|
revoked_by uuid REFERENCES users(id) ON DELETE SET NULL,
|
|
UNIQUE(subject_type,mode,subject_value)
|
|
);
|
|
CREATE INDEX security_list_active_idx ON security_list_entries(subject_type,mode,expires_at) WHERE revoked_at IS NULL;
|
|
|
|
CREATE TABLE user_appeals (
|
|
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
user_id uuid NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
risk_event_id uuid REFERENCES risk_events(id) ON DELETE SET NULL,
|
|
body text NOT NULL CHECK (char_length(btrim(body)) BETWEEN 1 AND 5000),
|
|
status text NOT NULL DEFAULT 'submitted' CHECK (status IN ('submitted','reviewing','accepted','rejected')),
|
|
resolution text NOT NULL DEFAULT '',
|
|
resolved_by uuid REFERENCES users(id) ON DELETE SET NULL,
|
|
resolved_at timestamptz,
|
|
created_at timestamptz NOT NULL DEFAULT now(),
|
|
updated_at timestamptz NOT NULL DEFAULT now()
|
|
);
|
|
|
|
CREATE TABLE media_request_callbacks (
|
|
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
name text NOT NULL CHECK (char_length(btrim(name)) BETWEEN 1 AND 128),
|
|
callback_url text NOT NULL CHECK (callback_url ~ '^https://'),
|
|
secret_cipher bytea NOT NULL,
|
|
enabled boolean NOT NULL DEFAULT true,
|
|
created_by uuid NOT NULL REFERENCES users(id),
|
|
created_at timestamptz NOT NULL DEFAULT now(),
|
|
updated_at timestamptz NOT NULL DEFAULT now()
|
|
);
|
|
|
|
CREATE TABLE media_request_callback_events (
|
|
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
callback_id uuid NOT NULL REFERENCES media_request_callbacks(id) ON DELETE CASCADE,
|
|
external_event_id text NOT NULL CHECK (char_length(external_event_id) BETWEEN 1 AND 256),
|
|
request_id uuid REFERENCES media_requests(id) ON DELETE SET NULL,
|
|
payload jsonb NOT NULL CHECK (jsonb_typeof(payload)='object'),
|
|
signature_valid boolean NOT NULL,
|
|
applied boolean NOT NULL DEFAULT false,
|
|
error_summary text NOT NULL DEFAULT '',
|
|
received_at timestamptz NOT NULL DEFAULT now(),
|
|
UNIQUE(callback_id,external_event_id)
|
|
);
|