From b48cb1c48c7339a294efdfdaee102b4a9d650729 Mon Sep 17 00:00:00 2001 From: Catherine Renelle <32781029+catrenelle@users.noreply.github.com> Date: Mon, 9 Feb 2026 20:56:26 -0500 Subject: [PATCH] Mark existing bank-synced transactions as Cleared on startup One-time migration: UPDATE all transactions that have a FitId (bank-synced) and Status=Uncleared to Status=Cleared. Tracked in data_migrations table so it only runs once. Co-Authored-By: Claude Opus 4.6 --- src/Purrse.Api/Program.cs | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/Purrse.Api/Program.cs b/src/Purrse.Api/Program.cs index e5fa423..a3fb05c 100644 --- a/src/Purrse.Api/Program.cs +++ b/src/Purrse.Api/Program.cs @@ -119,8 +119,25 @@ using (var scope = app.Services.CreateScope()) await db.Database.MigrateAsync(); } -// One-time data migration: split SimpleFIN connections by institution +// One-time data migrations await SimpleFinConnectionMigration.RunAsync(app.Services, app.Services.GetRequiredService>()); +using (var scope = app.Services.CreateScope()) +{ + var db = scope.ServiceProvider.GetRequiredService(); + await db.Database.ExecuteSqlRawAsync( + "CREATE TABLE IF NOT EXISTS data_migrations (name TEXT PRIMARY KEY, applied_at TIMESTAMP NOT NULL)"); + var applied = await db.Database.SqlQueryRaw( + "SELECT 1 AS \"Value\" FROM data_migrations WHERE name = 'ClearSyncedTransactions'").AnyAsync(); + if (!applied) + { + var count = await db.Database.ExecuteSqlRawAsync( + "UPDATE \"Transactions\" SET \"Status\" = 1 WHERE \"FitId\" IS NOT NULL AND \"Status\" = 0"); + if (count > 0) + app.Services.GetRequiredService>().LogInformation("Marked {Count} bank-synced transactions as Cleared", count); + await db.Database.ExecuteSqlRawAsync( + "INSERT INTO data_migrations (name, applied_at) VALUES ('ClearSyncedTransactions', NOW()) ON CONFLICT DO NOTHING"); + } +} // Initialize plugin system var pluginService = app.Services.GetRequiredService();