feat(db): Phase 1 — DB-Schema, goose-Migrations, GORM-Models
Initialer Schema-Set (8 Migrationen, 13 Tabellen) für EdgeGuard v1: users + audit_log + system_settings, ha_nodes, backends/domains/ routing_rules/tls_certs, forward_proxy_acls, wireguard_peers, firewall_rules, dns_zones/dns_records, licenses. Migrations liegen in internal/database/migrations/ (analog mail-gateway) und werden per //go:embed ins Binary gepackt — keine separate SQL-Dateien im .deb. ValidateMigrations + Test schützen vor Duplicate-Versionen (mail-gateway 2026-05-08-Vorfall). GORM-Models für alle Tabellen, sensible Felder (password_hash, private_key_enc) sind json:"-". Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
56
internal/database/migrations/0001_init.sql
Normal file
56
internal/database/migrations/0001_init.sql
Normal file
@@ -0,0 +1,56 @@
|
||||
-- +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
|
||||
Reference in New Issue
Block a user