refactor(db): migrate application checklist

Move workflow checklist state into an additive provider-aware migration. Preserve system-key idempotency, manual progress, ordering, and application cascade semantics.
This commit is contained in:
cesnimda
2026-08-30 18:52:08 +02:00
parent ae57d1afde
commit e933409698
9 changed files with 165 additions and 63 deletions
@@ -712,34 +712,6 @@ public static class StartupInitializationExtensions
EnsureColumn(c, "AiInteractions", "EstimatedTokenCount", "ALTER TABLE AiInteractions ADD COLUMN EstimatedTokenCount INTEGER NOT NULL DEFAULT 0;");
}
// Phase 5 Milestone 2: the application checklist (workflow guidance over readiness signals).
static void EnsureApplicationChecklistTable(DbConnection c)
{
Exec(c, """
CREATE TABLE IF NOT EXISTS "ApplicationChecklistItems" (
"Id" INTEGER NOT NULL CONSTRAINT "PK_ApplicationChecklistItems" PRIMARY KEY AUTOINCREMENT,
"OwnerUserId" TEXT NOT NULL,
"JobApplicationId" INTEGER NOT NULL,
"SystemKey" TEXT NULL,
"AutoSignal" TEXT NULL,
"Title" TEXT NOT NULL,
"Description" TEXT NULL,
"Category" TEXT NOT NULL,
"Status" TEXT NOT NULL,
"Section" TEXT NULL,
"SortOrder" INTEGER NOT NULL,
"IsSystemGenerated" INTEGER NOT NULL,
"IsAutoCompleted" INTEGER NOT NULL,
"CompletedAt" TEXT NULL,
"CreatedAtUtc" TEXT NOT NULL,
"UpdatedAtUtc" TEXT NOT NULL,
CONSTRAINT "FK_ApplicationChecklistItems_JobApplications_JobApplicationId" FOREIGN KEY ("JobApplicationId") REFERENCES "JobApplications" ("Id") ON DELETE CASCADE
);
""");
Exec(c, """CREATE UNIQUE INDEX IF NOT EXISTS "IX_ApplicationChecklistItems_JobApplicationId_SystemKey" ON "ApplicationChecklistItems" ("JobApplicationId", "SystemKey");""");
Exec(c, """CREATE INDEX IF NOT EXISTS "IX_ApplicationChecklistItems_Owner_Job_Sort" ON "ApplicationChecklistItems" ("OwnerUserId", "JobApplicationId", "SortOrder");""");
}
// Phase 5.4: append-only cover letter history.
static void EnsureCoverLetterVersionsTable(DbConnection c)
{
@@ -784,7 +756,6 @@ public static class StartupInitializationExtensions
ReconcileGmailConnectionColumns(conn);
EnsureCareerProfileTables(conn);
ReconcileAiInteractionUsageColumns(conn);
EnsureApplicationChecklistTable(conn);
EnsureCoverLetterVersionsTable(conn);
EnsureInterviewPrepItemsTable(conn);
@@ -1180,32 +1151,6 @@ public static class StartupInitializationExtensions
DropMalformedMySqlTable(conn, "CoverLetterVersions", "CreatedAtUtc", "datetime");
DropMalformedMySqlTable(conn, "InterviewPrepItems", "CreatedAtUtc", "datetime");
if (!HasMySqlTable(conn, "ApplicationChecklistItems") && HasMySqlTable(conn, "JobApplications"))
{
using var cmd = conn.CreateCommand();
cmd.CommandText = @"CREATE TABLE IF NOT EXISTS `ApplicationChecklistItems` (
`Id` int NOT NULL AUTO_INCREMENT,
`OwnerUserId` varchar(255) NOT NULL,
`JobApplicationId` int NOT NULL,
`SystemKey` varchar(64) NULL,
`AutoSignal` varchar(64) NULL,
`Title` varchar(255) NOT NULL,
`Description` longtext NULL,
`Category` varchar(32) NOT NULL,
`Status` varchar(32) NOT NULL,
`Section` varchar(64) NULL,
`SortOrder` int NOT NULL,
`IsSystemGenerated` tinyint(1) NOT NULL,
`IsAutoCompleted` tinyint(1) NOT NULL,
`CompletedAt` datetime(6) NULL,
`CreatedAtUtc` datetime(6) NOT NULL,
`UpdatedAtUtc` datetime(6) NOT NULL,
PRIMARY KEY (`Id`),
CONSTRAINT `FK_ApplicationChecklistItems_JobApplications_JobApplicationId` FOREIGN KEY (`JobApplicationId`) REFERENCES `JobApplications` (`Id`) ON DELETE CASCADE
);";
cmd.ExecuteNonQuery();
}
if (!HasMySqlTable(conn, "CoverLetterVersions") && HasMySqlTable(conn, "JobApplications"))
{
using var cmd = conn.CreateCommand();
@@ -14,6 +14,7 @@ internal static class StartupSchemaOwnership
"AiUsageRecords",
"AiWorkspaceNotes",
"AiInteractions",
"ApplicationChecklistItems",
"Attachments",
"Companies",
"Correspondences",
@@ -44,7 +45,6 @@ internal static class StartupSchemaOwnership
internal static readonly IReadOnlySet<string> ReconcilerOwnedTables = new HashSet<string>(StringComparer.Ordinal)
{
"ApplicationChecklistItems",
"AspNetRoleClaims",
"AspNetRoles",
"AspNetUserClaims",