diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 7678df0..e7784a4 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -39,17 +39,15 @@ jobs:
- name: Restore dependencies
run: dotnet restore
- env:
- ConnectionStrings__PreceptDb: "Host=localhost;Port=5432;Username=${{ env.TEST_DB_USER }};Password=${{ steps.db-password.outputs.password }};Database=${{ env.TEST_DB_NAME }}"
- name: Build
run: dotnet build --configuration Release --no-restore
- env:
- ConnectionStrings__PreceptDb: "Host=localhost;Port=5432;Username=${{ env.TEST_DB_USER }};Password=${{ steps.db-password.outputs.password }};Database=${{ env.TEST_DB_NAME }}"
- name: Test
run: dotnet test --configuration Release --no-build --logger "trx" --results-directory "TestResults"
env:
+ # Tell the shared test fixture to use the CI-provisioned Postgres
+ # server instead of starting a Testcontainers container.
ConnectionStrings__PreceptDb: "Host=localhost;Port=5432;Username=${{ env.TEST_DB_USER }};Password=${{ steps.db-password.outputs.password }};Database=${{ env.TEST_DB_NAME }}"
# OWASP A06: Scan for vulnerable NuGet packages
diff --git a/.gitignore b/.gitignore
index 0ea80e8..f9a1a8f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -54,8 +54,6 @@ secrets.json
appsettings.*.json
!appsettings.json
-Migrations/
-
.vscode/
node_modules/
diff --git a/Precept.Api/Migrations/20260620021952_InitialPostgresCreate.Designer.cs b/Precept.Api/Migrations/20260620021952_InitialPostgresCreate.Designer.cs
new file mode 100644
index 0000000..5985c05
--- /dev/null
+++ b/Precept.Api/Migrations/20260620021952_InitialPostgresCreate.Designer.cs
@@ -0,0 +1,684 @@
+//
+using System;
+using System.Collections.Generic;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
+using Precept.Api.Data;
+
+#nullable disable
+
+namespace Precept.Api.Migrations
+{
+ [DbContext(typeof(PreceptDbContext))]
+ [Migration("20260620021952_InitialPostgresCreate")]
+ partial class InitialPostgresCreate
+ {
+ ///
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("ProductVersion", "10.0.8")
+ .HasAnnotation("Relational:MaxIdentifierLength", 63);
+
+ NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("text");
+
+ b.Property("ConcurrencyStamp")
+ .IsConcurrencyToken()
+ .HasColumnType("text");
+
+ b.Property("Name")
+ .HasMaxLength(256)
+ .HasColumnType("character varying(256)");
+
+ b.Property("NormalizedName")
+ .HasMaxLength(256)
+ .HasColumnType("character varying(256)");
+
+ 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");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ 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");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ 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("Precept.Api.Models.Application", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property("CompanyName")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("DateApplied")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("DateLastContact")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("FollowUpDate")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("IsRemote")
+ .HasColumnType("boolean");
+
+ b.Property("JobDescriptionId")
+ .HasColumnType("uuid");
+
+ b.Property("Location")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("Notes")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("ResumeVersion")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("RoleTitle")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("SalaryRange")
+ .HasColumnType("text");
+
+ b.Property("Source")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("Status")
+ .HasColumnType("integer");
+
+ b.Property("UserId")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.HasKey("Id");
+
+ b.HasIndex("JobDescriptionId");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("Applications");
+ });
+
+ modelBuilder.Entity("Precept.Api.Models.ApplicationUser", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("text");
+
+ b.Property("AccessFailedCount")
+ .HasColumnType("integer");
+
+ b.Property("ConcurrencyStamp")
+ .IsConcurrencyToken()
+ .HasColumnType("text");
+
+ b.Property("CreatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("Email")
+ .HasMaxLength(256)
+ .HasColumnType("character varying(256)");
+
+ b.Property("EmailConfirmed")
+ .HasColumnType("boolean");
+
+ b.Property("FirstName")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("LastName")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("LockoutEnabled")
+ .HasColumnType("boolean");
+
+ b.Property("LockoutEnd")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("NormalizedEmail")
+ .HasMaxLength(256)
+ .HasColumnType("character varying(256)");
+
+ b.Property("NormalizedUserName")
+ .HasMaxLength(256)
+ .HasColumnType("character varying(256)");
+
+ b.Property("PasswordHash")
+ .HasColumnType("text");
+
+ b.Property("PhoneNumber")
+ .HasColumnType("text");
+
+ b.Property("PhoneNumberConfirmed")
+ .HasColumnType("boolean");
+
+ b.Property("SecurityStamp")
+ .HasColumnType("text");
+
+ b.Property("TwoFactorEnabled")
+ .HasColumnType("boolean");
+
+ b.Property("UserName")
+ .HasMaxLength(256)
+ .HasColumnType("character varying(256)");
+
+ b.HasKey("Id");
+
+ b.HasIndex("NormalizedEmail")
+ .HasDatabaseName("EmailIndex");
+
+ b.HasIndex("NormalizedUserName")
+ .IsUnique()
+ .HasDatabaseName("UserNameIndex");
+
+ b.ToTable("AspNetUsers", (string)null);
+ });
+
+ modelBuilder.Entity("Precept.Api.Models.BehavioralStory", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property("Action")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("CreatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("Result")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("Situation")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("Tags")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("Task")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("Title")
+ .IsRequired()
+ .HasMaxLength(100)
+ .HasColumnType("character varying(100)");
+
+ b.Property("UpdatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("UserId")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.HasKey("Id");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("BehavioralStories");
+ });
+
+ modelBuilder.Entity("Precept.Api.Models.JobDescription", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property("CompanyName")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("DatePosted")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("Description")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.PrimitiveCollection>("ExtractedKeyWords")
+ .IsRequired()
+ .HasColumnType("text[]");
+
+ b.Property("IsRemote")
+ .HasColumnType("boolean");
+
+ b.Property("Location")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.PrimitiveCollection>("MissingKeyWords")
+ .IsRequired()
+ .HasColumnType("text[]");
+
+ b.Property("RoleTitle")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("SalaryRange")
+ .HasColumnType("text");
+
+ b.Property("Source")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("Url")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("UserId")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("YourMatchScore")
+ .HasColumnType("integer");
+
+ b.HasKey("Id");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("JobDescriptions");
+ });
+
+ modelBuilder.Entity("Precept.Api.Models.RefreshToken", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property("CreatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("DeviceInfo")
+ .HasMaxLength(512)
+ .HasColumnType("character varying(512)");
+
+ b.Property("ExpiresAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("RememberMe")
+ .HasColumnType("boolean");
+
+ b.Property("ReplacedByToken")
+ .HasMaxLength(128)
+ .HasColumnType("character varying(128)");
+
+ b.Property("RevokedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("Token")
+ .IsRequired()
+ .HasMaxLength(128)
+ .HasColumnType("character varying(128)");
+
+ b.Property("UserId")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.HasKey("Id");
+
+ b.HasIndex("Token");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("RefreshTokens");
+ });
+
+ modelBuilder.Entity("Precept.Api.Models.Skill", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property("Category")
+ .HasMaxLength(50)
+ .HasColumnType("character varying(50)");
+
+ b.Property("CreatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasMaxLength(100)
+ .HasColumnType("character varying(100)");
+
+ b.Property("Notes")
+ .HasColumnType("text");
+
+ b.Property("ProficiencyLevel")
+ .HasColumnType("integer");
+
+ b.Property("UpdatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("UserId")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.HasKey("Id");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("Skills");
+ });
+
+ modelBuilder.Entity("Precept.Api.Models.Story", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property("Category")
+ .HasColumnType("integer");
+
+ b.Property("CodeSnippet")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("ConfidenceLevel")
+ .HasColumnType("integer");
+
+ b.Property("CreatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("Explanation")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("LastReviewedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("SourceProject")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("Title")
+ .IsRequired()
+ .HasMaxLength(100)
+ .HasColumnType("character varying(100)");
+
+ b.Property("UpdatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("UserId")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.HasKey("Id");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("Stories");
+ });
+
+ 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("Precept.Api.Models.ApplicationUser", null)
+ .WithMany()
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b =>
+ {
+ b.HasOne("Precept.Api.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("Precept.Api.Models.ApplicationUser", null)
+ .WithMany()
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b =>
+ {
+ b.HasOne("Precept.Api.Models.ApplicationUser", null)
+ .WithMany()
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+ });
+
+ modelBuilder.Entity("Precept.Api.Models.Application", b =>
+ {
+ b.HasOne("Precept.Api.Models.JobDescription", "JobDescription")
+ .WithMany("Applications")
+ .HasForeignKey("JobDescriptionId")
+ .OnDelete(DeleteBehavior.SetNull);
+
+ b.HasOne("Precept.Api.Models.ApplicationUser", "User")
+ .WithMany("Applications")
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("JobDescription");
+
+ b.Navigation("User");
+ });
+
+ modelBuilder.Entity("Precept.Api.Models.BehavioralStory", b =>
+ {
+ b.HasOne("Precept.Api.Models.ApplicationUser", "User")
+ .WithMany("BehavioralStories")
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("User");
+ });
+
+ modelBuilder.Entity("Precept.Api.Models.JobDescription", b =>
+ {
+ b.HasOne("Precept.Api.Models.ApplicationUser", "User")
+ .WithMany("JobDescriptions")
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("User");
+ });
+
+ modelBuilder.Entity("Precept.Api.Models.RefreshToken", b =>
+ {
+ b.HasOne("Precept.Api.Models.ApplicationUser", "User")
+ .WithMany()
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("User");
+ });
+
+ modelBuilder.Entity("Precept.Api.Models.Skill", b =>
+ {
+ b.HasOne("Precept.Api.Models.ApplicationUser", "User")
+ .WithMany("Skills")
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("User");
+ });
+
+ modelBuilder.Entity("Precept.Api.Models.Story", b =>
+ {
+ b.HasOne("Precept.Api.Models.ApplicationUser", "User")
+ .WithMany("Stories")
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("User");
+ });
+
+ modelBuilder.Entity("Precept.Api.Models.ApplicationUser", b =>
+ {
+ b.Navigation("Applications");
+
+ b.Navigation("BehavioralStories");
+
+ b.Navigation("JobDescriptions");
+
+ b.Navigation("Skills");
+
+ b.Navigation("Stories");
+ });
+
+ modelBuilder.Entity("Precept.Api.Models.JobDescription", b =>
+ {
+ b.Navigation("Applications");
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
diff --git a/Precept.Api/Migrations/20260620021952_InitialPostgresCreate.cs b/Precept.Api/Migrations/20260620021952_InitialPostgresCreate.cs
new file mode 100644
index 0000000..d937ee9
--- /dev/null
+++ b/Precept.Api/Migrations/20260620021952_InitialPostgresCreate.cs
@@ -0,0 +1,454 @@
+using System;
+using System.Collections.Generic;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
+
+#nullable disable
+
+namespace Precept.Api.Migrations
+{
+ ///
+ public partial class InitialPostgresCreate : Migration
+ {
+ ///
+ protected override void Up(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.CreateTable(
+ name: "AspNetRoles",
+ columns: table => new
+ {
+ Id = table.Column(type: "text", nullable: false),
+ Name = table.Column(type: "character varying(256)", maxLength: 256, nullable: true),
+ NormalizedName = table.Column(type: "character varying(256)", maxLength: 256, nullable: true),
+ ConcurrencyStamp = table.Column(type: "text", nullable: true)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_AspNetRoles", x => x.Id);
+ });
+
+ migrationBuilder.CreateTable(
+ name: "AspNetUsers",
+ columns: table => new
+ {
+ Id = table.Column(type: "text", nullable: false),
+ FirstName = table.Column(type: "text", nullable: false),
+ LastName = table.Column(type: "text", nullable: false),
+ CreatedAt = table.Column(type: "timestamp with time zone", nullable: false),
+ UserName = table.Column(type: "character varying(256)", maxLength: 256, nullable: true),
+ NormalizedUserName = table.Column(type: "character varying(256)", maxLength: 256, nullable: true),
+ Email = table.Column(type: "character varying(256)", maxLength: 256, nullable: true),
+ NormalizedEmail = table.Column(type: "character varying(256)", maxLength: 256, nullable: true),
+ EmailConfirmed = table.Column(type: "boolean", nullable: false),
+ PasswordHash = table.Column(type: "text", nullable: true),
+ SecurityStamp = table.Column(type: "text", nullable: true),
+ ConcurrencyStamp = table.Column(type: "text", nullable: true),
+ PhoneNumber = table.Column(type: "text", nullable: true),
+ PhoneNumberConfirmed = table.Column(type: "boolean", nullable: false),
+ TwoFactorEnabled = table.Column(type: "boolean", nullable: false),
+ LockoutEnd = table.Column(type: "timestamp with time zone", nullable: true),
+ LockoutEnabled = table.Column(type: "boolean", nullable: false),
+ AccessFailedCount = table.Column(type: "integer", nullable: false)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_AspNetUsers", x => x.Id);
+ });
+
+ migrationBuilder.CreateTable(
+ name: "AspNetRoleClaims",
+ columns: table => new
+ {
+ Id = table.Column(type: "integer", nullable: false)
+ .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
+ RoleId = table.Column(type: "text", nullable: false),
+ ClaimType = table.Column(type: "text", nullable: true),
+ ClaimValue = table.Column(type: "text", nullable: true)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_AspNetRoleClaims", x => x.Id);
+ table.ForeignKey(
+ name: "FK_AspNetRoleClaims_AspNetRoles_RoleId",
+ column: x => x.RoleId,
+ principalTable: "AspNetRoles",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Cascade);
+ });
+
+ migrationBuilder.CreateTable(
+ name: "AspNetUserClaims",
+ columns: table => new
+ {
+ Id = table.Column(type: "integer", nullable: false)
+ .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
+ UserId = table.Column(type: "text", nullable: false),
+ ClaimType = table.Column(type: "text", nullable: true),
+ ClaimValue = table.Column(type: "text", nullable: true)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_AspNetUserClaims", x => x.Id);
+ table.ForeignKey(
+ name: "FK_AspNetUserClaims_AspNetUsers_UserId",
+ column: x => x.UserId,
+ principalTable: "AspNetUsers",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Cascade);
+ });
+
+ migrationBuilder.CreateTable(
+ name: "AspNetUserLogins",
+ columns: table => new
+ {
+ LoginProvider = table.Column(type: "text", nullable: false),
+ ProviderKey = table.Column(type: "text", nullable: false),
+ ProviderDisplayName = table.Column(type: "text", nullable: true),
+ UserId = table.Column(type: "text", nullable: false)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_AspNetUserLogins", x => new { x.LoginProvider, x.ProviderKey });
+ table.ForeignKey(
+ name: "FK_AspNetUserLogins_AspNetUsers_UserId",
+ column: x => x.UserId,
+ principalTable: "AspNetUsers",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Cascade);
+ });
+
+ migrationBuilder.CreateTable(
+ name: "AspNetUserRoles",
+ columns: table => new
+ {
+ UserId = table.Column(type: "text", nullable: false),
+ RoleId = table.Column(type: "text", nullable: false)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_AspNetUserRoles", x => new { x.UserId, x.RoleId });
+ table.ForeignKey(
+ name: "FK_AspNetUserRoles_AspNetRoles_RoleId",
+ column: x => x.RoleId,
+ principalTable: "AspNetRoles",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Cascade);
+ table.ForeignKey(
+ name: "FK_AspNetUserRoles_AspNetUsers_UserId",
+ column: x => x.UserId,
+ principalTable: "AspNetUsers",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Cascade);
+ });
+
+ migrationBuilder.CreateTable(
+ name: "AspNetUserTokens",
+ columns: table => new
+ {
+ UserId = table.Column(type: "text", nullable: false),
+ LoginProvider = table.Column(type: "text", nullable: false),
+ Name = table.Column(type: "text", nullable: false),
+ Value = table.Column(type: "text", nullable: true)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_AspNetUserTokens", x => new { x.UserId, x.LoginProvider, x.Name });
+ table.ForeignKey(
+ name: "FK_AspNetUserTokens_AspNetUsers_UserId",
+ column: x => x.UserId,
+ principalTable: "AspNetUsers",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Cascade);
+ });
+
+ migrationBuilder.CreateTable(
+ name: "BehavioralStories",
+ columns: table => new
+ {
+ Id = table.Column(type: "uuid", nullable: false),
+ UserId = table.Column(type: "text", nullable: false),
+ Title = table.Column(type: "character varying(100)", maxLength: 100, nullable: false),
+ Situation = table.Column(type: "text", nullable: false),
+ Task = table.Column(type: "text", nullable: false),
+ Action = table.Column(type: "text", nullable: false),
+ Result = table.Column(type: "text", nullable: false),
+ Tags = table.Column(type: "text", nullable: false),
+ CreatedAt = table.Column(type: "timestamp with time zone", nullable: false),
+ UpdatedAt = table.Column(type: "timestamp with time zone", nullable: false)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_BehavioralStories", x => x.Id);
+ table.ForeignKey(
+ name: "FK_BehavioralStories_AspNetUsers_UserId",
+ column: x => x.UserId,
+ principalTable: "AspNetUsers",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Cascade);
+ });
+
+ migrationBuilder.CreateTable(
+ name: "JobDescriptions",
+ columns: table => new
+ {
+ Id = table.Column(type: "uuid", nullable: false),
+ UserId = table.Column(type: "text", nullable: false),
+ CompanyName = table.Column(type: "text", nullable: false),
+ RoleTitle = table.Column(type: "text", nullable: false),
+ Description = table.Column(type: "text", nullable: false),
+ ExtractedKeyWords = table.Column>(type: "text[]", nullable: false),
+ MissingKeyWords = table.Column>(type: "text[]", nullable: false),
+ YourMatchScore = table.Column(type: "integer", nullable: true),
+ Url = table.Column(type: "text", nullable: false),
+ SalaryRange = table.Column(type: "text", nullable: true),
+ Location = table.Column(type: "text", nullable: false),
+ IsRemote = table.Column(type: "boolean", nullable: false),
+ Source = table.Column(type: "text", nullable: false),
+ DatePosted = table.Column(type: "timestamp with time zone", nullable: false)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_JobDescriptions", x => x.Id);
+ table.ForeignKey(
+ name: "FK_JobDescriptions_AspNetUsers_UserId",
+ column: x => x.UserId,
+ principalTable: "AspNetUsers",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Cascade);
+ });
+
+ migrationBuilder.CreateTable(
+ name: "RefreshTokens",
+ columns: table => new
+ {
+ Id = table.Column(type: "uuid", nullable: false),
+ Token = table.Column(type: "character varying(128)", maxLength: 128, nullable: false),
+ UserId = table.Column(type: "text", nullable: false),
+ CreatedAt = table.Column(type: "timestamp with time zone", nullable: false),
+ ExpiresAt = table.Column(type: "timestamp with time zone", nullable: false),
+ RevokedAt = table.Column(type: "timestamp with time zone", nullable: true),
+ ReplacedByToken = table.Column(type: "character varying(128)", maxLength: 128, nullable: true),
+ DeviceInfo = table.Column(type: "character varying(512)", maxLength: 512, nullable: true),
+ RememberMe = table.Column(type: "boolean", nullable: false)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_RefreshTokens", x => x.Id);
+ table.ForeignKey(
+ name: "FK_RefreshTokens_AspNetUsers_UserId",
+ column: x => x.UserId,
+ principalTable: "AspNetUsers",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Cascade);
+ });
+
+ migrationBuilder.CreateTable(
+ name: "Skills",
+ columns: table => new
+ {
+ Id = table.Column(type: "uuid", nullable: false),
+ UserId = table.Column(type: "text", nullable: false),
+ Name = table.Column(type: "character varying(100)", maxLength: 100, nullable: false),
+ Category = table.Column(type: "character varying(50)", maxLength: 50, nullable: true),
+ ProficiencyLevel = table.Column(type: "integer", nullable: false),
+ Notes = table.Column(type: "text", nullable: true),
+ CreatedAt = table.Column(type: "timestamp with time zone", nullable: false),
+ UpdatedAt = table.Column(type: "timestamp with time zone", nullable: false)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_Skills", x => x.Id);
+ table.ForeignKey(
+ name: "FK_Skills_AspNetUsers_UserId",
+ column: x => x.UserId,
+ principalTable: "AspNetUsers",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Cascade);
+ });
+
+ migrationBuilder.CreateTable(
+ name: "Stories",
+ columns: table => new
+ {
+ Id = table.Column(type: "uuid", nullable: false),
+ UserId = table.Column(type: "text", nullable: false),
+ Title = table.Column(type: "character varying(100)", maxLength: 100, nullable: false),
+ CodeSnippet = table.Column(type: "text", nullable: false),
+ Explanation = table.Column(type: "text", nullable: false),
+ SourceProject = table.Column(type: "text", nullable: false),
+ Category = table.Column(type: "integer", nullable: false),
+ CreatedAt = table.Column(type: "timestamp with time zone", nullable: false),
+ LastReviewedAt = table.Column(type: "timestamp with time zone", nullable: true),
+ UpdatedAt = table.Column(type: "timestamp with time zone", nullable: false),
+ ConfidenceLevel = table.Column(type: "integer", nullable: false)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_Stories", x => x.Id);
+ table.ForeignKey(
+ name: "FK_Stories_AspNetUsers_UserId",
+ column: x => x.UserId,
+ principalTable: "AspNetUsers",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Cascade);
+ });
+
+ migrationBuilder.CreateTable(
+ name: "Applications",
+ columns: table => new
+ {
+ Id = table.Column(type: "uuid", nullable: false),
+ UserId = table.Column(type: "text", nullable: false),
+ CompanyName = table.Column(type: "text", nullable: false),
+ RoleTitle = table.Column(type: "text", nullable: false),
+ Location = table.Column(type: "text", nullable: false),
+ SalaryRange = table.Column(type: "text", nullable: true),
+ Status = table.Column(type: "integer", nullable: false),
+ DateApplied = table.Column(type: "timestamp with time zone", nullable: true),
+ DateLastContact = table.Column(type: "timestamp with time zone", nullable: true),
+ FollowUpDate = table.Column(type: "timestamp with time zone", nullable: false),
+ ResumeVersion = table.Column(type: "text", nullable: false),
+ Notes = table.Column(type: "text", nullable: false),
+ IsRemote = table.Column(type: "boolean", nullable: false),
+ Source = table.Column(type: "text", nullable: false),
+ JobDescriptionId = table.Column(type: "uuid", nullable: true)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_Applications", x => x.Id);
+ table.ForeignKey(
+ name: "FK_Applications_AspNetUsers_UserId",
+ column: x => x.UserId,
+ principalTable: "AspNetUsers",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Cascade);
+ table.ForeignKey(
+ name: "FK_Applications_JobDescriptions_JobDescriptionId",
+ column: x => x.JobDescriptionId,
+ principalTable: "JobDescriptions",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.SetNull);
+ });
+
+ migrationBuilder.CreateIndex(
+ name: "IX_Applications_JobDescriptionId",
+ table: "Applications",
+ column: "JobDescriptionId");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_Applications_UserId",
+ table: "Applications",
+ column: "UserId");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_AspNetRoleClaims_RoleId",
+ table: "AspNetRoleClaims",
+ column: "RoleId");
+
+ migrationBuilder.CreateIndex(
+ name: "RoleNameIndex",
+ table: "AspNetRoles",
+ column: "NormalizedName",
+ unique: true);
+
+ migrationBuilder.CreateIndex(
+ name: "IX_AspNetUserClaims_UserId",
+ table: "AspNetUserClaims",
+ column: "UserId");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_AspNetUserLogins_UserId",
+ table: "AspNetUserLogins",
+ column: "UserId");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_AspNetUserRoles_RoleId",
+ table: "AspNetUserRoles",
+ column: "RoleId");
+
+ migrationBuilder.CreateIndex(
+ name: "EmailIndex",
+ table: "AspNetUsers",
+ column: "NormalizedEmail");
+
+ migrationBuilder.CreateIndex(
+ name: "UserNameIndex",
+ table: "AspNetUsers",
+ column: "NormalizedUserName",
+ unique: true);
+
+ migrationBuilder.CreateIndex(
+ name: "IX_BehavioralStories_UserId",
+ table: "BehavioralStories",
+ column: "UserId");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_JobDescriptions_UserId",
+ table: "JobDescriptions",
+ column: "UserId");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_RefreshTokens_Token",
+ table: "RefreshTokens",
+ column: "Token");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_RefreshTokens_UserId",
+ table: "RefreshTokens",
+ column: "UserId");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_Skills_UserId",
+ table: "Skills",
+ column: "UserId");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_Stories_UserId",
+ table: "Stories",
+ column: "UserId");
+ }
+
+ ///
+ protected override void Down(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.DropTable(
+ name: "Applications");
+
+ migrationBuilder.DropTable(
+ name: "AspNetRoleClaims");
+
+ migrationBuilder.DropTable(
+ name: "AspNetUserClaims");
+
+ migrationBuilder.DropTable(
+ name: "AspNetUserLogins");
+
+ migrationBuilder.DropTable(
+ name: "AspNetUserRoles");
+
+ migrationBuilder.DropTable(
+ name: "AspNetUserTokens");
+
+ migrationBuilder.DropTable(
+ name: "BehavioralStories");
+
+ migrationBuilder.DropTable(
+ name: "RefreshTokens");
+
+ migrationBuilder.DropTable(
+ name: "Skills");
+
+ migrationBuilder.DropTable(
+ name: "Stories");
+
+ migrationBuilder.DropTable(
+ name: "JobDescriptions");
+
+ migrationBuilder.DropTable(
+ name: "AspNetRoles");
+
+ migrationBuilder.DropTable(
+ name: "AspNetUsers");
+ }
+ }
+}
diff --git a/Precept.Api/Migrations/20260621222255_SyncModelSnapshot.Designer.cs b/Precept.Api/Migrations/20260621222255_SyncModelSnapshot.Designer.cs
new file mode 100644
index 0000000..c1cddae
--- /dev/null
+++ b/Precept.Api/Migrations/20260621222255_SyncModelSnapshot.Designer.cs
@@ -0,0 +1,726 @@
+//
+using System;
+using System.Collections.Generic;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
+using Precept.Api.Data;
+
+#nullable disable
+
+namespace Precept.Api.Migrations
+{
+ [DbContext(typeof(PreceptDbContext))]
+ [Migration("20260621222255_SyncModelSnapshot")]
+ partial class SyncModelSnapshot
+ {
+ ///
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("ProductVersion", "10.0.8")
+ .HasAnnotation("Relational:MaxIdentifierLength", 63);
+
+ NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("text");
+
+ b.Property("ConcurrencyStamp")
+ .IsConcurrencyToken()
+ .HasColumnType("text");
+
+ b.Property("Name")
+ .HasMaxLength(256)
+ .HasColumnType("character varying(256)");
+
+ b.Property("NormalizedName")
+ .HasMaxLength(256)
+ .HasColumnType("character varying(256)");
+
+ 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");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ 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");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ 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