diff --git a/Apis/cv-matcher-data/Migrations/20260529111000_UpdateResultsUniqueConstraintToIncludeLanguage.Designer.cs b/Apis/cv-matcher-data/Migrations/20260529111000_UpdateResultsUniqueConstraintToIncludeLanguage.Designer.cs
new file mode 100644
index 0000000..560b81f
--- /dev/null
+++ b/Apis/cv-matcher-data/Migrations/20260529111000_UpdateResultsUniqueConstraintToIncludeLanguage.Designer.cs
@@ -0,0 +1,130 @@
+//
+using System;
+using CvMatcher.Data;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Metadata;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+
+#nullable disable
+
+namespace CvMatcher.Data.Migrations
+{
+ [DbContext(typeof(CvMatcherDbContext))]
+ [Migration("20260529111000_UpdateResultsUniqueConstraintToIncludeLanguage")]
+ partial class UpdateResultsUniqueConstraintToIncludeLanguage
+ {
+ ///
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasDefaultSchema("cvMatcher")
+ .HasAnnotation("ProductVersion", "10.0.7")
+ .HasAnnotation("Relational:MaxIdentifierLength", 128);
+
+ SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
+
+ modelBuilder.Entity("CvMatcher.Data.Entities.AiPromptEntity", b =>
+ {
+ b.Property("Key")
+ .HasMaxLength(128)
+ .HasColumnType("nvarchar(128)");
+
+ b.Property("Language")
+ .HasMaxLength(8)
+ .HasColumnType("nvarchar(8)");
+
+ b.Property("Description")
+ .IsRequired()
+ .ValueGeneratedOnAdd()
+ .HasMaxLength(500)
+ .HasColumnType("nvarchar(500)")
+ .HasDefaultValue("");
+
+ b.Property("UpdatedAt")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("datetime2")
+ .HasDefaultValueSql("SYSUTCDATETIME()");
+
+ b.Property("Value")
+ .IsRequired()
+ .HasColumnType("nvarchar(max)");
+
+ b.HasKey("Key", "Language");
+
+ b.ToTable("AiPrompts", "cvMatcher");
+ });
+
+ modelBuilder.Entity("CvMatcher.Data.Entities.CvMatchResultEntity", b =>
+ {
+ b.Property("Id")
+ .HasMaxLength(64)
+ .HasColumnType("nvarchar(64)");
+
+ b.Property("CreatedAt")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("datetime2")
+ .HasDefaultValueSql("SYSUTCDATETIME()");
+
+ b.Property("CvDocumentId")
+ .IsRequired()
+ .HasMaxLength(64)
+ .HasColumnType("nvarchar(64)");
+
+ b.Property("JobDocumentId")
+ .IsRequired()
+ .HasMaxLength(64)
+ .HasColumnType("nvarchar(64)");
+
+ b.Property("Language")
+ .IsRequired()
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("ResultJson")
+ .IsRequired()
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("Score")
+ .HasColumnType("int");
+
+ b.HasKey("Id");
+
+ b.HasIndex("CvDocumentId", "JobDocumentId", "Language")
+ .IsUnique();
+
+ b.ToTable("Results", "cvMatcher");
+ });
+
+ modelBuilder.Entity("CvMatcher.Data.Entities.CvMatcherChatCacheEntity", b =>
+ {
+ b.Property("CacheKey")
+ .HasMaxLength(64)
+ .HasColumnType("nvarchar(64)");
+
+ b.Property("CreatedAt")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("datetime2")
+ .HasDefaultValueSql("SYSUTCDATETIME()");
+
+ b.Property("Model")
+ .IsRequired()
+ .HasMaxLength(120)
+ .HasColumnType("nvarchar(120)");
+
+ b.Property("ResponseText")
+ .IsRequired()
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("Temperature")
+ .HasColumnType("decimal(4,2)");
+
+ b.HasKey("CacheKey");
+
+ b.ToTable("ChatCache", "cvMatcher");
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
diff --git a/Apis/cv-matcher-data/Migrations/20260529111000_UpdateResultsUniqueConstraintToIncludeLanguage.cs b/Apis/cv-matcher-data/Migrations/20260529111000_UpdateResultsUniqueConstraintToIncludeLanguage.cs
new file mode 100644
index 0000000..550b5bd
--- /dev/null
+++ b/Apis/cv-matcher-data/Migrations/20260529111000_UpdateResultsUniqueConstraintToIncludeLanguage.cs
@@ -0,0 +1,46 @@
+using Microsoft.EntityFrameworkCore.Migrations;
+
+#nullable disable
+
+namespace CvMatcher.Data.Migrations
+{
+ ///
+ public partial class UpdateResultsUniqueConstraintToIncludeLanguage : Migration
+ {
+ ///
+ protected override void Up(MigrationBuilder migrationBuilder)
+ {
+ // The Language column was added in migration 20260524140335, but the unique constraint
+ // was never updated from (CvDocumentId, JobDocumentId) to include Language.
+ // This caused duplicate key violations when matching the same CV+Job in different languages.
+
+ migrationBuilder.DropIndex(
+ name: "IX_Results_CvDocumentId_JobDocumentId",
+ schema: MigrationConstants.SchemaName,
+ table: "Results");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_Results_CvDocumentId_JobDocumentId_Language",
+ schema: MigrationConstants.SchemaName,
+ table: "Results",
+ columns: new[] { "CvDocumentId", "JobDocumentId", "Language" },
+ unique: true);
+ }
+
+ ///
+ protected override void Down(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.DropIndex(
+ name: "IX_Results_CvDocumentId_JobDocumentId_Language",
+ schema: MigrationConstants.SchemaName,
+ table: "Results");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_Results_CvDocumentId_JobDocumentId",
+ schema: MigrationConstants.SchemaName,
+ table: "Results",
+ columns: new[] { "CvDocumentId", "JobDocumentId" },
+ unique: true);
+ }
+ }
+}
diff --git a/Apis/cv-matcher-data/Migrations/CvMatcherDbContextModelSnapshot.cs b/Apis/cv-matcher-data/Migrations/CvMatcherDbContextModelSnapshot.cs
index 33937c3..5e2fe70 100644
--- a/Apis/cv-matcher-data/Migrations/CvMatcherDbContextModelSnapshot.cs
+++ b/Apis/cv-matcher-data/Migrations/CvMatcherDbContextModelSnapshot.cs
@@ -88,7 +88,7 @@ namespace CvMatcher.Data.Migrations
b.HasKey("Id");
- b.HasIndex("CvDocumentId", "JobDocumentId")
+ b.HasIndex("CvDocumentId", "JobDocumentId", "Language")
.IsUnique();
b.ToTable("Results", "cvMatcher");