This directory contains SQL migration files for database schema changes. The migration system uses SHA256 checksums to ensure migration immutability and consistency across environments.
Format: NNN_description.sql
NNN: Sequential number (e.g., 001, 002, 003)description: Brief description in snake_caseExample: 017_add_gemini_tier_id.sql
_notx.sql 命名与执行语义(并发索引专用)当迁移包含 CREATE INDEX CONCURRENTLY 或 DROP INDEX CONCURRENTLY 时,必须使用 _notx.sql 后缀,例如:
062_add_accounts_priority_indexes_notx.sql063_drop_legacy_indexes_notx.sql运行规则:
*.sql(不带 _notx)按事务执行。*_notx.sql 按非事务执行,不会包裹在 BEGIN/COMMIT 中。*_notx.sql 仅允许并发索引语句,不允许混入事务控制语句或其他 DDL/DML。幂等要求(必须):
CREATE INDEX CONCURRENTLY IF NOT EXISTS ...DROP INDEX CONCURRENTLY IF EXISTS ...这样可以保证灾备重放、重复执行时不会因对象已存在/不存在而失败。
This project uses a custom migration runner (internal/repository/migrations_runner.go) that executes the full SQL file content as-is.
*.sql): executed in a transaction.Non-transactional migrations (*_notx.sql): split by statement and executed without transaction (for CONCURRENTLY).
-- Forward-only migration (recommended)
ALTER TABLE usage_logs ADD COLUMN IF NOT EXISTS example_column VARCHAR(100);
⚠️ Do not place executable "Down" SQL in the same file. The runner does not parse goose Up/Down sections and will execute all SQL statements in the file.
Once a migration is applied to ANY environment (dev, staging, production), it MUST NOT be modified.
Why?
schema_migrations tableCreate new migration
# Create new file with next sequential number
touch migrations/018_your_change.sql
Write forward-only migration SQL
Test locally
# Apply migration
make migrate-up
# Test rollback
make migrate-down
Commit and deploy
git add migrations/018_your_change.sql
git commit -m "feat(db): add your change"
Error message:
migration 017_add_gemini_tier_id.sql checksum mismatch (db=abc123... file=def456...)
Solution:
# 1. Find the original version
git log --oneline -- migrations/017_add_gemini_tier_id.sql
# 2. Revert to the commit when it was first applied
git checkout <commit-hash> -- migrations/017_add_gemini_tier_id.sql
# 3. Create a NEW migration for your changes
touch migrations/018_your_new_change.sql
schema_migrations (filename, checksum, applied_at)internal/repository/migrations_runner.goKeep migrations small and focused
Write reversible migrations
Use transactions
Add comments
Test in development first
-- Add tier_id field to Gemini OAuth accounts for quota tracking
UPDATE accounts
SET credentials = jsonb_set(
credentials,
'{tier_id}',
'"LEGACY"',
true
)
WHERE platform = 'gemini'
AND type = 'oauth'
AND credentials->>'tier_id' IS NULL;
See "If You Accidentally Modified an Applied Migration" above.
# Check migration status
psql -d sub2api -c "SELECT * FROM schema_migrations ORDER BY applied_at DESC;"
# Manually rollback if needed (use with caution)
# Better to fix the migration and create a new one
-- DANGEROUS: Only use in development or with extreme caution
INSERT INTO schema_migrations (filename, checksum, applied_at)
VALUES ('NNN_migration.sql', 'calculated_checksum', NOW());
internal/repository/migrations_runner.go