Skip to content

fix(indexer): remove ensureSchema() and add startup schema-version guard - #1186

Open
Chucks1093 wants to merge 2 commits into
Epta-Node:mainfrom
Chucks1093:feat/issue-1176-schema-version-guard
Open

fix(indexer): remove ensureSchema() and add startup schema-version guard#1186
Chucks1093 wants to merge 2 commits into
Epta-Node:mainfrom
Chucks1093:feat/issue-1176-schema-version-guard

Conversation

@Chucks1093

Copy link
Copy Markdown
Contributor

Closes #1176

What changed

1. ensureSchema() removed from src/index.ts

The function ran 15+ CREATE TABLE IF NOT EXISTS / CREATE INDEX IF NOT EXISTS statements on every process startup, bypassing the versioned migration suite in services/indexer/migrations/. Problems:

  • Silently created old schema on fresh deployments that hadn't yet had migrations applied
  • CREATE TABLE IF NOT EXISTS is a no-op on existing tables, so additive column changes from migrations were never applied to existing deployments
  • Acquired AccessShareLock on pg_class on every startup
  • No rollback path

2. src/schema-version.ts — startup guard

New assertSchemaVersion(pool) function replaces ensureSchema() in main(). It queries pg_tables and information_schema.columns to verify that all sentinel tables and columns are present, and calls process.exit(1) with a descriptive error message if any are missing:

DB schema is out of date — run migrations before starting the indexer:
  bash services/indexer/migrate.sh
  (or: docker compose run --rm migrate)

Sentinel tables checked: raw_events, indexer_cursor, indexer_state, device_tokens, sent_notifications, blocks, dm_keys, notification_preferences (011 — forward-progress sentinel).
Sentinel column checked: posts.content_tsv (added by 009_posts_fts).

3. docker-compose.ymlmigrate init service

Added a migrate one-shot service that applies all .sql files in filename order before the indexer starts:

migrate:
  image: postgres:16-alpine
  restart: "no"
  depends_on:
    postgres:
      condition: service_healthy
  ...

indexer:
  depends_on:
    postgres:
      condition: service_healthy
    migrate:
      condition: service_completed_successfully

The postgres service's initdb.d mount is removed — migrations are now always applied explicitly by the migrate service, not implicitly on first boot.

4. migrate.sh — bare-metal migration runner

New services/indexer/migrate.sh for CI / bare-metal deployments (no Docker required):

DATABASE_URL=postgresql://user:pass@host/db bash services/indexer/migrate.sh

5. tests/migrations/test-migrations.sh — Step 10

New step verifies the assertSchemaVersion() sentinel invariants after the full migration run, and confirms the sentinel table (notification_preferences) is absent on a partially-migrated DB (negative test).

6. migrations/README.md updated

Removed the ensureSchema() paragraph and replaced it with instructions for running migrations via docker compose up or migrate.sh.

Tests

src/__tests__/schema-version.test.ts — 5 Jest cases:

  • Resolves cleanly when all sentinel tables and columns are present
  • Calls process.exit(1) when a required table is missing
  • Calls process.exit(1) when posts.content_tsv is missing
  • Reports all missing tables in a single error call
  • Passes when the table list is a superset of the required tables

@vercel

vercel Bot commented Aug 26, 2026

Copy link
Copy Markdown

@Chucks1093 is attempting to deploy a commit to the Jaja's projects Team on Vercel.

A member of the Team first needs to authorize it.

@devJaja
devJaja self-requested a review August 27, 2026 06:08
@devJaja

devJaja commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

Nice work @Chucks1093

Kindly fix all the ci checks failure

@devJaja

devJaja commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

@Chucks1093

Resolve conflicts

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Backend: ensureSchema() runs un-versioned DDL on every startup — production schema drift, no rollback path

2 participants