-- ============================================================================= -- VIBN fs_* tables + agent_sessions migration -- Run once against the production Coolify Postgres database. -- -- These tables back the live app (fs_ prefix = "Firestore-shaped" flexible -- JSONB rows that replaced the original Firebase collections). -- -- Safe to re-run — all statements use IF NOT EXISTS / ON CONFLICT. -- ============================================================================= -- Enable uuid support (safe no-op if already enabled) CREATE EXTENSION IF NOT EXISTS "uuid-ossp"; -- --------------------------------------------------------------------------- -- fs_users (mirrors Firebase Auth + Firestore user docs) -- --------------------------------------------------------------------------- CREATE TABLE IF NOT EXISTS fs_users ( id TEXT PRIMARY KEY, -- gen_random_uuid()::text at insert time user_id TEXT, -- NextAuth User.id (cuid) data JSONB NOT NULL DEFAULT '{}', created_at TIMESTAMPTZ NOT NULL DEFAULT now(), updated_at TIMESTAMPTZ NOT NULL DEFAULT now() ); CREATE INDEX IF NOT EXISTS fs_users_email_idx ON fs_users ((data->>'email')); CREATE INDEX IF NOT EXISTS fs_users_user_id_idx ON fs_users (user_id); -- --------------------------------------------------------------------------- -- fs_projects (Firestore projects collection) -- --------------------------------------------------------------------------- CREATE TABLE IF NOT EXISTS fs_projects ( id TEXT PRIMARY KEY, -- randomUUID() at insert time user_id TEXT NOT NULL, -- FK → fs_users.id workspace TEXT NOT NULL, slug TEXT NOT NULL UNIQUE, data JSONB NOT NULL DEFAULT '{}', created_at TIMESTAMPTZ NOT NULL DEFAULT now(), updated_at TIMESTAMPTZ NOT NULL DEFAULT now() ); CREATE INDEX IF NOT EXISTS fs_projects_user_idx ON fs_projects (user_id); CREATE INDEX IF NOT EXISTS fs_projects_workspace_idx ON fs_projects (workspace); CREATE INDEX IF NOT EXISTS fs_projects_slug_idx ON fs_projects (slug); -- --------------------------------------------------------------------------- -- fs_sessions (AI coding session logs) -- --------------------------------------------------------------------------- CREATE TABLE IF NOT EXISTS fs_sessions ( id TEXT PRIMARY KEY, user_id TEXT, data JSONB NOT NULL DEFAULT '{}', created_at TIMESTAMPTZ NOT NULL DEFAULT now(), updated_at TIMESTAMPTZ NOT NULL DEFAULT now() ); CREATE INDEX IF NOT EXISTS fs_sessions_user_idx ON fs_sessions (user_id); CREATE INDEX IF NOT EXISTS fs_sessions_project_idx ON fs_sessions ((data->>'projectId')); -- --------------------------------------------------------------------------- -- agent_sessions (vibn-agent-runner execution records) -- --------------------------------------------------------------------------- CREATE TABLE IF NOT EXISTS agent_sessions ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), project_id TEXT NOT NULL, -- fs_projects.id (TEXT) app_name TEXT NOT NULL, app_path TEXT NOT NULL, task TEXT NOT NULL, plan JSONB, status TEXT NOT NULL DEFAULT 'pending', output JSONB NOT NULL DEFAULT '[]'::jsonb, changed_files JSONB NOT NULL DEFAULT '[]'::jsonb, error TEXT, started_at TIMESTAMPTZ, completed_at TIMESTAMPTZ, created_at TIMESTAMPTZ NOT NULL DEFAULT now(), updated_at TIMESTAMPTZ NOT NULL DEFAULT now() ); CREATE INDEX IF NOT EXISTS agent_sessions_project_idx ON agent_sessions (project_id, created_at DESC); CREATE INDEX IF NOT EXISTS agent_sessions_status_idx ON agent_sessions (status); -- --------------------------------------------------------------------------- -- agent_session_events (append-only timeline for SSE + replay) -- --------------------------------------------------------------------------- CREATE TABLE IF NOT EXISTS agent_session_events ( id BIGSERIAL PRIMARY KEY, session_id UUID NOT NULL REFERENCES agent_sessions(id) ON DELETE CASCADE, project_id TEXT NOT NULL, seq INT NOT NULL, ts TIMESTAMPTZ NOT NULL, type TEXT NOT NULL, payload JSONB NOT NULL DEFAULT '{}'::jsonb, client_event_id UUID UNIQUE, created_at TIMESTAMPTZ NOT NULL DEFAULT now(), UNIQUE(session_id, seq) ); CREATE INDEX IF NOT EXISTS agent_session_events_session_seq_idx ON agent_session_events (session_id, seq); -- --------------------------------------------------------------------------- -- NextAuth / Prisma tables (required by PrismaAdapter + strategy:"database") -- Only created if not already present from a prisma migrate run. -- --------------------------------------------------------------------------- CREATE TABLE IF NOT EXISTS users ( id TEXT PRIMARY KEY, name TEXT, email TEXT UNIQUE, email_verified TIMESTAMPTZ, image TEXT ); CREATE TABLE IF NOT EXISTS accounts ( id TEXT PRIMARY KEY, user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE, type TEXT NOT NULL, provider TEXT NOT NULL, provider_account_id TEXT NOT NULL, refresh_token TEXT, access_token TEXT, expires_at INTEGER, token_type TEXT, scope TEXT, id_token TEXT, session_state TEXT, UNIQUE (provider, provider_account_id) ); CREATE TABLE IF NOT EXISTS sessions ( id TEXT PRIMARY KEY, session_token TEXT UNIQUE NOT NULL, user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE, expires TIMESTAMPTZ NOT NULL ); CREATE TABLE IF NOT EXISTS verification_tokens ( identifier TEXT NOT NULL, token TEXT UNIQUE NOT NULL, expires TIMESTAMPTZ NOT NULL, UNIQUE (identifier, token) ); -- Done SELECT 'Migration complete' AS status;