diff --git a/JobTrackerApi/JobTrackerApi.csproj b/JobTrackerApi/JobTrackerApi.csproj
index feaf612..828a1c3 100644
--- a/JobTrackerApi/JobTrackerApi.csproj
+++ b/JobTrackerApi/JobTrackerApi.csproj
@@ -13,6 +13,12 @@
+
+
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+ all
+
diff --git a/JobTrackerApi/Migrations/20260711181039_SyncModelSnapshot.Designer.cs b/JobTrackerApi/Migrations/20260711181039_SyncModelSnapshot.Designer.cs
new file mode 100644
index 0000000..074b483
--- /dev/null
+++ b/JobTrackerApi/Migrations/20260711181039_SyncModelSnapshot.Designer.cs
@@ -0,0 +1,1170 @@
+//
+using System;
+using JobTrackerApi.Data;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+
+#nullable disable
+
+namespace JobTrackerApi.Migrations
+{
+ [DbContext(typeof(JobTrackerContext))]
+ [Migration("20260711181039_SyncModelSnapshot")]
+ partial class SyncModelSnapshot
+ {
+ ///
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder.HasAnnotation("ProductVersion", "9.0.14");
+
+ modelBuilder.Entity("JobTrackerApi.Models.ApplicationUser", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("TEXT");
+
+ b.Property("AccessFailedCount")
+ .HasColumnType("INTEGER");
+
+ b.Property("AvatarImageDataUrl")
+ .HasColumnType("TEXT");
+
+ b.Property("ConcurrencyStamp")
+ .IsConcurrencyToken()
+ .HasColumnType("TEXT");
+
+ b.Property("CurrentCvExtractionRunId")
+ .HasColumnType("INTEGER");
+
+ b.Property("CurrentCvProfileVersion")
+ .HasColumnType("INTEGER");
+
+ b.Property("CurrentCvUploadArtifactId")
+ .HasColumnType("INTEGER");
+
+ b.Property("DisplayName")
+ .HasColumnType("TEXT");
+
+ b.Property("Email")
+ .HasMaxLength(256)
+ .HasColumnType("TEXT");
+
+ b.Property("EmailConfirmed")
+ .HasColumnType("INTEGER");
+
+ b.Property("FirstName")
+ .HasColumnType("TEXT");
+
+ b.Property("GoogleEmail")
+ .HasColumnType("TEXT");
+
+ b.Property("GoogleLinkedAt")
+ .HasColumnType("TEXT");
+
+ b.Property("GoogleSubject")
+ .HasColumnType("TEXT");
+
+ b.Property("LastName")
+ .HasColumnType("TEXT");
+
+ b.Property("LockoutEnabled")
+ .HasColumnType("INTEGER");
+
+ b.Property("LockoutEnd")
+ .HasColumnType("TEXT");
+
+ b.Property("NormalizedEmail")
+ .HasMaxLength(256)
+ .HasColumnType("TEXT");
+
+ b.Property("NormalizedUserName")
+ .HasMaxLength(256)
+ .HasColumnType("TEXT");
+
+ b.Property("PasswordHash")
+ .HasColumnType("TEXT");
+
+ b.Property("PhoneNumber")
+ .HasColumnType("TEXT");
+
+ b.Property("PhoneNumberConfirmed")
+ .HasColumnType("INTEGER");
+
+ b.Property("ProfileCvStructureJson")
+ .HasColumnType("TEXT");
+
+ b.Property("ProfileCvText")
+ .HasColumnType("TEXT");
+
+ b.Property("SecurityStamp")
+ .HasColumnType("TEXT");
+
+ b.Property("TwoFactorEnabled")
+ .HasColumnType("INTEGER");
+
+ b.Property("UserName")
+ .HasMaxLength(256)
+ .HasColumnType("TEXT");
+
+ b.HasKey("Id");
+
+ b.HasIndex("NormalizedEmail")
+ .HasDatabaseName("EmailIndex");
+
+ b.HasIndex("NormalizedUserName")
+ .IsUnique()
+ .HasDatabaseName("UserNameIndex");
+
+ b.ToTable("AspNetUsers", (string)null);
+ });
+
+ modelBuilder.Entity("JobTrackerApi.Models.Attachment", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property("FileName")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.Property("FilePath")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.Property("FileSize")
+ .HasColumnType("INTEGER");
+
+ b.Property("FileType")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.Property("JobApplicationId")
+ .HasColumnType("INTEGER");
+
+ b.Property("Purpose")
+ .HasColumnType("TEXT");
+
+ b.Property("UploadDate")
+ .HasColumnType("TEXT");
+
+ b.Property("UseForAi")
+ .HasColumnType("INTEGER");
+
+ b.HasKey("Id");
+
+ b.HasIndex("JobApplicationId");
+
+ b.ToTable("Attachments");
+ });
+
+ modelBuilder.Entity("JobTrackerApi.Models.Company", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property("LastContactedAt")
+ .HasColumnType("TEXT");
+
+ b.Property("Location")
+ .HasColumnType("TEXT");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.Property("NextContactAt")
+ .HasColumnType("TEXT");
+
+ b.Property("OwnerUserId")
+ .HasColumnType("TEXT");
+
+ b.Property("PipelineStage")
+ .HasColumnType("TEXT");
+
+ b.Property("RecruiterEmail")
+ .HasColumnType("TEXT");
+
+ b.Property("RecruiterLinkedIn")
+ .HasColumnType("TEXT");
+
+ b.Property("RecruiterName")
+ .HasColumnType("TEXT");
+
+ b.Property("Source")
+ .HasColumnType("TEXT");
+
+ b.HasKey("Id");
+
+ b.HasIndex("OwnerUserId");
+
+ b.ToTable("Companies");
+ });
+
+ modelBuilder.Entity("JobTrackerApi.Models.Correspondence", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property("AttachmentMetadataJson")
+ .HasColumnType("TEXT");
+
+ b.Property("Channel")
+ .HasColumnType("TEXT");
+
+ b.Property("Content")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.Property("Date")
+ .HasColumnType("TEXT");
+
+ b.Property("Direction")
+ .HasColumnType("TEXT");
+
+ b.Property("ExternalFrom")
+ .HasColumnType("TEXT");
+
+ b.Property("ExternalLabelsJson")
+ .HasColumnType("TEXT");
+
+ b.Property("ExternalMessageId")
+ .HasColumnType("TEXT");
+
+ b.Property("ExternalThreadId")
+ .HasColumnType("TEXT");
+
+ b.Property("ExternalTo")
+ .HasColumnType("TEXT");
+
+ b.Property("From")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.Property("JobApplicationId")
+ .HasColumnType("INTEGER");
+
+ b.Property("Provider")
+ .HasColumnType("TEXT");
+
+ b.Property("Subject")
+ .HasColumnType("TEXT");
+
+ b.HasKey("Id");
+
+ b.HasIndex("JobApplicationId");
+
+ b.ToTable("Correspondences");
+ });
+
+ modelBuilder.Entity("JobTrackerApi.Models.CvExtractionRun", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property("AppliedAtUtc")
+ .HasColumnType("TEXT");
+
+ b.Property("ArtifactId")
+ .HasColumnType("INTEGER");
+
+ b.Property("CompletedAtUtc")
+ .HasColumnType("TEXT");
+
+ b.Property("ErrorMessage")
+ .HasColumnType("TEXT");
+
+ b.Property("LlmPromptVersion")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.Property("NormalizedText")
+ .HasColumnType("TEXT");
+
+ b.Property("NormalizerVersion")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.Property("OwnerUserId")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.Property("ParserVersion")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.Property("RawExtractedText")
+ .HasColumnType("TEXT");
+
+ b.Property("StartedAtUtc")
+ .HasColumnType("TEXT");
+
+ b.Property("Status")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.Property("StructuredProfileJson")
+ .HasColumnType("TEXT");
+
+ b.Property("Trigger")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.HasKey("Id");
+
+ b.HasIndex("ArtifactId");
+
+ b.HasIndex("OwnerUserId", "StartedAtUtc");
+
+ b.ToTable("CvExtractionRuns");
+ });
+
+ modelBuilder.Entity("JobTrackerApi.Models.CvUploadArtifact", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property("ByteSize")
+ .HasColumnType("INTEGER");
+
+ b.Property("MimeType")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.Property("OriginalFileName")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.Property("OwnerUserId")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.Property("Sha256")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.Property("StoragePath")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.Property("StoredFileName")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.Property("UploadedAtUtc")
+ .HasColumnType("TEXT");
+
+ b.HasKey("Id");
+
+ b.HasIndex("OwnerUserId", "UploadedAtUtc");
+
+ b.ToTable("CvUploadArtifacts");
+ });
+
+ modelBuilder.Entity("JobTrackerApi.Models.GmailConnection", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property("AccessTokenExpiresAt")
+ .HasColumnType("TEXT");
+
+ b.Property("ConnectedAt")
+ .HasColumnType("TEXT");
+
+ b.Property("EncryptedAccessToken")
+ .HasColumnType("TEXT");
+
+ b.Property("EncryptedRefreshToken")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.Property("GmailAddress")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.Property("LastSyncAttemptedAt")
+ .HasColumnType("TEXT");
+
+ b.Property("LastSyncError")
+ .HasColumnType("TEXT");
+
+ b.Property("LastSyncMode")
+ .HasColumnType("TEXT");
+
+ b.Property("LastSyncSource")
+ .HasColumnType("TEXT");
+
+ b.Property("LastSyncStatus")
+ .HasColumnType("TEXT");
+
+ b.Property("LastSyncSucceededAt")
+ .HasColumnType("TEXT");
+
+ b.Property("LastSyncedAt")
+ .HasColumnType("TEXT");
+
+ b.Property("OwnerUserId")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.Property("Scope")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.HasKey("Id");
+
+ b.HasIndex("OwnerUserId");
+
+ b.HasIndex("OwnerUserId", "GmailAddress")
+ .IsUnique();
+
+ b.ToTable("GmailConnections");
+ });
+
+ modelBuilder.Entity("JobTrackerApi.Models.GmailReviewDecision", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property("Decision")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.Property("JobApplicationId")
+ .HasColumnType("INTEGER");
+
+ b.Property("Note")
+ .HasColumnType("TEXT");
+
+ b.Property("OwnerUserId")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.Property("ThreadId")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.Property("UpdatedAt")
+ .HasColumnType("TEXT");
+
+ b.HasKey("Id");
+
+ b.ToTable("GmailReviewDecisions");
+ });
+
+ modelBuilder.Entity("JobTrackerApi.Models.ImapConnection", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property("ConnectedAt")
+ .HasColumnType("TEXT");
+
+ b.Property("EncryptedPassword")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.Property("Host")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.Property("LastSyncAttemptedAt")
+ .HasColumnType("TEXT");
+
+ b.Property("LastSyncError")
+ .HasColumnType("TEXT");
+
+ b.Property("LastSyncMode")
+ .HasColumnType("TEXT");
+
+ b.Property("LastSyncSource")
+ .HasColumnType("TEXT");
+
+ b.Property("LastSyncStatus")
+ .HasColumnType("TEXT");
+
+ b.Property("LastSyncSucceededAt")
+ .HasColumnType("TEXT");
+
+ b.Property("LastSyncedAt")
+ .HasColumnType("TEXT");
+
+ b.Property("OwnerUserId")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.Property("Port")
+ .HasColumnType("INTEGER");
+
+ b.Property("UseSsl")
+ .HasColumnType("INTEGER");
+
+ b.Property("Username")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.HasKey("Id");
+
+ b.ToTable("ImapConnections");
+ });
+
+ modelBuilder.Entity("JobTrackerApi.Models.JobApplication", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property("CompanyId")
+ .HasColumnType("INTEGER");
+
+ b.Property("CoverLetterText")
+ .HasColumnType("TEXT");
+
+ b.Property("DateApplied")
+ .HasColumnType("TEXT");
+
+ b.Property("Deadline")
+ .HasColumnType("TEXT");
+
+ b.Property("DeletedAt")
+ .HasColumnType("TEXT");
+
+ b.Property("Description")
+ .HasColumnType("TEXT");
+
+ b.Property("DescriptionLanguage")
+ .HasColumnType("TEXT");
+
+ b.Property("FeedbackRequestedAt")
+ .HasColumnType("TEXT");
+
+ b.Property("FollowUpAt")
+ .HasColumnType("TEXT");
+
+ b.Property("HasCoverLetter")
+ .HasColumnType("INTEGER");
+
+ b.Property("HasOtherAttachment")
+ .HasColumnType("INTEGER");
+
+ b.Property("HasPortfolio")
+ .HasColumnType("INTEGER");
+
+ b.Property("HasResume")
+ .HasColumnType("INTEGER");
+
+ b.Property("IsDeleted")
+ .HasColumnType("INTEGER");
+
+ b.Property("JobTitle")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.Property("JobUrl")
+ .HasColumnType("TEXT");
+
+ b.Property("LastReminderEmailSentAt")
+ .HasColumnType("TEXT");
+
+ b.Property("Location")
+ .HasColumnType("TEXT");
+
+ b.Property("NextAction")
+ .HasColumnType("TEXT");
+
+ b.Property("Notes")
+ .HasColumnType("TEXT");
+
+ b.Property("OwnerUserId")
+ .HasColumnType("TEXT");
+
+ b.Property("RecruiterMessageDraft")
+ .HasColumnType("TEXT");
+
+ b.Property("ResponseDate")
+ .HasColumnType("TEXT");
+
+ b.Property("ResponseReceived")
+ .HasColumnType("INTEGER");
+
+ b.Property("Salary")
+ .HasColumnType("TEXT");
+
+ b.Property("SalaryCurrency")
+ .HasColumnType("TEXT");
+
+ b.Property("SalaryMax")
+ .HasColumnType("TEXT");
+
+ b.Property("SalaryMin")
+ .HasColumnType("TEXT");
+
+ b.Property("SalaryPeriod")
+ .HasColumnType("TEXT");
+
+ b.Property("ShortSummary")
+ .HasColumnType("TEXT");
+
+ b.Property("Status")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.Property("Tags")
+ .HasColumnType("TEXT");
+
+ b.Property("TailoredCvText")
+ .HasColumnType("TEXT");
+
+ b.Property("TailoredCvUpdatedAt")
+ .HasColumnType("TEXT");
+
+ b.Property("TranslatedDescription")
+ .HasColumnType("TEXT");
+
+ b.HasKey("Id");
+
+ b.HasIndex("CompanyId");
+
+ b.HasIndex("OwnerUserId");
+
+ b.HasIndex("OwnerUserId", "FollowUpAt");
+
+ b.HasIndex("OwnerUserId", "IsDeleted");
+
+ b.ToTable("JobApplications");
+ });
+
+ modelBuilder.Entity("JobTrackerApi.Models.JobEvent", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property("At")
+ .HasColumnType("TEXT");
+
+ b.Property("JobApplicationId")
+ .HasColumnType("INTEGER");
+
+ b.Property("NewValue")
+ .HasColumnType("TEXT");
+
+ b.Property("Note")
+ .HasColumnType("TEXT");
+
+ b.Property("OldValue")
+ .HasColumnType("TEXT");
+
+ b.Property("Type")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.HasKey("Id");
+
+ b.HasIndex("JobApplicationId");
+
+ b.ToTable("JobEvents");
+ });
+
+ modelBuilder.Entity("JobTrackerApi.Models.MicrosoftGraphConnection", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property("AccessTokenExpiresAt")
+ .HasColumnType("TEXT");
+
+ b.Property("ConnectedAt")
+ .HasColumnType("TEXT");
+
+ b.Property("EncryptedAccessToken")
+ .HasColumnType("TEXT");
+
+ b.Property("EncryptedRefreshToken")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.Property("LastSyncAttemptedAt")
+ .HasColumnType("TEXT");
+
+ b.Property("LastSyncError")
+ .HasColumnType("TEXT");
+
+ b.Property("LastSyncMode")
+ .HasColumnType("TEXT");
+
+ b.Property("LastSyncSource")
+ .HasColumnType("TEXT");
+
+ b.Property("LastSyncStatus")
+ .HasColumnType("TEXT");
+
+ b.Property("LastSyncSucceededAt")
+ .HasColumnType("TEXT");
+
+ b.Property("LastSyncedAt")
+ .HasColumnType("TEXT");
+
+ b.Property("MailAddress")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.Property("OwnerUserId")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.Property("Scope")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.HasKey("Id");
+
+ b.ToTable("MicrosoftGraphConnections");
+ });
+
+ modelBuilder.Entity("JobTrackerApi.Models.RuleSettings", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property("AppliedFollowUpDays")
+ .HasColumnType("INTEGER");
+
+ b.Property("AppliedGhostDays")
+ .HasColumnType("INTEGER");
+
+ b.Property("FeedbackFollowUpDays")
+ .HasColumnType("INTEGER");
+
+ b.Property("FeedbackGhostDays")
+ .HasColumnType("INTEGER");
+
+ b.Property("OfferFollowUpDays")
+ .HasColumnType("INTEGER");
+
+ b.Property("OfferGhostDays")
+ .HasColumnType("INTEGER");
+
+ b.HasKey("Id");
+
+ b.ToTable("RuleSettings");
+
+ b.HasData(
+ new
+ {
+ Id = 1,
+ AppliedFollowUpDays = 14,
+ AppliedGhostDays = 30,
+ FeedbackFollowUpDays = 7,
+ FeedbackGhostDays = 14,
+ OfferFollowUpDays = 7,
+ OfferGhostDays = 14
+ });
+ });
+
+ modelBuilder.Entity("JobTrackerApi.Models.SystemEmailSettings", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property("Enabled")
+ .HasColumnType("INTEGER");
+
+ b.Property("From")
+ .HasColumnType("TEXT");
+
+ b.Property("FromName")
+ .HasColumnType("TEXT");
+
+ b.Property("SmtpEnableSsl")
+ .HasColumnType("INTEGER");
+
+ b.Property("SmtpHost")
+ .HasColumnType("TEXT");
+
+ b.Property("SmtpPassword")
+ .HasColumnType("TEXT");
+
+ b.Property("SmtpPort")
+ .HasColumnType("INTEGER");
+
+ b.Property("SmtpTimeoutMs")
+ .HasColumnType("INTEGER");
+
+ b.Property("SmtpUser")
+ .HasColumnType("TEXT");
+
+ b.HasKey("Id");
+
+ b.ToTable("SystemEmailSettings");
+ });
+
+ modelBuilder.Entity("JobTrackerApi.Models.TailoredCvDraft", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property("CanonicalProfileVersion")
+ .HasColumnType("INTEGER");
+
+ b.Property("CustomSectionsJson")
+ .HasColumnType("TEXT");
+
+ b.Property("EducationJson")
+ .HasColumnType("TEXT");
+
+ b.Property("ExperienceJson")
+ .HasColumnType("TEXT");
+
+ b.Property("GenerationContextHash")
+ .HasColumnType("TEXT");
+
+ b.Property("Headline")
+ .HasColumnType("TEXT");
+
+ b.Property("JobApplicationId")
+ .HasColumnType("INTEGER");
+
+ b.Property("LastEditedAtUtc")
+ .HasColumnType("TEXT");
+
+ b.Property("LastGeneratedAtUtc")
+ .HasColumnType("TEXT");
+
+ b.Property("OwnerUserId")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.Property("RenderOptionsJson")
+ .HasColumnType("TEXT");
+
+ b.Property("SelectedSkillsJson")
+ .HasColumnType("TEXT");
+
+ b.Property("Status")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.Property("SummaryJson")
+ .HasColumnType("TEXT");
+
+ b.Property("TemplateId")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.HasKey("Id");
+
+ b.HasIndex("JobApplicationId")
+ .IsUnique();
+
+ b.HasIndex("OwnerUserId", "JobApplicationId")
+ .IsUnique();
+
+ b.ToTable("TailoredCvDrafts");
+ });
+
+ modelBuilder.Entity("JobTrackerApi.Models.UserRuleSettings", b =>
+ {
+ b.Property("OwnerUserId")
+ .HasColumnType("TEXT");
+
+ b.Property("AppliedFollowUpDays")
+ .HasColumnType("INTEGER");
+
+ b.Property("AppliedGhostDays")
+ .HasColumnType("INTEGER");
+
+ b.Property("FeedbackFollowUpDays")
+ .HasColumnType("INTEGER");
+
+ b.Property("FeedbackGhostDays")
+ .HasColumnType("INTEGER");
+
+ b.Property("OfferFollowUpDays")
+ .HasColumnType("INTEGER");
+
+ b.Property("OfferGhostDays")
+ .HasColumnType("INTEGER");
+
+ b.HasKey("OwnerUserId");
+
+ b.ToTable("UserRuleSettings");
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("TEXT");
+
+ b.Property("ConcurrencyStamp")
+ .IsConcurrencyToken()
+ .HasColumnType("TEXT");
+
+ b.Property("Name")
+ .HasMaxLength(256)
+ .HasColumnType("TEXT");
+
+ b.Property("NormalizedName")
+ .HasMaxLength(256)
+ .HasColumnType("TEXT");
+
+ b.HasKey("Id");
+
+ b.HasIndex("NormalizedName")
+ .IsUnique()
+ .HasDatabaseName("RoleNameIndex");
+
+ b.ToTable("AspNetRoles", (string)null);
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property("ClaimType")
+ .HasColumnType("TEXT");
+
+ b.Property("ClaimValue")
+ .HasColumnType("TEXT");
+
+ b.Property("RoleId")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.HasKey("Id");
+
+ b.HasIndex("RoleId");
+
+ b.ToTable("AspNetRoleClaims", (string)null);
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property("ClaimType")
+ .HasColumnType("TEXT");
+
+ b.Property("ClaimValue")
+ .HasColumnType("TEXT");
+
+ b.Property("UserId")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.HasKey("Id");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("AspNetUserClaims", (string)null);
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b =>
+ {
+ b.Property("LoginProvider")
+ .HasColumnType("TEXT");
+
+ b.Property("ProviderKey")
+ .HasColumnType("TEXT");
+
+ b.Property("ProviderDisplayName")
+ .HasColumnType("TEXT");
+
+ b.Property("UserId")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.HasKey("LoginProvider", "ProviderKey");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("AspNetUserLogins", (string)null);
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b =>
+ {
+ b.Property("UserId")
+ .HasColumnType("TEXT");
+
+ b.Property("RoleId")
+ .HasColumnType("TEXT");
+
+ b.HasKey("UserId", "RoleId");
+
+ b.HasIndex("RoleId");
+
+ b.ToTable("AspNetUserRoles", (string)null);
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b =>
+ {
+ b.Property("UserId")
+ .HasColumnType("TEXT");
+
+ b.Property("LoginProvider")
+ .HasColumnType("TEXT");
+
+ b.Property("Name")
+ .HasColumnType("TEXT");
+
+ b.Property("Value")
+ .HasColumnType("TEXT");
+
+ b.HasKey("UserId", "LoginProvider", "Name");
+
+ b.ToTable("AspNetUserTokens", (string)null);
+ });
+
+ modelBuilder.Entity("JobTrackerApi.Models.Attachment", b =>
+ {
+ b.HasOne("JobTrackerApi.Models.JobApplication", "JobApplication")
+ .WithMany("Attachments")
+ .HasForeignKey("JobApplicationId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("JobApplication");
+ });
+
+ modelBuilder.Entity("JobTrackerApi.Models.Correspondence", b =>
+ {
+ b.HasOne("JobTrackerApi.Models.JobApplication", "JobApplication")
+ .WithMany("Messages")
+ .HasForeignKey("JobApplicationId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("JobApplication");
+ });
+
+ modelBuilder.Entity("JobTrackerApi.Models.CvExtractionRun", b =>
+ {
+ b.HasOne("JobTrackerApi.Models.CvUploadArtifact", "Artifact")
+ .WithMany()
+ .HasForeignKey("ArtifactId")
+ .OnDelete(DeleteBehavior.SetNull);
+
+ b.Navigation("Artifact");
+ });
+
+ modelBuilder.Entity("JobTrackerApi.Models.JobApplication", b =>
+ {
+ b.HasOne("JobTrackerApi.Models.Company", "Company")
+ .WithMany("Jobs")
+ .HasForeignKey("CompanyId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("Company");
+ });
+
+ modelBuilder.Entity("JobTrackerApi.Models.JobEvent", b =>
+ {
+ b.HasOne("JobTrackerApi.Models.JobApplication", "JobApplication")
+ .WithMany("Events")
+ .HasForeignKey("JobApplicationId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("JobApplication");
+ });
+
+ modelBuilder.Entity("JobTrackerApi.Models.TailoredCvDraft", b =>
+ {
+ b.HasOne("JobTrackerApi.Models.JobApplication", "JobApplication")
+ .WithOne("TailoredCvDraft")
+ .HasForeignKey("JobTrackerApi.Models.TailoredCvDraft", "JobApplicationId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("JobApplication");
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b =>
+ {
+ b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
+ .WithMany()
+ .HasForeignKey("RoleId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b =>
+ {
+ b.HasOne("JobTrackerApi.Models.ApplicationUser", null)
+ .WithMany()
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b =>
+ {
+ b.HasOne("JobTrackerApi.Models.ApplicationUser", null)
+ .WithMany()
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b =>
+ {
+ b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
+ .WithMany()
+ .HasForeignKey("RoleId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("JobTrackerApi.Models.ApplicationUser", null)
+ .WithMany()
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b =>
+ {
+ b.HasOne("JobTrackerApi.Models.ApplicationUser", null)
+ .WithMany()
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+ });
+
+ modelBuilder.Entity("JobTrackerApi.Models.Company", b =>
+ {
+ b.Navigation("Jobs");
+ });
+
+ modelBuilder.Entity("JobTrackerApi.Models.JobApplication", b =>
+ {
+ b.Navigation("Attachments");
+
+ b.Navigation("Events");
+
+ b.Navigation("Messages");
+
+ b.Navigation("TailoredCvDraft");
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
diff --git a/JobTrackerApi/Migrations/20260711181039_SyncModelSnapshot.cs b/JobTrackerApi/Migrations/20260711181039_SyncModelSnapshot.cs
new file mode 100644
index 0000000..9c8e0a4
--- /dev/null
+++ b/JobTrackerApi/Migrations/20260711181039_SyncModelSnapshot.cs
@@ -0,0 +1,33 @@
+using System;
+using Microsoft.EntityFrameworkCore.Migrations;
+
+#nullable disable
+
+namespace JobTrackerApi.Migrations
+{
+ ///