-- +goose Up
-- +goose StatementBegin

-- Admin users (analog enconf admin_users). Auth is JWT-based; password
-- is bcrypt'd via golang.org/x/crypto/bcrypt. role is a free-form
-- text column today (only "admin" exists in v1) so future RBAC roles
-- can be added without a CHECK-constraint migration.
CREATE TABLE IF NOT EXISTS users (
    id            BIGSERIAL PRIMARY KEY,
    email         TEXT NOT NULL,
    password_hash TEXT NOT NULL,
    role          TEXT NOT NULL DEFAULT 'admin',
    active        BOOLEAN NOT NULL DEFAULT TRUE,
    last_login_at TIMESTAMPTZ,
    created_at    TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    updated_at    TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    CONSTRAINT users_email_unique UNIQUE (email)
);

CREATE INDEX IF NOT EXISTS idx_users_active ON users (active) WHERE active;

-- Append-only audit trail. Every config change, login, license event,
-- upgrade trigger gets an entry. detail is freeform JSONB so each
-- handler can attach whatever context is meaningful (e.g. diff of the
-- domain row, apt versions before/after, cluster-join token hash).
CREATE TABLE IF NOT EXISTS audit_log (
    id         BIGSERIAL PRIMARY KEY,
    actor      TEXT NOT NULL,
    action     TEXT NOT NULL,
    subject    TEXT,
    detail     JSONB,
    node_id    TEXT,
    created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

CREATE INDEX IF NOT EXISTS idx_audit_log_created_at ON audit_log (created_at DESC);
CREATE INDEX IF NOT EXISTS idx_audit_log_subject    ON audit_log (subject);
CREATE INDEX IF NOT EXISTS idx_audit_log_action     ON audit_log (action);

-- Global key/value config. Avoids one-row tables for things like
-- cluster FQDN, ACME contact e-mail, default WireGuard listen port.
-- value is TEXT — JSON encoding is on the caller if needed.
CREATE TABLE IF NOT EXISTS system_settings (
    key        TEXT PRIMARY KEY,
    value      TEXT NOT NULL,
    updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

-- +goose StatementEnd

-- +goose Down
-- +goose StatementBegin
DROP TABLE IF EXISTS system_settings;
DROP TABLE IF EXISTS audit_log;
DROP TABLE IF EXISTS users;
-- +goose StatementEnd
