fix(migrations): unblock the runner and make 0049 apply on MySQL - #1705
Merged
BHUVANSH855 merged 1 commit intoAug 29, 2026
Merged
Conversation
Three migrations landed claiming version 0049. loadMigrations throws while building the file list, before it compares anything against schema_migrations, so the failure is total: npm run migrate and even migrate:status refuse the whole directory rather than the three files. Nothing could be applied to any environment, and nothing in CI runs the runner, so main stayed green while the schema pipeline was fully blocked. Renumber by merge order. 0049 stays with coupons_schema, which merged first; product_search_fulltext becomes 0050 and fraud_monitoring_queue 0051. Renumbering is safe precisely because the collision meant none of the three could ever have been applied. 0049_coupons_schema.sql needed more than a number. It was a second CREATE TABLE IF NOT EXISTS for a table 0001_baseline_schema.sql already owns, which MySQL skips silently -- so the migration would have recorded itself as applied having changed nothing -- followed by ALTER TABLE ... ADD COLUMN IF NOT EXISTS, which is MariaDB syntax that MySQL 8 rejects with ERROR 1064 after the table was already created. Rewrite it as the ALTERs it should always have been: add the nullable expires_at that validateCoupon reads before falling back to the baseline's NOT NULL end_date, and widen the type enum to hold 'percent', which both validateCoupon and pricing.service.js accept and the admin form submits. Every enum member the baseline declared is kept, since dropping one rewrites the rows using it to ''. Add backend/tests/migrationSequence.test.js: no duplicate versions, every filename matching the runner's pattern, no MariaDB-only syntax, and no table created by more than one migration -- the rule migrations/README.md states and that a human has to remember at merge time.
🔍 Quality Gate Report✅ All quality gates passed!
|
|
Someone is attempting to deploy a commit to the Bhuvansh's projects Team on Vercel. A member of the Team first needs to authorize it. |
🤖 AI Code Review🔴 Score: 50/100 | AI review unavailable at this time. Automated AI review — a human maintainer will also review. |
|
💡 Suggested reviewers based on relevant file history: @Aditya8369, @Pcmhacker-hero |
BHUVANSH855
approved these changes
Aug 29, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #1700
What was wrong
Three migrations claimed version
0049.loadMigrationsthrows while building the file list, before it compares anything againstschema_migrations, so the failure is total:Not the three files — the whole directory. No schema change could be applied to any environment.
migrations/README.mdnames this hazard by name ("a collision takes the whole sequence down and not just the two files involved") and the three still merged, because each looked fine in isolation and in review. Nothing in CI runs the runner, somainstayed green.The renumber
By merge order, which is the only ordering that does not rewrite history someone might have applied:
0049_coupons_schema.sql0049_coupons_schema.sql0049_product_search_fulltext.sql0050_product_search_fulltext.sql0049_fraud_monitoring_queue.sql0051_fraud_monitoring_queue.sqlRenumbering is safe here precisely because of the collision: the runner refused the directory before it read
schema_migrations, so none of the three has ever been applied anywhere. Environments are migrated to0048.0049 needed more than a number
While writing the guard I found the coupons migration could not have worked even alone. It was:
The
CREATE TABLEwas a no-op.couponsis already declared in0001_baseline_schema.sql, and the baseline runs first on every database, fresh or adopted.CREATE TABLE IF NOT EXISTSagainst an existing table is skipped silently, so the migration would have recorded itself as applied having changed nothing. This is the exact case the README warns about:The
ALTERwas invalid.ADD COLUMN IF NOT EXISTSis a MariaDB extension; MySQL 8 answersERROR 1064. Sitting after theCREATE TABLE, it would have aborted the migration partway through — table present, version unrecorded — and the next run would then hit the "never edit an applied migration" checksum rule on the way past.So the file is now the ALTERs it should always have been, against the baseline's table:
ADD COLUMN expires_at DATETIME NULL—validateCouponreadscoupon.expires_at || coupon.end_date || coupon.expiry_date. The baseline'send_dateisNOT NULL, so without this a coupon that never expires cannot be expressed: every row has to name a date it stops working.MODIFY COLUMN type ENUM('percentage', 'percent', 'fixed', 'free_shipping')—'percent'is accepted as a synonym for'percentage'by bothvalidateCouponandpricing.service.js, and the admin coupon form submits it, so the column has to hold it. All three original members are kept: dropping one rewrites every row using it to''.expires_at, covering the expiry check the new column introduces.Plain ALTERs, not guarded ones — the runner applies each migration exactly once and records it, so nothing here needs to be idempotent.
Guard
backend/tests/migrationSequence.test.js, 65 cases:.sqlfilename matches the runner'sNNNN_name.sqlpattern (anything else is ignored and reported rather than applied).0001declares stored procedures and is not safe to re-run; a file numbered below it would be applied against no schema.ADD COLUMN IF NOT EXISTS,DROP COLUMN IF EXISTS,ADD INDEX IF NOT EXISTS,CREATE OR REPLACE TABLE. This class of bug fails at deploy time on a fresh database rather than in review.0049was breaking, now checked instead of remembered.coupons,fraud_monitoring_queue, the products full-text index) all still have an owner.It also turns two red suites green
The repository already had guards for this collision; both have been failing on
mainsince the third0049merged, and neither could be seen becausecheck:syntaxfails first and skips the test job on every PR:Both pass on this branch.
tests/migrationSequence.test.jsadds the checks those two do not make — the filename pattern, the MariaDB-only dialect scan, and the one-owning-migration-per-table rule.Verification
Confirmed the guard is real by restoring
main'smigrations/and re-running it:CI note — merge #1701 first
The Syntax check job fails on this branch, and it is not this change:
frontend/scripts/shop.jsis unparsable onmain— the responsive refactor duplicated and interleaved its initialization block. Every open PR against this repository inherits it, and becausecheck:syntaxis the first CI job and the other two are gated on it, Backend tests and Server boots are skipped rather than run. That is why this PR shows no test result.#1701 fixes it. Once that merges, this branch picks the fix up from
mainwith no rebase needed — the two touch no file in common. All gates pass locally on this branch's changes:and I verified the whole set merges cleanly by merging all five of these branches together locally: no conflicts,
check:syntaxgreen at 659 files, and the full Jest suite at 2976 passing.The
Vercelcheck fails on every PR in this repository with "Authorization required to deploy" against thebhuvanshs-projectsteam, unrelated to any change.