-- YakPanel 2026 core schema
-- PostgreSQL 15+ compatible

CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
CREATE EXTENSION IF NOT EXISTS "citext";

-- Shared timestamps helper convention:
-- created_at timestamptz not null default now()
-- updated_at timestamptz not null default now()

CREATE TABLE tenants (
    id uuid PRIMARY KEY DEFAULT uuid_generate_v4(),
    name varchar(150) NOT NULL,
    slug citext NOT NULL UNIQUE,
    status varchar(32) NOT NULL DEFAULT 'active',
    plan_code varchar(64) NOT NULL DEFAULT 'starter',
    settings jsonb NOT NULL DEFAULT '{}'::jsonb,
    created_at timestamptz NOT NULL DEFAULT now(),
    updated_at timestamptz NOT NULL DEFAULT now()
);

CREATE TABLE users (
    id uuid PRIMARY KEY DEFAULT uuid_generate_v4(),
    email citext NOT NULL UNIQUE,
    password_hash text NOT NULL,
    display_name varchar(120) NOT NULL,
    is_platform_admin boolean NOT NULL DEFAULT false,
    last_login_at timestamptz NULL,
    created_at timestamptz NOT NULL DEFAULT now(),
    updated_at timestamptz NOT NULL DEFAULT now()
);

CREATE TABLE tenant_users (
    id uuid PRIMARY KEY DEFAULT uuid_generate_v4(),
    tenant_id uuid NOT NULL REFERENCES tenants(id) ON DELETE CASCADE,
    user_id uuid NOT NULL REFERENCES users(id) ON DELETE CASCADE,
    status varchar(32) NOT NULL DEFAULT 'active',
    joined_at timestamptz NOT NULL DEFAULT now(),
    created_at timestamptz NOT NULL DEFAULT now(),
    updated_at timestamptz NOT NULL DEFAULT now(),
    UNIQUE (tenant_id, user_id)
);

CREATE TABLE roles (
    id uuid PRIMARY KEY DEFAULT uuid_generate_v4(),
    tenant_id uuid NOT NULL REFERENCES tenants(id) ON DELETE CASCADE,
    name varchar(64) NOT NULL,
    description text NOT NULL DEFAULT '',
    is_system boolean NOT NULL DEFAULT false,
    created_at timestamptz NOT NULL DEFAULT now(),
    updated_at timestamptz NOT NULL DEFAULT now(),
    UNIQUE (tenant_id, name)
);

CREATE TABLE permissions (
    id uuid PRIMARY KEY DEFAULT uuid_generate_v4(),
    code varchar(100) NOT NULL UNIQUE,
    description text NOT NULL DEFAULT '',
    created_at timestamptz NOT NULL DEFAULT now(),
    updated_at timestamptz NOT NULL DEFAULT now()
);

CREATE TABLE role_permissions (
    role_id uuid NOT NULL REFERENCES roles(id) ON DELETE CASCADE,
    permission_id uuid NOT NULL REFERENCES permissions(id) ON DELETE CASCADE,
    created_at timestamptz NOT NULL DEFAULT now(),
    PRIMARY KEY (role_id, permission_id)
);

CREATE TABLE user_roles (
    tenant_user_id uuid NOT NULL REFERENCES tenant_users(id) ON DELETE CASCADE,
    role_id uuid NOT NULL REFERENCES roles(id) ON DELETE CASCADE,
    created_at timestamptz NOT NULL DEFAULT now(),
    PRIMARY KEY (tenant_user_id, role_id)
);

CREATE TABLE scopes (
    id uuid PRIMARY KEY DEFAULT uuid_generate_v4(),
    tenant_id uuid NOT NULL REFERENCES tenants(id) ON DELETE CASCADE,
    role_id uuid NULL REFERENCES roles(id) ON DELETE CASCADE,
    resource_type varchar(64) NOT NULL,
    resource_id uuid NULL,
    action varchar(64) NOT NULL,
    effect varchar(8) NOT NULL DEFAULT 'allow',
    conditions jsonb NOT NULL DEFAULT '{}'::jsonb,
    created_at timestamptz NOT NULL DEFAULT now(),
    updated_at timestamptz NOT NULL DEFAULT now()
);

