first commit
This commit is contained in:
@@ -0,0 +1,46 @@
|
||||
DROP TRIGGER IF EXISTS trg_cron_jobs_updated_at ON cron_jobs;
|
||||
DROP TRIGGER IF EXISTS trg_dns_records_updated_at ON dns_records;
|
||||
DROP TRIGGER IF EXISTS trg_dns_zones_updated_at ON dns_zones;
|
||||
DROP TRIGGER IF EXISTS trg_mail_accounts_updated_at ON mail_accounts;
|
||||
DROP TRIGGER IF EXISTS trg_ssl_certificates_updated_at ON ssl_certificates;
|
||||
DROP TRIGGER IF EXISTS trg_ftp_accounts_updated_at ON ftp_accounts;
|
||||
DROP TRIGGER IF EXISTS trg_sites_updated_at ON sites;
|
||||
DROP TRIGGER IF EXISTS trg_servers_updated_at ON servers;
|
||||
DROP TRIGGER IF EXISTS trg_users_updated_at ON users;
|
||||
|
||||
DROP FUNCTION IF EXISTS set_updated_at();
|
||||
|
||||
DROP TABLE IF EXISTS audit_logs;
|
||||
DROP TABLE IF EXISTS jobs;
|
||||
DROP TABLE IF EXISTS backups;
|
||||
DROP TABLE IF EXISTS cron_jobs;
|
||||
DROP TABLE IF EXISTS dns_records;
|
||||
DROP TABLE IF EXISTS dns_zones;
|
||||
DROP TABLE IF EXISTS mail_accounts;
|
||||
DROP TABLE IF EXISTS mail_domains;
|
||||
DROP TABLE IF EXISTS ssl_certificates;
|
||||
DROP TABLE IF EXISTS ftp_accounts;
|
||||
DROP TABLE IF EXISTS database_users;
|
||||
DROP TABLE IF EXISTS databases;
|
||||
DROP TABLE IF EXISTS domains;
|
||||
DROP TABLE IF EXISTS sites;
|
||||
DROP TABLE IF EXISTS server_access;
|
||||
DROP TABLE IF EXISTS servers;
|
||||
DROP TABLE IF EXISTS api_keys;
|
||||
DROP TABLE IF EXISTS sessions;
|
||||
DROP TABLE IF EXISTS users;
|
||||
|
||||
DROP TYPE IF EXISTS dns_record_type;
|
||||
DROP TYPE IF EXISTS job_status;
|
||||
DROP TYPE IF EXISTS backup_status;
|
||||
DROP TYPE IF EXISTS backup_type;
|
||||
DROP TYPE IF EXISTS db_engine;
|
||||
DROP TYPE IF EXISTS ssl_status;
|
||||
DROP TYPE IF EXISTS ssl_type;
|
||||
DROP TYPE IF EXISTS site_status;
|
||||
DROP TYPE IF EXISTS server_status;
|
||||
DROP TYPE IF EXISTS user_role;
|
||||
DROP TYPE IF EXISTS user_status;
|
||||
|
||||
DROP EXTENSION IF EXISTS citext;
|
||||
DROP EXTENSION IF EXISTS pgcrypto;
|
||||
@@ -0,0 +1,357 @@
|
||||
-- Panel hosting control panel — initial schema
|
||||
|
||||
CREATE EXTENSION IF NOT EXISTS "pgcrypto";
|
||||
CREATE EXTENSION IF NOT EXISTS "citext";
|
||||
|
||||
-- ─── Enums ───────────────────────────────────────────────────────────────────
|
||||
|
||||
CREATE TYPE user_status AS ENUM ('active', 'suspended', 'pending');
|
||||
CREATE TYPE user_role AS ENUM ('superadmin', 'admin', 'reseller', 'user');
|
||||
|
||||
CREATE TYPE server_status AS ENUM ('online', 'offline', 'maintenance', 'provisioning');
|
||||
CREATE TYPE site_status AS ENUM ('active', 'suspended', 'creating', 'deleting', 'error');
|
||||
CREATE TYPE ssl_type AS ENUM ('letsencrypt', 'custom', 'self_signed');
|
||||
CREATE TYPE ssl_status AS ENUM ('pending', 'active', 'expired', 'error');
|
||||
CREATE TYPE db_engine AS ENUM ('mysql', 'postgresql');
|
||||
CREATE TYPE backup_type AS ENUM ('full', 'files', 'database');
|
||||
CREATE TYPE backup_status AS ENUM ('pending', 'running', 'completed', 'failed');
|
||||
CREATE TYPE job_status AS ENUM ('pending', 'running', 'completed', 'failed', 'cancelled');
|
||||
CREATE TYPE dns_record_type AS ENUM ('A', 'AAAA', 'CNAME', 'MX', 'TXT', 'NS', 'SRV', 'PTR');
|
||||
|
||||
-- ─── Users & auth ────────────────────────────────────────────────────────────
|
||||
|
||||
CREATE TABLE users (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
uuid UUID NOT NULL DEFAULT gen_random_uuid() UNIQUE,
|
||||
email CITEXT NOT NULL UNIQUE,
|
||||
username VARCHAR(64) NOT NULL UNIQUE,
|
||||
password_hash TEXT NOT NULL,
|
||||
role user_role NOT NULL DEFAULT 'user',
|
||||
status user_status NOT NULL DEFAULT 'pending',
|
||||
locale VARCHAR(10) NOT NULL DEFAULT 'ru',
|
||||
timezone VARCHAR(64) NOT NULL DEFAULT 'Europe/Moscow',
|
||||
last_login_at TIMESTAMPTZ,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
||||
);
|
||||
|
||||
CREATE TABLE sessions (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
user_id BIGINT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
token_hash TEXT NOT NULL UNIQUE,
|
||||
ip_address INET,
|
||||
user_agent TEXT,
|
||||
expires_at TIMESTAMPTZ NOT NULL,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
||||
);
|
||||
|
||||
CREATE INDEX idx_sessions_user_id ON sessions(user_id);
|
||||
CREATE INDEX idx_sessions_expires_at ON sessions(expires_at);
|
||||
|
||||
CREATE TABLE api_keys (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
user_id BIGINT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
name VARCHAR(128) NOT NULL,
|
||||
key_hash TEXT NOT NULL UNIQUE,
|
||||
key_prefix VARCHAR(16) NOT NULL,
|
||||
last_used_at TIMESTAMPTZ,
|
||||
expires_at TIMESTAMPTZ,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
||||
);
|
||||
|
||||
CREATE INDEX idx_api_keys_user_id ON api_keys(user_id);
|
||||
|
||||
-- ─── Servers (managed nodes) ─────────────────────────────────────────────────
|
||||
|
||||
CREATE TABLE servers (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
uuid UUID NOT NULL DEFAULT gen_random_uuid() UNIQUE,
|
||||
name VARCHAR(128) NOT NULL,
|
||||
hostname VARCHAR(255) NOT NULL,
|
||||
ip_address INET NOT NULL,
|
||||
ssh_port INT NOT NULL DEFAULT 22,
|
||||
status server_status NOT NULL DEFAULT 'provisioning',
|
||||
agent_token_hash TEXT,
|
||||
agent_version VARCHAR(32),
|
||||
os_info JSONB NOT NULL DEFAULT '{}',
|
||||
resources JSONB NOT NULL DEFAULT '{}',
|
||||
settings JSONB NOT NULL DEFAULT '{}',
|
||||
last_seen_at TIMESTAMPTZ,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
||||
);
|
||||
|
||||
CREATE UNIQUE INDEX idx_servers_hostname ON servers(hostname);
|
||||
|
||||
-- User access to servers (multi-tenant / reseller model)
|
||||
CREATE TABLE server_access (
|
||||
user_id BIGINT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
server_id BIGINT NOT NULL REFERENCES servers(id) ON DELETE CASCADE,
|
||||
can_manage BOOLEAN NOT NULL DEFAULT false,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
PRIMARY KEY (user_id, server_id)
|
||||
);
|
||||
|
||||
-- ─── Sites (websites) ────────────────────────────────────────────────────────
|
||||
|
||||
CREATE TABLE sites (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
uuid UUID NOT NULL DEFAULT gen_random_uuid() UNIQUE,
|
||||
server_id BIGINT NOT NULL REFERENCES servers(id) ON DELETE RESTRICT,
|
||||
owner_id BIGINT NOT NULL REFERENCES users(id) ON DELETE RESTRICT,
|
||||
name VARCHAR(128) NOT NULL,
|
||||
document_root VARCHAR(512) NOT NULL,
|
||||
php_version VARCHAR(16),
|
||||
status site_status NOT NULL DEFAULT 'creating',
|
||||
settings JSONB NOT NULL DEFAULT '{}',
|
||||
disk_quota_mb INT,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
UNIQUE (server_id, name)
|
||||
);
|
||||
|
||||
CREATE INDEX idx_sites_owner_id ON sites(owner_id);
|
||||
CREATE INDEX idx_sites_server_id ON sites(server_id);
|
||||
|
||||
CREATE TABLE domains (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
site_id BIGINT NOT NULL REFERENCES sites(id) ON DELETE CASCADE,
|
||||
domain CITEXT NOT NULL,
|
||||
is_primary BOOLEAN NOT NULL DEFAULT false,
|
||||
ssl_enabled BOOLEAN NOT NULL DEFAULT true,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
UNIQUE (domain)
|
||||
);
|
||||
|
||||
CREATE INDEX idx_domains_site_id ON domains(site_id);
|
||||
|
||||
-- Only one primary domain per site
|
||||
CREATE UNIQUE INDEX idx_domains_site_primary
|
||||
ON domains(site_id) WHERE is_primary = true;
|
||||
|
||||
-- ─── Databases ───────────────────────────────────────────────────────────────
|
||||
|
||||
CREATE TABLE databases (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
uuid UUID NOT NULL DEFAULT gen_random_uuid() UNIQUE,
|
||||
site_id BIGINT NOT NULL REFERENCES sites(id) ON DELETE CASCADE,
|
||||
server_id BIGINT NOT NULL REFERENCES servers(id) ON DELETE RESTRICT,
|
||||
name VARCHAR(64) NOT NULL,
|
||||
engine db_engine NOT NULL DEFAULT 'mysql',
|
||||
charset VARCHAR(32) NOT NULL DEFAULT 'utf8mb4',
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
UNIQUE (server_id, engine, name)
|
||||
);
|
||||
|
||||
CREATE INDEX idx_databases_site_id ON databases(site_id);
|
||||
|
||||
CREATE TABLE database_users (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
database_id BIGINT NOT NULL REFERENCES databases(id) ON DELETE CASCADE,
|
||||
username VARCHAR(64) NOT NULL,
|
||||
password_hash TEXT NOT NULL,
|
||||
privileges TEXT[] NOT NULL DEFAULT '{ALL}',
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
UNIQUE (database_id, username)
|
||||
);
|
||||
|
||||
-- ─── FTP ─────────────────────────────────────────────────────────────────────
|
||||
|
||||
CREATE TABLE ftp_accounts (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
site_id BIGINT NOT NULL REFERENCES sites(id) ON DELETE CASCADE,
|
||||
username VARCHAR(64) NOT NULL,
|
||||
password_hash TEXT NOT NULL,
|
||||
home_path VARCHAR(512) NOT NULL,
|
||||
quota_mb INT,
|
||||
is_active BOOLEAN NOT NULL DEFAULT true,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
UNIQUE (site_id, username)
|
||||
);
|
||||
|
||||
-- ─── SSL certificates ────────────────────────────────────────────────────────
|
||||
|
||||
CREATE TABLE ssl_certificates (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
domain_id BIGINT NOT NULL REFERENCES domains(id) ON DELETE CASCADE,
|
||||
type ssl_type NOT NULL,
|
||||
status ssl_status NOT NULL DEFAULT 'pending',
|
||||
issuer VARCHAR(255),
|
||||
cert_pem TEXT,
|
||||
key_pem TEXT,
|
||||
chain_pem TEXT,
|
||||
issued_at TIMESTAMPTZ,
|
||||
expires_at TIMESTAMPTZ,
|
||||
auto_renew BOOLEAN NOT NULL DEFAULT true,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
||||
);
|
||||
|
||||
CREATE INDEX idx_ssl_certificates_domain_id ON ssl_certificates(domain_id);
|
||||
CREATE INDEX idx_ssl_certificates_expires_at ON ssl_certificates(expires_at);
|
||||
|
||||
-- ─── Mail ────────────────────────────────────────────────────────────────────
|
||||
|
||||
CREATE TABLE mail_domains (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
site_id BIGINT NOT NULL REFERENCES sites(id) ON DELETE CASCADE,
|
||||
domain CITEXT NOT NULL UNIQUE,
|
||||
dkim_enabled BOOLEAN NOT NULL DEFAULT true,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
||||
);
|
||||
|
||||
CREATE TABLE mail_accounts (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
mail_domain_id BIGINT NOT NULL REFERENCES mail_domains(id) ON DELETE CASCADE,
|
||||
email CITEXT NOT NULL UNIQUE,
|
||||
password_hash TEXT NOT NULL,
|
||||
quota_mb INT NOT NULL DEFAULT 1024,
|
||||
is_active BOOLEAN NOT NULL DEFAULT true,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
||||
);
|
||||
|
||||
CREATE INDEX idx_mail_accounts_mail_domain_id ON mail_accounts(mail_domain_id);
|
||||
|
||||
-- ─── DNS ─────────────────────────────────────────────────────────────────────
|
||||
|
||||
CREATE TABLE dns_zones (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
server_id BIGINT NOT NULL REFERENCES servers(id) ON DELETE CASCADE,
|
||||
domain CITEXT NOT NULL,
|
||||
serial BIGINT NOT NULL DEFAULT 1,
|
||||
ttl INT NOT NULL DEFAULT 3600,
|
||||
is_active BOOLEAN NOT NULL DEFAULT true,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
UNIQUE (server_id, domain)
|
||||
);
|
||||
|
||||
CREATE TABLE dns_records (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
zone_id BIGINT NOT NULL REFERENCES dns_zones(id) ON DELETE CASCADE,
|
||||
type dns_record_type NOT NULL,
|
||||
name VARCHAR(255) NOT NULL DEFAULT '@',
|
||||
content TEXT NOT NULL,
|
||||
ttl INT NOT NULL DEFAULT 3600,
|
||||
priority INT,
|
||||
is_active BOOLEAN NOT NULL DEFAULT true,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
||||
);
|
||||
|
||||
CREATE INDEX idx_dns_records_zone_id ON dns_records(zone_id);
|
||||
|
||||
-- ─── Cron jobs ───────────────────────────────────────────────────────────────
|
||||
|
||||
CREATE TABLE cron_jobs (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
site_id BIGINT NOT NULL REFERENCES sites(id) ON DELETE CASCADE,
|
||||
schedule VARCHAR(128) NOT NULL,
|
||||
command TEXT NOT NULL,
|
||||
run_as VARCHAR(64) NOT NULL DEFAULT 'www-data',
|
||||
is_active BOOLEAN NOT NULL DEFAULT true,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
||||
);
|
||||
|
||||
CREATE INDEX idx_cron_jobs_site_id ON cron_jobs(site_id);
|
||||
|
||||
-- ─── Backups ─────────────────────────────────────────────────────────────────
|
||||
|
||||
CREATE TABLE backups (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
uuid UUID NOT NULL DEFAULT gen_random_uuid() UNIQUE,
|
||||
site_id BIGINT NOT NULL REFERENCES sites(id) ON DELETE CASCADE,
|
||||
type backup_type NOT NULL,
|
||||
status backup_status NOT NULL DEFAULT 'pending',
|
||||
storage_path VARCHAR(1024),
|
||||
size_bytes BIGINT,
|
||||
error_message TEXT,
|
||||
started_at TIMESTAMPTZ,
|
||||
completed_at TIMESTAMPTZ,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
||||
);
|
||||
|
||||
CREATE INDEX idx_backups_site_id ON backups(site_id);
|
||||
CREATE INDEX idx_backups_status ON backups(status);
|
||||
|
||||
-- ─── Async job queue (panel → agent tasks) ───────────────────────────────────
|
||||
|
||||
CREATE TABLE jobs (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
uuid UUID NOT NULL DEFAULT gen_random_uuid() UNIQUE,
|
||||
server_id BIGINT REFERENCES servers(id) ON DELETE SET NULL,
|
||||
site_id BIGINT REFERENCES sites(id) ON DELETE SET NULL,
|
||||
user_id BIGINT REFERENCES users(id) ON DELETE SET NULL,
|
||||
type VARCHAR(64) NOT NULL,
|
||||
payload JSONB NOT NULL DEFAULT '{}',
|
||||
status job_status NOT NULL DEFAULT 'pending',
|
||||
result JSONB,
|
||||
error_message TEXT,
|
||||
attempts INT NOT NULL DEFAULT 0,
|
||||
max_attempts INT NOT NULL DEFAULT 3,
|
||||
scheduled_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
started_at TIMESTAMPTZ,
|
||||
completed_at TIMESTAMPTZ,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
||||
);
|
||||
|
||||
CREATE INDEX idx_jobs_status_scheduled ON jobs(status, scheduled_at)
|
||||
WHERE status IN ('pending', 'running');
|
||||
CREATE INDEX idx_jobs_server_id ON jobs(server_id);
|
||||
|
||||
-- ─── Audit log ───────────────────────────────────────────────────────────────
|
||||
|
||||
CREATE TABLE audit_logs (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
user_id BIGINT REFERENCES users(id) ON DELETE SET NULL,
|
||||
action VARCHAR(64) NOT NULL,
|
||||
resource VARCHAR(64) NOT NULL,
|
||||
resource_id BIGINT,
|
||||
details JSONB NOT NULL DEFAULT '{}',
|
||||
ip_address INET,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
||||
);
|
||||
|
||||
CREATE INDEX idx_audit_logs_user_id ON audit_logs(user_id);
|
||||
CREATE INDEX idx_audit_logs_resource ON audit_logs(resource, resource_id);
|
||||
CREATE INDEX idx_audit_logs_created_at ON audit_logs(created_at);
|
||||
|
||||
-- ─── updated_at trigger ──────────────────────────────────────────────────────
|
||||
|
||||
CREATE OR REPLACE FUNCTION set_updated_at()
|
||||
RETURNS TRIGGER AS $$
|
||||
BEGIN
|
||||
NEW.updated_at = now();
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
CREATE TRIGGER trg_users_updated_at
|
||||
BEFORE UPDATE ON users FOR EACH ROW EXECUTE PROCEDURE set_updated_at();
|
||||
|
||||
CREATE TRIGGER trg_servers_updated_at
|
||||
BEFORE UPDATE ON servers FOR EACH ROW EXECUTE PROCEDURE set_updated_at();
|
||||
|
||||
CREATE TRIGGER trg_sites_updated_at
|
||||
BEFORE UPDATE ON sites FOR EACH ROW EXECUTE PROCEDURE set_updated_at();
|
||||
|
||||
CREATE TRIGGER trg_ftp_accounts_updated_at
|
||||
BEFORE UPDATE ON ftp_accounts FOR EACH ROW EXECUTE PROCEDURE set_updated_at();
|
||||
|
||||
CREATE TRIGGER trg_ssl_certificates_updated_at
|
||||
BEFORE UPDATE ON ssl_certificates FOR EACH ROW EXECUTE PROCEDURE set_updated_at();
|
||||
|
||||
CREATE TRIGGER trg_mail_accounts_updated_at
|
||||
BEFORE UPDATE ON mail_accounts FOR EACH ROW EXECUTE PROCEDURE set_updated_at();
|
||||
|
||||
CREATE TRIGGER trg_dns_zones_updated_at
|
||||
BEFORE UPDATE ON dns_zones FOR EACH ROW EXECUTE PROCEDURE set_updated_at();
|
||||
|
||||
CREATE TRIGGER trg_dns_records_updated_at
|
||||
BEFORE UPDATE ON dns_records FOR EACH ROW EXECUTE PROCEDURE set_updated_at();
|
||||
|
||||
CREATE TRIGGER trg_cron_jobs_updated_at
|
||||
BEFORE UPDATE ON cron_jobs FOR EACH ROW EXECUTE PROCEDURE set_updated_at();
|
||||
Reference in New Issue
Block a user