Files
selfpost/internal/store/migrations/0001_init.sql
T
mix 8ce050ef7f release: 0.1.0: Phases 0-11: panel, Postfix/DKIM, milter, backup, Docker image
Initial feature-complete implementation of the v1.0 specification (phases 0-11 of `docs/implementation-plan.md`).
Added:
  - Panel (Go, single static binary) with SQLite persistence, one-time
  - Domain management with per-domain DKIM (RSA-2048, generated in pure Go) and
  - Application (sender identity) management: SASL credentials via `sasldb2`,
  - Full Postfix relay config generated from env at container start: SMTPS 465,
  - Journal milter (pure Go, `go-milter`) recording every send to `send_log`;
  … (6 more in CHANGELOG)

Full detail: CHANGELOG.md (0.1.0).
2026-09-22 15:24:51 +03:00

77 lines
2.9 KiB
SQL

-- Initial SelfPost schema (spec 9). One SQLite file under /data holds the whole
-- panel state so a single directory backup/restore is sufficient (spec 7.5.A).
-- Single administrator account (spec 7.6.1). Exactly one row is allowed; the
-- presence of that row is what marks primary setup as complete, which is why
-- the /setup route disappears once it exists.
CREATE TABLE admin (
id INTEGER PRIMARY KEY CHECK (id = 1),
username TEXT NOT NULL,
password_hash TEXT NOT NULL,
created_at TEXT NOT NULL
);
-- Free-form key/value panel settings (retention overrides, misc flags).
CREATE TABLE settings (
key TEXT PRIMARY KEY,
value TEXT NOT NULL
);
-- Sending domains managed through the panel (spec 4.1). DKIM keys themselves
-- live on disk under /data; this row records the selector and metadata.
CREATE TABLE domains (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL UNIQUE,
dkim_selector TEXT NOT NULL,
created_at TEXT NOT NULL
);
-- Applications bound to a domain (spec 4.1). address_mode is either the domain
-- wildcard or an explicit address list; the SASL login is globally unique.
CREATE TABLE applications (
id INTEGER PRIMARY KEY AUTOINCREMENT,
domain_id INTEGER NOT NULL REFERENCES domains(id) ON DELETE CASCADE,
login TEXT NOT NULL UNIQUE,
address_mode TEXT NOT NULL CHECK (address_mode IN ('wildcard', 'list')),
created_at TEXT NOT NULL
);
-- Explicit sender addresses for applications in 'list' mode. Each address must
-- belong to the application's domain (validated in the panel, spec 7.6.2).
CREATE TABLE application_addresses (
id INTEGER PRIMARY KEY AUTOINCREMENT,
application_id INTEGER NOT NULL REFERENCES applications(id) ON DELETE CASCADE,
address TEXT NOT NULL,
UNIQUE (application_id, address)
);
-- Structured send log (spec 7.3). One row per (queue-id, recipient); the
-- log-tailer advances status from queued to a final state.
CREATE TABLE send_log (
id INTEGER PRIMARY KEY AUTOINCREMENT,
queue_id TEXT,
domain TEXT,
app_login TEXT,
from_addr TEXT,
to_addr TEXT,
subject TEXT,
status TEXT NOT NULL,
created_at TEXT NOT NULL,
updated_at TEXT NOT NULL
);
CREATE INDEX idx_send_log_queue_id ON send_log (queue_id);
CREATE INDEX idx_send_log_domain ON send_log (domain);
CREATE INDEX idx_send_log_created_at ON send_log (created_at);
-- Differentiated rate limits per domain/application (spec 7.4). Both the IP
-- binding and the message limit are optional.
CREATE TABLE rate_limits (
id INTEGER PRIMARY KEY AUTOINCREMENT,
scope TEXT NOT NULL CHECK (scope IN ('domain', 'application')),
ref_id INTEGER NOT NULL,
allowed_ips TEXT,
max_messages INTEGER,
window_seconds INTEGER,
UNIQUE (scope, ref_id)
);