Sangeetha-Grantha

Metadata Value
Status Superseded by ADR-013
Version 1.1.0
Last Updated 2026-09-10
Author Sangeetha Grantha Team
Document Type Decision record
Supersedes ADR-003

ADR-010: Migration Tool Course Correction — Rust CLI to Python db-migrate + Makefile


[!NOTE] Decision record: preserve the original rationale and check its decision/supersession status. Current runtime guidance is in system architecture and Flyway migrations.

Context

ADR-003 established a custom Rust CLI (tools/sangita-cli) using sqlx as the database migration tool. After 10 months of production use, several pain points emerged:

  1. Toolchain burden: The Rust CLI required maintaining a separate Rust toolchain alongside Kotlin/JVM (backend), Node/Bun (frontend), and Python (extraction). Four language ecosystems was excessive for the team size.
  2. Compilation overhead: Rust’s compile times (30-60 seconds for incremental builds) created friction for simple migration tasks that should take seconds.
  3. Feature stagnation: The CLI’s database commands worked but saw no feature evolution — rollbacks remained unimplemented, and the CLI’s other capabilities (network config, health checks) were rarely used.
  4. Docker Compose already running: The development workflow already used Docker Compose for PostgreSQL and the backend. Adding migration execution to Docker Compose was natural.
  5. Python already in the stack: The extraction worker (tools/krithi-extract-enrich-worker) already required Python, so Python was not a new dependency.

The Rust CLI was archived as part of TRACK-078 (February 2026).

Decision

Replace the Rust-based migration CLI with a Python db-migrate tool (tools/db-migrate/) combined with a Makefile as the developer workflow interface.

Rationale

  1. Fewer moving parts: Eliminates the Rust toolchain entirely. The project now uses three language ecosystems (Kotlin, TypeScript, Python) instead of four.
  2. Instant execution: Python migrations run in under 1 second vs 30+ seconds for Rust compilation + execution.
  3. Makefile as universal interface: make migrate is language-agnostic, self-documenting, and tab-completable. Every developer knows Make.
  4. Docker Compose alignment: Database lifecycle (start, stop, reset) is managed by Docker Compose, which was already the standard for local development.
  5. Python simplicity: The migration logic is ~200 lines of straightforward Python — easy to understand, debug, and extend.
  6. Migration files unchanged: The SQL migration files in database/migrations/ required zero changes. The -- migrate:up / -- migrate:down format works identically.

Implementation Details

New Tool Structure

tools/db-migrate/
├── db_migrate.py          # Migration runner (psycopg2)
├── requirements.txt       # Python dependencies
└── README.md              # Usage documentation

Makefile Targets

make db             # Start PostgreSQL via Docker Compose
make db-reset       # Drop → create → migrate → seed
make migrate        # Run pending migrations only
make seed           # Execute seed data scripts
make clean          # Remove all containers and volumes

Migration File Format (unchanged)

Files in database/migrations/ follow NN__description.sql naming:

-- migrate:up
SET search_path TO public;
-- SQL statements here

-- migrate:down
-- Rollback SQL (optional)

Current Migrations (38 total as of March 2026)

The migration count grew from 7 (at ADR-003 time) to 38, covering:

Consequences

Positive

Negative

Neutral

Follow-up

References


Section index · Documentation home · Feature status