Files
archivdms/internal/storage/migrations/026_accounting_api_keys.sql
T
patrick 9a24ea29e1 FDN-01: repository & projektgerüst
Git-Repository für bestehenden archivdms-Code initialisiert, Branch-/Commit-Konvention (feature/<ticket>-<slug>-Branches, Ticket-Prefix in Commit-Nachricht) etabliert.
2026-08-11 21:27:53 +02:00

47 lines
2.2 KiB
SQL

-- 026_accounting_api_keys.sql
-- Documentation only — applied via
-- internal/storage/accounting_api_keys.go (Store.initAccountingAPIKeysSchema),
-- wired into storage.New() after initSharesSchema. Idempotent
-- (CREATE TABLE / CREATE INDEX IF NOT EXISTS).
--
-- Per-tenant API keys for the read-only Buchhaltungs-Pull-API
-- (GET /api/v1/accounting/documents[/{id}/file], siehe MEMORY.md
-- project_belegdatum_und_buchhaltung). A key is a tenant-level MACHINE
-- credential, not a user session: it grants read access to that tenant's
-- archived documents and to nothing else, which is why creating one requires
-- domain_admin.
--
-- Token handling mirrors document_shares (009_shares.sql) exactly:
-- * raw key = "adms_" + base64url(32 crypto/rand bytes), generated once
-- * returned to the caller EXACTLY once (POST response), never retrievable again
-- * only the hex SHA-256 hash is persisted (key_hash, UNIQUE)
-- * authentication always looks up by key_hash, never by id
--
-- Keys are never hard-deleted: revoking sets revoked_at, so the audit trail
-- (audit event accounting_pull, Detail carries "key:<id>") stays resolvable for
-- GoBD-Nachvollziehbarkeit. ResolveAccountingAPIKey filters revoked_at IS NULL
-- inside the same UPDATE ... RETURNING that refreshes last_used_at, so a
-- revoked key can never yield a tenant id.
--
-- No FK on tenant_id / created_by: consistent with the rest of the schema
-- (plain BIGINT), because tenants/users are owned by other stores that
-- initialise after storage.New().
CREATE TABLE IF NOT EXISTS accounting_api_keys (
id BIGSERIAL PRIMARY KEY,
tenant_id BIGINT NOT NULL,
key_hash TEXT NOT NULL UNIQUE,
label TEXT NOT NULL DEFAULT '',
created_by BIGINT,
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
revoked_at TIMESTAMPTZ,
last_used_at TIMESTAMPTZ
);
CREATE INDEX IF NOT EXISTS idx_accounting_api_keys_tenant ON accounting_api_keys(tenant_id);
-- No new columns on documents: the pull query (internal/storage/accounting_pull.go)
-- reads existing columns only (document_date, document_date_score from
-- 025_document_date_score.sql, doc_type_id, correspondent_id, created_at) and
-- paginates by the (created_at, id) keyset, which idx_documents_tenant plus the
-- primary key already support.