diff --git a/kustomize/base/hasura/hasura-bootstrap.mjs b/kustomize/base/hasura/hasura-bootstrap.mjs index 398b7d0..2c09cf4 100644 --- a/kustomize/base/hasura/hasura-bootstrap.mjs +++ b/kustomize/base/hasura/hasura-bootstrap.mjs @@ -92,6 +92,9 @@ async function main() { const PUBLIC_DLOB_SOURCE_HEADER = 'X-Hasura-Dlob-Source'; const apiTokensTable = { schema: 'public', name: 'api_tokens' }; + const botConfigTable = { schema: 'public', name: 'bot_config' }; + const botStateTable = { schema: 'public', name: 'bot_state' }; + const botEventsTable = { schema: 'public', name: 'bot_events' }; const source = 'default'; const baseTicks = { schema: 'public', name: 'drift_ticks' }; @@ -460,6 +463,12 @@ async function main() { 'raw', ], { publicFilter: dlobPublicFilter }); + // Bot control-plane tables (tracked; permissions are intentionally not created here by default). + for (const t of [botConfigTable, botStateTable, botEventsTable]) { + await metadataIgnore({ type: 'pg_untrack_table', args: { source, table: t } }); + await metadata({ type: 'pg_track_table', args: { source, table: t } }); + } + // Return table type for candle functions (needed for Hasura to track the function). await metadataIgnore({ type: 'pg_track_table', args: { source, table: candlesReturnTable } }); diff --git a/kustomize/base/initdb/001_init.sql b/kustomize/base/initdb/001_init.sql index 6618671..d7a2b32 100644 --- a/kustomize/base/initdb/001_init.sql +++ b/kustomize/base/initdb/001_init.sql @@ -111,6 +111,50 @@ ALTER TABLE api_tokens ADD COLUMN IF NOT EXISTS scopes TEXT[] NOT NULL DEFAULT A CREATE INDEX IF NOT EXISTS api_tokens_revoked_at_idx ON api_tokens (revoked_at); +-- Bot control-plane (desired state) + executor telemetry (state/events). +-- +-- MVP intent: +-- - `bot_config`: desired state (mode/market/limits/kill switch) +-- - `bot_state`: heartbeat + last error/action +-- - `bot_events`: append-only audit log +CREATE TABLE IF NOT EXISTS public.bot_config ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + name TEXT NOT NULL UNIQUE, + market_name TEXT NOT NULL, + market_type TEXT NOT NULL DEFAULT 'perp', + mode TEXT NOT NULL DEFAULT 'off', + kill_switch BOOLEAN NOT NULL DEFAULT FALSE, + params JSONB, + created_at TIMESTAMPTZ NOT NULL DEFAULT now(), + updated_at TIMESTAMPTZ NOT NULL DEFAULT now() +); + +CREATE INDEX IF NOT EXISTS bot_config_updated_at_desc_idx + ON public.bot_config (updated_at DESC); + +CREATE TABLE IF NOT EXISTS public.bot_state ( + bot_id UUID PRIMARY KEY REFERENCES public.bot_config(id) ON DELETE CASCADE, + last_heartbeat_at TIMESTAMPTZ, + last_action_at TIMESTAMPTZ, + last_error TEXT, + state JSONB, + updated_at TIMESTAMPTZ NOT NULL DEFAULT now() +); + +CREATE INDEX IF NOT EXISTS bot_state_updated_at_desc_idx + ON public.bot_state (updated_at DESC); + +CREATE TABLE IF NOT EXISTS public.bot_events ( + id BIGSERIAL PRIMARY KEY, + bot_id UUID NOT NULL REFERENCES public.bot_config(id) ON DELETE CASCADE, + ts TIMESTAMPTZ NOT NULL DEFAULT now(), + type TEXT NOT NULL, + payload JSONB +); + +CREATE INDEX IF NOT EXISTS bot_events_bot_ts_desc_idx + ON public.bot_events (bot_id, ts DESC); + -- Compute OHLC candles from `drift_ticks` for a symbol and bucket size. -- Exposed via Hasura (track function) and used by trade-api to compute indicators server-side. -- Hasura tracks functions only if they return SETOF a table/view type.