

Also from Kynth Studios


Also from Kynth Studios


Also from Kynth Studios
12345# Database Migration Guidelines67## When to Use This Rule89**Use this rule when:**10- Creating new database migrations11- Modifying database schema12- Understanding migration file naming conventions13- Working with Flyway migrations14- Troubleshooting migration issues15- Versioning database changes16- Squashing / collapsing historical migrations into the baseline1718## Migration Tool1920The project uses Flyway for database migrations, configured in Spring Boot.2122## Migration Files Location2324* SQL migrations: `backend/src/main/resources/db/migration/`25* Java migrations: `backend/src/main/java/db/migration/`26* Files follow the naming convention: `V{version}__{description}.sql` (or `.java`)27 * Example: `V300000231__rename_a_column.sql` (version must exceed **`300000230`**)2829## Version Numbering3031* Versions use a numerical format3233The project uses versioned files named `V{number}__{description}.sql`. The current full application DDL is collapsed into **`V100000000__baseline.sql`**; **`V300000230__db_migration_placeholder.sql`** is a placeholder for the next migration.3435New migrations need to use a **greater** version number than **`300000230`**.3637### Migration Process3839* Migrations run automatically when the application starts (non-test environments)40* Non-test startup runs **`flyway.repair()` then `flyway.migrate()`** (`FlyWayFreeVersionRealMigration`). `repair()` is what makes squashing safe on existing databases (checksum realign + remove history for deleted files).41* For unit tests, DB migration is included in the test command (see `backend-development` rule for test execution)4243## Migration file structure4445* **`V100000000__baseline.sql`** holds the collapsed full DDL (fresh installs).46* **`V300000230__db_migration_placeholder.sql`** is the tail placeholder; add new migrations with a higher version.47* Each **new** file after that should contain one atomic change (create/alter/rename/drop as needed).4849## Best Practices:5051* Each migration should be reversible when possible52* Migrations are version controlled and should never be modified once committed (except the intentional baseline content replace during a squash — see below)53* New changes should always be added as new migration files54* Clear, descriptive names should be used for migration files to indicate their purpose5556## Squashing historical migrations5758Rare maintenance: collapse applied migrations into the baseline so the repo keeps only baseline + tip placeholder (+ any newer work after the next tip). **Do not squash casually.** Production (and other long-lived DBs) survive because startup always **`repair()`s before `migrate()`**.5960### Invariants6162* **Tip placeholder first.** Add a **new** no-op placeholder whose version is **greater than every migration you will delete**. Reusing an old placeholder that already sits behind later versions is wrong.63* **Deploy and confirm** that tip placeholder on production (and any other long-lived environments) before deleting files. Check `flyway_schema_history`.64* **Freeze** new schema migrations until the squash commit is deployed.65* **Keep the baseline version number** (`V100000000`). Replace **file contents only**. Renaming/renumbering the baseline makes Flyway treat it as a new pending migration and can run full `CREATE` DDL on an existing DB.66* **Dump at the tip.** Local schema must have applied through the new placeholder before dumping.67* **Delete SQL and Java** migrations strictly between baseline and the tip placeholder.68* Dump is **CREATE-only DDL, no data**; omit **`flyway_schema_history`** (match the header comment on the current baseline).6970### Procedure71721. Find the highest existing migration version (SQL under `resources/db/migration/` and Java under `java/db/migration/`).732. Add a no-op tip placeholder, e.g. `V{max+1}__db_migration_placeholder.sql`, with a short comment that future migrations must use a greater version.743. Commit, deploy, and confirm the placeholder row exists in production `flyway_schema_history`. Freeze further migrations.754. On a local DB migrated through that tip, dump the full schema (no data). Prefer the same shape as the current baseline (CREATE statements; no `flyway_schema_history`).765. Replace the **contents** of `V100000000__baseline.sql` with that dump (same filename/version). Delete every migration file (`.sql` and `.java`) with version **strictly between** baseline and the tip placeholder. Keep baseline + tip placeholder.776. Update this rule’s baseline/placeholder version references and the “greater than” example so they match the new tip.787. Commit, deploy the squash. Confirm startup succeeds and `flyway_schema_history` looks sane (baseline checksum repaired; deleted versions gone; tip still present).798. Regenerate **`docs/database-erd.md`** if the collapsed schema should be re-exported (see below).8081## Entity-relationship diagram8283After adding or changing schema migrations, regenerate **`docs/database-erd.md`** so the Mermaid ERD stays aligned with Flyway. Follow the **`database-erd`** skill (`.agents/skills/database-erd/SKILL.md`): run `CURSOR_DEV=true nix develop -c pnpm export:database-erd` (or `python3 scripts/export_database_erd.py`) against a migrated local MySQL schema.84
One repository carrying more than one format is the comparison this product exists for: does anyone actually write different content in each file, or is one a copy of the other?
| Repository | Format | Stack | Covers | Score | Changed |
|---|---|---|---|---|---|
| nerds-odd-e/doughnut.cursor/rules/general.mdc · 49 | Cursor rules | styledo-not | 49/100 | 14 days ago | |
| nerds-odd-e/doughnut.clinerules/daisyui.md · 49 | Cline rules | setuplint-formatstyleui+1 | 57/100 | 14 days ago | |
| nerds-odd-e/doughnut.cursor/rules/architecture-decisions.mdc · 49 | Cursor rules | no sections | 16/100 | 14 days ago | |
| nerds-odd-e/doughnut.cursor/rules/backend-code.mdc · 49 | Cursor rules | styletypesdatabasedo-not | 61/100 | 14 days ago | |
| nerds-odd-e/doughnut.cursor/rules/backend-testing.mdc · 49 | Cursor rules | buildteststyletesting-strategy+2 | 73/100 | 14 days ago | |
| nerds-odd-e/doughnut.cursor/rules/cli.mdc · 49 | Cursor rules | setupbuildteststyle+4 | 96/100 | 14 days ago | |
| nerds-odd-e/doughnut.cursor/rules/e2e-authoring.mdc · 49 | Cursor rules | setupteststylearch+3 | 80/100 | 14 days ago | |
| nerds-odd-e/doughnut.cursor/rules/e2e-ocr.mdc · 49 | Cursor rules | setuptesting-strategydo-not | 46/100 | 14 days ago | |
| nerds-odd-e/doughnut.cursor/rules/frontend-api.mdc · 49 | Cursor rules | styletesting-strategyapido-not | 57/100 | 14 days ago | |
| nerds-odd-e/doughnut.cursor/rules/frontend-component.mdc · 49 | Cursor rules | testlint-formatstylearch+2 | 76/100 | 14 days ago | |
| nerds-odd-e/doughnut.cursor/rules/frontend-storybook.mdc · 49 | Cursor rules | buildteststyletesting-strategy+1 | 69/100 | 14 days ago | |
| nerds-odd-e/doughnut.cursor/rules/frontend-testing.mdc · 49 | Cursor rules | buildteststyletesting-strategy+2 | 89/100 | 14 days ago | |
| nerds-odd-e/doughnut.cursor/rules/gsd-coexistence.mdc · 49 | Cursor rules | style | 60/100 | 14 days ago | |
| nerds-odd-e/doughnut.cursor/rules/linting_formating.mdc · 49 | Cursor rules | testlint-formatstylearch+6 | 88/100 | 14 days ago | |
| nerds-odd-e/doughnut.cursor/rules/mcp-server.mdc · 49 | Cursor rules | buildtestlint-formatarch+2 | 85/100 | 14 days ago | |
| nerds-odd-e/doughnut.cursor/rules/planning.mdc · 49 | Cursor rules | teststylearchdo-not+1 | 75/100 | 14 days ago | |
| nerds-odd-e/doughnut.cursor/rules/script.mdc · 49 | Cursor rules | testarch | 58/100 | 14 days ago | |
| nerds-odd-e/doughnutAGENTS.md · 49 | AGENTS.md | no sections | 47/100 | 14 days ago | |
| nerds-odd-e/doughnutCLAUDE.md · 49 | CLAUDE.md | agent-behaviour | 47/100 | 14 days ago |
Same format, overlapping stack, ranked by quality.
| Repository | Format | Stack | Covers | Score | Changed |
|---|---|---|---|---|---|
| hiromaily/go-crypto-wallet.cursor/rules/typescript.mdc · 126 | Cursor rules | setupbuildtestlint-format+6 | 100/100 | 14 days ago | |
| TechSquidTV/Hermes.cursor/rules/10-hermes-api.mdc · 46 | Cursor rules | testlint-formatstylearch+5 | 100/100 | 14 days ago | |
| dodgecfr/combatfilms-webapp.cursor/rules/frontend.mdc · 0 | Cursor rules | setuptestlint-formatstyle+7 | 99/100 | 14 days ago | |
| deifos/clipmira-subtitles.cursor/rules/frontend.mdc · 1 | Cursor rules | setuptestlint-formatstyle+7 | 99/100 | 14 days ago | |
| markstev/mark-starter.cursor/rules/frontend.mdc · 0 | Cursor rules | setuptestlint-formatstyle+6 | 99/100 | 14 days ago | |
| Allymahmoud/case-intake-platform.cursor/rules/frontend.mdc · 0 | Cursor rules | setuptestlint-formatstyle+7 | 99/100 | 14 days ago | |
| langflow-ai/langflow.cursor/rules/docs_development.mdc · 153k | Cursor rules | setupbuildtestlint-format+7 | 97/100 | 14 days ago | |
| TechSquidTV/Hermes.cursor/rules/20-hermes-api-tests.mdc · 46 | Cursor rules | teststyletesting-strategysecurity+3 | 97/100 | 14 days ago |
A badge carrying the measured quality of the strongest agent config file in this repository, out of 100. It reads from this index every time somebody loads your page, so it changes when the measurement changes and there is nothing to keep up to date. Free, no account, and the value is not something you or we can set by hand.
[](https://rulestack.kynth.studio/configs/nerds-odd-e-doughnut-cursor-rules-db-migration)Would rather not hotlink us? Every badge is also served in shields.io’s endpoint schema, so shields renders the image and your readers never talk to our domain:
Published by Toolproof, the masthead over this index and eight others. The method behind the number is at toolproof.kynth.studio/methodology, and the whole thing is readable as JSON with no key at /api.