feat(email): add tenant draft persistence
CI and Deploy / test (pull_request) Successful in 4m15s
CI and Deploy / deploy (pull_request) Has been skipped

Add owner-filtered, job-cascading private draft storage with reversible SQLite and MariaDB migration paths. No API or UI exposes draft content yet.
This commit is contained in:
cesnimda
2026-08-10 09:55:16 +02:00
parent ee8efd361d
commit 14b396a452
6 changed files with 2960 additions and 0 deletions
@@ -1098,6 +1098,61 @@ namespace JobTrackerApi.Migrations
b.ToTable("CvVariantVersions");
});
modelBuilder.Entity("JobTrackerApi.Models.EmailDraft", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("TEXT");
b.Property<string>("BodyText")
.IsRequired()
.HasColumnType("TEXT");
b.Property<DateTime>("CreatedAtUtc")
.HasColumnType("TEXT");
b.Property<int>("JobApplicationId")
.HasColumnType("INTEGER");
b.Property<string>("OwnerUserId")
.IsRequired()
.HasMaxLength(255)
.HasColumnType("TEXT");
b.Property<string>("Provider")
.IsRequired()
.HasMaxLength(32)
.HasColumnType("TEXT");
b.Property<long>("Revision")
.HasColumnType("INTEGER");
b.Property<string>("Subject")
.IsRequired()
.HasMaxLength(998)
.HasColumnType("TEXT");
b.Property<string>("ThreadId")
.HasMaxLength(512)
.HasColumnType("TEXT");
b.Property<string>("To")
.IsRequired()
.HasMaxLength(320)
.HasColumnType("TEXT");
b.Property<DateTime>("UpdatedAtUtc")
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("JobApplicationId");
b.HasIndex("OwnerUserId", "JobApplicationId", "UpdatedAtUtc");
b.ToTable("EmailDrafts");
});
modelBuilder.Entity("JobTrackerApi.Models.EmailSendAttempt", b =>
{
b.Property<Guid>("Id")
@@ -2446,6 +2501,17 @@ namespace JobTrackerApi.Migrations
b.Navigation("CvVariant");
});
modelBuilder.Entity("JobTrackerApi.Models.EmailDraft", b =>
{
b.HasOne("JobTrackerApi.Models.JobApplication", "JobApplication")
.WithMany()
.HasForeignKey("JobApplicationId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("JobApplication");
});
modelBuilder.Entity("JobTrackerApi.Models.EmailSendAttempt", b =>
{
b.HasOne("JobTrackerApi.Models.JobApplication", "JobApplication")