Files
CurrenciCombo/orchestrator/src/db/migrations/003_events.ts
nsatoshi cb376eda31
Some checks failed
CI / Frontend Lint (push) Has been cancelled
CI / Frontend Type Check (push) Has been cancelled
CI / Frontend Build (push) Has been cancelled
CI / Frontend E2E Tests (push) Has been cancelled
CI / Orchestrator Build (push) Has been cancelled
CI / Contracts Compile (push) Has been cancelled
CI / Contracts Test (push) Has been cancelled
Security Scan / Dependency Vulnerability Scan (push) Has been cancelled
Security Scan / OWASP ZAP Scan (push) Has been cancelled
PR D: typed + signed event bus + events table + SSE (arch step 5) (#8)
2026-04-22 17:17:40 +00:00

44 lines
1.4 KiB
TypeScript

import { query } from "../postgres";
/**
* Migration 003 — append-only events journal (arch §4.5, §5.5, §7).
*
* The `events` table is the system-of-record for normalised workflow
* events (arch §7.2: `transaction.created`, `instrument.ready`,
* `payment.settled`, `transaction.committed`, …). It is:
*
* - append-only (no UPDATE / DELETE)
* - signed (HMAC of (plan_id, type, payload_hash, prev_hash))
* - hash-chained via prev_hash for tamper-evident forensic replay
* - indexed by plan_id so the SSE endpoint can stream efficiently
*/
export async function up() {
await query(
`CREATE TABLE IF NOT EXISTS events (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
plan_id UUID NOT NULL REFERENCES plans(plan_id) ON DELETE CASCADE,
type VARCHAR(128) NOT NULL,
actor VARCHAR(255),
payload JSONB NOT NULL DEFAULT '{}'::jsonb,
payload_hash CHAR(64) NOT NULL,
prev_hash CHAR(64),
signature CHAR(64) NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP
)`,
);
await query(
`CREATE INDEX IF NOT EXISTS idx_events_plan_id_created
ON events(plan_id, created_at)`,
);
await query(
`CREATE INDEX IF NOT EXISTS idx_events_type
ON events(type)`,
);
}
export async function down() {
await query("DROP TABLE IF EXISTS events CASCADE");
}