Files
certremind/db/schema.sql
2026-05-23 17:03:05 +09:00

145 lines
5.4 KiB
PL/PgSQL

CREATE EXTENSION IF NOT EXISTS pgcrypto;
CREATE OR REPLACE FUNCTION set_updated_at()
RETURNS TRIGGER AS $$
BEGIN
NEW.updated_at = now();
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TABLE IF NOT EXISTS users (
user_id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
username text NOT NULL UNIQUE,
password_hash text NOT NULL,
display_name text NOT NULL,
created_at timestamptz NOT NULL DEFAULT now(),
updated_at timestamptz NOT NULL DEFAULT now()
);
DROP TRIGGER IF EXISTS users_set_updated_at ON users;
CREATE TRIGGER users_set_updated_at
BEFORE UPDATE ON users
FOR EACH ROW EXECUTE FUNCTION set_updated_at();
CREATE TABLE IF NOT EXISTS user_totp (
user_id uuid PRIMARY KEY REFERENCES users(user_id) ON DELETE CASCADE,
otp_secret text NOT NULL,
created_at timestamptz NOT NULL DEFAULT now(),
updated_at timestamptz NOT NULL DEFAULT now()
);
DROP TRIGGER IF EXISTS user_totp_set_updated_at ON user_totp;
CREATE TRIGGER user_totp_set_updated_at
BEFORE UPDATE ON user_totp
FOR EACH ROW EXECUTE FUNCTION set_updated_at();
CREATE TABLE IF NOT EXISTS sessions (
session_id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
user_id uuid NOT NULL REFERENCES users(user_id) ON DELETE CASCADE,
expires_at timestamptz NOT NULL,
created_at timestamptz NOT NULL DEFAULT now(),
updated_at timestamptz NOT NULL DEFAULT now()
);
CREATE INDEX IF NOT EXISTS sessions_user_id_idx ON sessions(user_id);
CREATE INDEX IF NOT EXISTS sessions_expires_at_idx ON sessions(expires_at);
DROP TRIGGER IF EXISTS sessions_set_updated_at ON sessions;
CREATE TRIGGER sessions_set_updated_at
BEFORE UPDATE ON sessions
FOR EACH ROW EXECUTE FUNCTION set_updated_at();
CREATE TABLE IF NOT EXISTS sites (
site_id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
user_id uuid NOT NULL REFERENCES users(user_id) ON DELETE CASCADE,
url text NOT NULL,
alias text NOT NULL,
certificate_issuer text,
certificate_issued_at timestamptz,
certificate_expires_at timestamptz,
certificate_checked_at timestamptz,
certificate_check_error text,
created_at timestamptz NOT NULL DEFAULT now(),
updated_at timestamptz NOT NULL DEFAULT now(),
UNIQUE (user_id, url)
);
ALTER TABLE sites
ADD COLUMN IF NOT EXISTS certificate_issuer text,
ADD COLUMN IF NOT EXISTS certificate_issued_at timestamptz,
ADD COLUMN IF NOT EXISTS certificate_expires_at timestamptz,
ADD COLUMN IF NOT EXISTS certificate_checked_at timestamptz,
ADD COLUMN IF NOT EXISTS certificate_check_error text;
CREATE INDEX IF NOT EXISTS sites_user_id_idx ON sites(user_id);
DROP TRIGGER IF EXISTS sites_set_updated_at ON sites;
CREATE TRIGGER sites_set_updated_at
BEFORE UPDATE ON sites
FOR EACH ROW EXECUTE FUNCTION set_updated_at();
CREATE TABLE IF NOT EXISTS notification_methods (
notification_method_id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
user_id uuid NOT NULL REFERENCES users(user_id) ON DELETE CASCADE,
notification_type text NOT NULL CHECK (notification_type IN ('webhook', 'push')),
alias text NOT NULL,
url text,
push_endpoint text,
push_p256dh text,
push_auth text,
created_at timestamptz NOT NULL DEFAULT now(),
updated_at timestamptz NOT NULL DEFAULT now()
);
CREATE INDEX IF NOT EXISTS notification_methods_user_id_idx ON notification_methods(user_id);
DROP TRIGGER IF EXISTS notification_methods_set_updated_at ON notification_methods;
CREATE TRIGGER notification_methods_set_updated_at
BEFORE UPDATE ON notification_methods
FOR EACH ROW EXECUTE FUNCTION set_updated_at();
CREATE TABLE IF NOT EXISTS site_alert_conditions (
site_alert_condition_id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
site_id uuid NOT NULL REFERENCES sites(site_id) ON DELETE CASCADE,
condition_type text NOT NULL CHECK (condition_type IN ('expires_within_hours')),
threshold_hours integer NOT NULL CHECK (threshold_hours > 0 AND threshold_hours <= 17520),
webhook_method_ids uuid[] NOT NULL DEFAULT '{}',
push_enabled boolean NOT NULL DEFAULT false,
created_at timestamptz NOT NULL DEFAULT now(),
updated_at timestamptz NOT NULL DEFAULT now(),
UNIQUE (site_id, condition_type, threshold_hours)
);
CREATE INDEX IF NOT EXISTS site_alert_conditions_site_id_idx ON site_alert_conditions(site_id);
DROP TRIGGER IF EXISTS site_alert_conditions_set_updated_at ON site_alert_conditions;
CREATE TRIGGER site_alert_conditions_set_updated_at
BEFORE UPDATE ON site_alert_conditions
FOR EACH ROW EXECUTE FUNCTION set_updated_at();
CREATE TABLE IF NOT EXISTS alert_history (
alert_id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
user_id uuid NOT NULL REFERENCES users(user_id) ON DELETE CASCADE,
site_id uuid REFERENCES sites(site_id) ON DELETE SET NULL,
alert_type text NOT NULL,
content text NOT NULL,
occurred_at timestamptz NOT NULL DEFAULT now(),
read_at timestamptz,
delivery_channels text[] NOT NULL DEFAULT ARRAY['app'],
delivery_result jsonb NOT NULL DEFAULT '{}'::jsonb,
dedupe_key text,
created_at timestamptz NOT NULL DEFAULT now(),
updated_at timestamptz NOT NULL DEFAULT now(),
UNIQUE (user_id, dedupe_key)
);
CREATE INDEX IF NOT EXISTS alert_history_user_id_idx ON alert_history(user_id);
CREATE INDEX IF NOT EXISTS alert_history_site_id_idx ON alert_history(site_id);
CREATE INDEX IF NOT EXISTS alert_history_occurred_at_idx ON alert_history(occurred_at);
DROP TRIGGER IF EXISTS alert_history_set_updated_at ON alert_history;
CREATE TRIGGER alert_history_set_updated_at
BEFORE UPDATE ON alert_history
FOR EACH ROW EXECUTE FUNCTION set_updated_at();