CREATE TABLE servers (
    id uuid PRIMARY KEY DEFAULT uuid_generate_v4(),
    tenant_id uuid NOT NULL REFERENCES tenants(id) ON DELETE CASCADE,
    name varchar(120) NOT NULL,
    host varchar(255) NOT NULL,
    port integer NOT NULL DEFAULT 443,
    os_type varchar(32) NOT NULL,
    status varchar(32) NOT NULL DEFAULT 'provisioning',
    region varchar(64) NOT NULL DEFAULT 'global',
    labels jsonb NOT NULL DEFAULT '[]'::jsonb,
    heartbeat_at timestamptz NULL,
    created_at timestamptz NOT NULL DEFAULT now(),
    updated_at timestamptz NOT NULL DEFAULT now(),
    UNIQUE (tenant_id, name)
);

CREATE TABLE server_agents (
    id uuid PRIMARY KEY DEFAULT uuid_generate_v4(),
    tenant_id uuid NOT NULL REFERENCES tenants(id) ON DELETE CASCADE,
    server_id uuid NOT NULL REFERENCES servers(id) ON DELETE CASCADE,
    agent_uid varchar(128) NOT NULL UNIQUE,
    agent_version varchar(32) NOT NULL,
    capabilities jsonb NOT NULL DEFAULT '{}'::jsonb,
    cert_fingerprint varchar(255) NOT NULL,
    last_seen_at timestamptz NULL,
    status varchar(32) NOT NULL DEFAULT 'offline',
    created_at timestamptz NOT NULL DEFAULT now(),
    updated_at timestamptz NOT NULL DEFAULT now()
);

CREATE TABLE jobs (
    id uuid PRIMARY KEY DEFAULT uuid_generate_v4(),
    tenant_id uuid NOT NULL REFERENCES tenants(id) ON DELETE CASCADE,
    server_id uuid NULL REFERENCES servers(id) ON DELETE SET NULL,
    requested_by_user_id uuid NULL REFERENCES users(id) ON DELETE SET NULL,
    type varchar(64) NOT NULL,
    status varchar(32) NOT NULL DEFAULT 'queued',
    priority smallint NOT NULL DEFAULT 5,
    idempotency_key varchar(120) NOT NULL,
    payload jsonb NOT NULL DEFAULT '{}'::jsonb,
    result jsonb NULL,
    started_at timestamptz NULL,
    finished_at timestamptz NULL,
    created_at timestamptz NOT NULL DEFAULT now(),
    updated_at timestamptz NOT NULL DEFAULT now(),
    UNIQUE (tenant_id, idempotency_key)
);

CREATE TABLE job_steps (
    id uuid PRIMARY KEY DEFAULT uuid_generate_v4(),
    job_id uuid NOT NULL REFERENCES jobs(id) ON DELETE CASCADE,
    step_order integer NOT NULL,
    name varchar(80) NOT NULL,
    status varchar(32) NOT NULL DEFAULT 'pending',
    input jsonb NOT NULL DEFAULT '{}'::jsonb,
    output jsonb NULL,
    error text NULL,
    started_at timestamptz NULL,
    finished_at timestamptz NULL,
    created_at timestamptz NOT NULL DEFAULT now(),
    updated_at timestamptz NOT NULL DEFAULT now(),
    UNIQUE (job_id, step_order)
);

CREATE TABLE job_events (
    id bigserial PRIMARY KEY,
    tenant_id uuid NOT NULL REFERENCES tenants(id) ON DELETE CASCADE,
    job_id uuid NOT NULL REFERENCES jobs(id) ON DELETE CASCADE,
    event_type varchar(64) NOT NULL,
    source varchar(32) NOT NULL,
    payload jsonb NOT NULL DEFAULT '{}'::jsonb,
    created_at timestamptz NOT NULL DEFAULT now()
);

CREATE INDEX idx_job_events_tenant_job_created ON job_events (tenant_id, job_id, created_at DESC);

CREATE TABLE audit_logs (
    id bigserial PRIMARY KEY,
    tenant_id uuid NULL REFERENCES tenants(id) ON DELETE SET NULL,
    actor_user_id uuid NULL REFERENCES users(id) ON DELETE SET NULL,
    actor_type varchar(32) NOT NULL,
    action varchar(80) NOT NULL,
    resource_type varchar(64) NOT NULL,
    resource_id uuid NULL,
    request_id varchar(64) NULL,
    ip inet NULL,
    user_agent text NULL,
    metadata jsonb NOT NULL DEFAULT '{}'::jsonb,
    created_at timestamptz NOT NULL DEFAULT now()
);

CREATE INDEX idx_audit_logs_tenant_created ON audit_logs (tenant_id, created_at DESC);
CREATE INDEX idx_scopes_tenant_action ON scopes (tenant_id, action);
CREATE INDEX idx_servers_tenant_status ON servers (tenant_id, status);
CREATE INDEX idx_jobs_tenant_status ON jobs (tenant_id, status);
