Files
claudetools/.claude/standards/gururmm/sqlx-migrations.md
Mike Swanson dd0ef45645 feat: implement agent-os standards system and feature planning tools
- Split CODING_GUIDELINES.md into 19 indexed standards files under .claude/standards/
  - 9 from CODING_GUIDELINES (conventions, powershell, security, api, git, gururmm)
  - 10 from session log tribal knowledge (syncro, ssh, gitea, python, client, gururmm)
- Add .claude/standards/index.yml for cheap relevance-based lookup
- Add /inject-standards command: load targeted standards per task instead of full guidelines
- Add /shape-spec command: pre-implementation spec for GuruRMM features (plan.md,
  shape.md, references.md, standards.md) with mandatory out-of-scope gate
- Add docs/tech-stack.md and docs/mission.md for ClaudeTools API
- Add projects/msp-tools/guru-rmm/docs/tech-stack.md and mission.md for GuruRMM
- Update CLAUDE.md commands table with /inject-standards and /shape-spec

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-16 12:59:49 -07:00

3.4 KiB

name, description, applies-to
name description applies-to
sqlx-migrations Never manually pre-apply migrations without tracking rows; use IF NOT EXISTS; let the server apply its own migrations gururmm

GuruRMM sqlx Migration Discipline

The core rule

Never manually pre-apply migrations via psql without also recording the corresponding row in _sqlx_migrations. If the row is missing, the server binary will attempt to re-run the migration at startup and fail when it finds the table or column already exists.

The correct workflow

Let the server binary apply its own migrations on startup:

1. Write the SQL migration file (server/migrations/NNN_description.sql)
2. Use ADD COLUMN IF NOT EXISTS / CREATE TABLE IF NOT EXISTS for idempotence
3. Run cargo sqlx prepare (keeps .sqlx/ offline cache current)
4. Commit the migration file + .sqlx/ changes
5. Build the server binary (push to Gitea triggers build-server.sh)
6. Deploy: stop → copy binary → start
7. sqlx applies the migration on startup and records the checksum row

Do not pre-apply the SQL with psql. Do not insert rows into _sqlx_migrations manually unless recovering from a specific failure.

Why: the proc macro excludes pre-applied rows

When DATABASE_URL is set at compile time, sqlx::migrate!() queries _sqlx_migrations during compilation and embeds only the migrations not yet present in the DB. If you pre-apply migration 026 via psql and its row is in _sqlx_migrations before the build, the compiled binary will not contain migration 026 — then at runtime, finding a row for version 26 with no matching embedded migration causes a fatal startup error.

The fix: delete the pre-applied _sqlx_migrations row(s), rebuild with SQLX_OFFLINE=true, let the server apply them naturally.

Write idempotent SQL

All migrations use IF NOT EXISTS or IF EXISTS forms:

-- Tables
CREATE TABLE IF NOT EXISTS policy_checks (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    ...
);

-- Columns
ALTER TABLE agents ADD COLUMN IF NOT EXISTS update_channel TEXT
    CHECK (update_channel IN ('stable', 'beta'));

This protects against the "table already exists" error if a migration is somehow applied twice, and allows the migration to be run safely during development resets.

SQLX_OFFLINE build environment

SQLX_OFFLINE=true is set permanently in /home/guru/.cargo/env on Saturn. All cargo builds by the guru user use the .sqlx/ offline cache rather than querying the live DB at compile time. This eliminates the proc macro/DB interaction entirely.

After any schema change that adds or modifies a query!() macro, re-run:

cd /home/guru/gururmm/server && cargo sqlx prepare
git add server/.sqlx && git commit -m "build: update sqlx offline query cache"

Recovery from _sqlx_migrations mismatch

If the server fails to start with "migration N was previously applied but is missing in the resolved migrations":

# Option 1: Delete the row (if the migration was manually applied and tables exist)
PGPASSWORD=<pw> psql -h localhost -U gururmm -d gururmm \
  -c "DELETE FROM _sqlx_migrations WHERE version IN (N);"
# Then rebuild so the binary embeds the migration

# Option 2: If checksum mismatch (binary embedded wrong content)
# Fix the SQL file, rerun cargo sqlx prepare, rebuild, deploy

Never delete _sqlx_migrations rows for migrations that the current binary does NOT embed — those rows protect against re-running already-applied migrations.