147 lines
3.8 KiB
SQL
147 lines
3.8 KiB
SQL
CREATE TABLE IF NOT EXISTS nodes (
|
|
id SERIAL PRIMARY KEY,
|
|
name TEXT UNIQUE NOT NULL,
|
|
hostname TEXT NOT NULL,
|
|
created_at TIMESTAMPTZ DEFAULT now()
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS domains (
|
|
id SERIAL PRIMARY KEY,
|
|
domain TEXT UNIQUE NOT NULL,
|
|
node_name TEXT NOT NULL,
|
|
status TEXT NOT NULL DEFAULT 'active',
|
|
first_seen_at TIMESTAMPTZ DEFAULT now(),
|
|
last_seen_at TIMESTAMPTZ DEFAULT now()
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS mailboxes (
|
|
id SERIAL PRIMARY KEY,
|
|
email_address TEXT UNIQUE NOT NULL,
|
|
domain TEXT NOT NULL,
|
|
node_name TEXT NOT NULL,
|
|
status TEXT NOT NULL DEFAULT 'active',
|
|
used_bytes BIGINT DEFAULT 0,
|
|
last_usage_scan_at TIMESTAMPTZ,
|
|
first_seen_at TIMESTAMPTZ DEFAULT now(),
|
|
last_seen_at TIMESTAMPTZ DEFAULT now()
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS admin_users (
|
|
id SERIAL PRIMARY KEY,
|
|
email TEXT UNIQUE NOT NULL,
|
|
password_hash TEXT NOT NULL,
|
|
role TEXT NOT NULL DEFAULT 'super_admin',
|
|
created_at TIMESTAMPTZ DEFAULT now()
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS audit_log (
|
|
id SERIAL PRIMARY KEY,
|
|
actor_email TEXT,
|
|
action TEXT NOT NULL,
|
|
target TEXT,
|
|
details JSONB,
|
|
created_at TIMESTAMPTZ DEFAULT now()
|
|
);
|
|
|
|
-- ============================================================
|
|
-- Upgrade existing MVP database
|
|
-- ============================================================
|
|
|
|
ALTER TABLE nodes
|
|
ADD COLUMN IF NOT EXISTS updated_at TIMESTAMPTZ DEFAULT now();
|
|
|
|
ALTER TABLE nodes
|
|
ADD COLUMN IF NOT EXISTS is_current BOOLEAN DEFAULT false;
|
|
|
|
ALTER TABLE domains
|
|
ADD COLUMN IF NOT EXISTS updated_at TIMESTAMPTZ DEFAULT now();
|
|
|
|
ALTER TABLE domains
|
|
ADD COLUMN IF NOT EXISTS last_synced_at TIMESTAMPTZ;
|
|
|
|
ALTER TABLE domains
|
|
ADD COLUMN IF NOT EXISTS notes TEXT DEFAULT '';
|
|
|
|
ALTER TABLE mailboxes
|
|
ADD COLUMN IF NOT EXISTS local_part TEXT;
|
|
|
|
ALTER TABLE mailboxes
|
|
ADD COLUMN IF NOT EXISTS quota_bytes BIGINT;
|
|
|
|
ALTER TABLE mailboxes
|
|
ADD COLUMN IF NOT EXISTS quota_percent NUMERIC(8,3);
|
|
|
|
ALTER TABLE mailboxes
|
|
ADD COLUMN IF NOT EXISTS message_count BIGINT;
|
|
|
|
ALTER TABLE mailboxes
|
|
ADD COLUMN IF NOT EXISTS message_limit BIGINT;
|
|
|
|
ALTER TABLE mailboxes
|
|
ADD COLUMN IF NOT EXISTS usage_scanned_at TIMESTAMPTZ;
|
|
|
|
ALTER TABLE mailboxes
|
|
ADD COLUMN IF NOT EXISTS updated_at TIMESTAMPTZ DEFAULT now();
|
|
|
|
ALTER TABLE mailboxes
|
|
ADD COLUMN IF NOT EXISTS deleted_at TIMESTAMPTZ;
|
|
|
|
ALTER TABLE admin_users
|
|
ADD COLUMN IF NOT EXISTS allowed_domains TEXT[] NOT NULL DEFAULT '{}';
|
|
|
|
ALTER TABLE admin_users
|
|
ADD COLUMN IF NOT EXISTS active BOOLEAN NOT NULL DEFAULT true;
|
|
|
|
ALTER TABLE admin_users
|
|
ADD COLUMN IF NOT EXISTS updated_at TIMESTAMPTZ DEFAULT now();
|
|
|
|
ALTER TABLE audit_log
|
|
ADD COLUMN IF NOT EXISTS target_type TEXT;
|
|
|
|
ALTER TABLE audit_log
|
|
ADD COLUMN IF NOT EXISTS target_id TEXT;
|
|
|
|
ALTER TABLE audit_log
|
|
ADD COLUMN IF NOT EXISTS ip_address TEXT;
|
|
|
|
-- details existed already, but make it safer for newer code
|
|
ALTER TABLE audit_log
|
|
ALTER COLUMN details SET DEFAULT '{}';
|
|
|
|
-- Fill local_part for existing rows
|
|
UPDATE mailboxes
|
|
SET local_part = split_part(email_address, '@', 1)
|
|
WHERE local_part IS NULL
|
|
AND email_address LIKE '%@%';
|
|
|
|
-- Keep old and new usage timestamp columns in sync initially
|
|
UPDATE mailboxes
|
|
SET usage_scanned_at = last_usage_scan_at
|
|
WHERE usage_scanned_at IS NULL
|
|
AND last_usage_scan_at IS NOT NULL;
|
|
|
|
-- Backfill new audit target columns from old target column
|
|
UPDATE audit_log
|
|
SET target_id = target
|
|
WHERE target_id IS NULL
|
|
AND target IS NOT NULL;
|
|
|
|
UPDATE audit_log
|
|
SET target_type = 'unknown'
|
|
WHERE target_type IS NULL;
|
|
|
|
-- Useful indexes
|
|
CREATE INDEX IF NOT EXISTS idx_domains_node_name
|
|
ON domains(node_name);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_mailboxes_domain
|
|
ON mailboxes(domain);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_mailboxes_node_name
|
|
ON mailboxes(node_name);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_audit_created
|
|
ON audit_log(created_at DESC);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_admin_users_allowed_domains
|
|
ON admin_users USING GIN(allowed_domains); |