Skip to content

Migration AddRefreshTokenReplacedBy missing Designer.cs (Postgres + SQLite) — silently skipped by EF #203

@davidortinau

Description

@davidortinau

Summary

Migration 20260503221947_AddRefreshTokenReplacedBy is missing its .Designer.cs companion in both src/SentenceStudio.Shared/Migrations/ (Postgres) and src/SentenceStudio.Shared/Migrations/Sqlite/ folders. EF Core discovers migrations via the [Migration("…")] attribute that the Designer file carries — so without it, MigrateAsync silently skips this migration. The next migration's ApplicationDbContextModelSnapshot.cs already reflects the new column, masking the gap.

Symptom

  • Azure Postgres prod DB: __EFMigrationsHistory was missing this row; RefreshTokens had no ReplacedByToken column.
  • /api/auth/refresh threw Npgsql.PostgresException 42703: column r.ReplacedByToken does not exist (line 212 of AuthEndpoints.cs).
  • Cascade: AI calls returned 401 → ClozureService deserialized empty response → Cloze page showed "No cloze sentences available" toast. (Also affects every other AI-backed activity once the access token expires.)

Affects

  • Production Postgres: hot-patched 2026-05-09 via direct ALTER TABLE + INSERT into __EFMigrationsHistory. No further action needed for this DB.
  • Future fresh deploys (any new Postgres DB): migration will still silently skip; NumbersActivityPhase1 will run on top, leaving ReplacedByToken column missing.
  • Mobile SQLite: new app installs that bootstrap from migrations are likely affected too. Existing devices with a populated DB are fine because their schema predates the gap.

Files

src/SentenceStudio.Shared/Migrations/20260503221947_AddRefreshTokenReplacedBy.cs           ← exists
src/SentenceStudio.Shared/Migrations/20260503221947_AddRefreshTokenReplacedBy.Designer.cs  ← MISSING
src/SentenceStudio.Shared/Migrations/Sqlite/20260503221947_AddRefreshTokenReplacedBy.cs           ← exists
src/SentenceStudio.Shared/Migrations/Sqlite/20260503221947_AddRefreshTokenReplacedBy.Designer.cs  ← MISSING

Fix

Regenerate via dotnet ef:

  1. Remove the broken migration (won't roll back the schema since it never applied to Postgres prod via EF; the column was added manually).
  2. Re-add it via dotnet ef migrations add AddRefreshTokenReplacedBy … — generates both .cs and .Designer.cs.
  3. Repeat for the SQLite provider — see .squad/skills/ef-dual-provider-migrations/SKILL.md.
  4. Run scripts/validate-mobile-migrations.sh.
  5. Verify the resulting migration is a no-op against current model snapshots (i.e., Up/Down only add/drop the column).
  6. Confirm __EFMigrationsHistory row in prod (already inserted manually) matches the new MigrationId. If dotnet ef regenerates with a different timestamp, the prod row needs to be updated.

Workaround applied (reference only)

BEGIN;
ALTER TABLE "RefreshTokens" ADD COLUMN IF NOT EXISTS "ReplacedByToken" text NULL;
INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion")
VALUES ('20260503221947_AddRefreshTokenReplacedBy', '10.0.7')
ON CONFLICT ("MigrationId") DO NOTHING;
COMMIT;

Related

  • Original migration commit: 0014a84c fix(auth): make login persist across restart + install (single-flight refresh, 24h JWT, grace window)
  • Skill reference: .squad/skills/ef-dual-provider-migrations/SKILL.md — dual-provider workflow that should have caught this.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions