Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions app/api/Data/ProductModels.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ public sealed class Requirement
public required string CreatedBy { get; set; }
public DateTime CreatedAt { get; set; }
public DateTime UpdatedAt { get; set; }
// Who saved the current version. Null only for a requirement created by an API older than
// migration RequirementUpdatedBy after that migration ran; read it as the creator (ADR-050).
public string? UpdatedBy { get; set; }
public DateTime? ArchivedAt { get; set; }
public int Version { get; set; } = 1;
}
Expand Down Expand Up @@ -129,3 +132,12 @@ public sealed class DocumentContent
public Guid DocumentId { get; set; }
public required byte[] Content { get; set; }
}

// A project document a requirement cites, saved with the requirement like its criteria (ADR-049).
public sealed class RequirementDocument
{
public Guid RequirementId { get; set; }
public Guid DocumentId { get; set; }
public required string LinkedBy { get; set; }
public DateTime LinkedAt { get; set; }
}
15 changes: 15 additions & 0 deletions app/api/Data/SpecThreadDbContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ public sealed class SpecThreadDbContext(DbContextOptions<SpecThreadDbContext> op
public DbSet<TeamInvitation> TeamInvitations => Set<TeamInvitation>();
public DbSet<Document> Documents => Set<Document>();
public DbSet<DocumentContent> DocumentContents => Set<DocumentContent>();
public DbSet<RequirementDocument> RequirementDocuments => Set<RequirementDocument>();

protected override void OnModelCreating(ModelBuilder model)
{
Expand Down Expand Up @@ -143,10 +144,12 @@ protected override void OnModelCreating(ModelBuilder model)
requirement.Property(x => x.CreatedBy).HasColumnName("created_by");
requirement.Property(x => x.CreatedAt).HasColumnName("created_at").HasDefaultValueSql("now()");
requirement.Property(x => x.UpdatedAt).HasColumnName("updated_at").HasDefaultValueSql("now()");
requirement.Property(x => x.UpdatedBy).HasColumnName("updated_by");
requirement.Property(x => x.ArchivedAt).HasColumnName("archived_at");
requirement.Property(x => x.Version).HasColumnName("version").HasDefaultValue(1).IsConcurrencyToken();
requirement.HasOne<Project>().WithMany().HasForeignKey(x => x.ProjectId).OnDelete(DeleteBehavior.Restrict);
requirement.HasOne<AuthUser>().WithMany().HasForeignKey(x => x.CreatedBy).OnDelete(DeleteBehavior.Restrict);
requirement.HasOne<AuthUser>().WithMany().HasForeignKey(x => x.UpdatedBy).OnDelete(DeleteBehavior.Restrict);

var criterion = model.Entity<AcceptanceCriterion>();
criterion.ToTable("acceptance_criteria", table =>
Expand Down Expand Up @@ -285,5 +288,17 @@ protected override void OnModelCreating(ModelBuilder model)
content.Property(x => x.DocumentId).HasColumnName("document_id");
content.Property(x => x.Content).HasColumnName("content");
content.HasOne<Document>().WithOne().HasForeignKey<DocumentContent>(x => x.DocumentId).OnDelete(DeleteBehavior.Restrict);

var citation = model.Entity<RequirementDocument>();
citation.ToTable("requirement_documents");
citation.HasKey(x => new { x.RequirementId, x.DocumentId });
citation.Property(x => x.RequirementId).HasColumnName("requirement_id");
citation.Property(x => x.DocumentId).HasColumnName("document_id");
citation.Property(x => x.LinkedBy).HasColumnName("linked_by");
citation.Property(x => x.LinkedAt).HasColumnName("linked_at").HasDefaultValueSql("now()");
citation.HasIndex(x => x.DocumentId);
citation.HasOne<Requirement>().WithMany().HasForeignKey(x => x.RequirementId).OnDelete(DeleteBehavior.Restrict);
citation.HasOne<Document>().WithMany().HasForeignKey(x => x.DocumentId).OnDelete(DeleteBehavior.Restrict);
citation.HasOne<AuthUser>().WithMany().HasForeignKey(x => x.LinkedBy).OnDelete(DeleteBehavior.Restrict);
}
}
Loading
Loading