From de6af53a7763e01479b48bd0c5b6840ce8a61fb2 Mon Sep 17 00:00:00 2001 From: Yaojia Wang Date: Tue, 4 Nov 2025 23:10:12 +0100 Subject: [PATCH] feat(backend): Add AuditLog database schema and migration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implement AuditLog entity and EF Core configuration for Sprint 2 Story 1 Task 1. Changes: - Created AuditLog entity with multi-tenant support - Added EF Core configuration with JSONB columns for PostgreSQL - Created composite indexes for query optimization - Generated database migration (20251104220842_AddAuditLogTable) - Updated PMDbContext with AuditLog DbSet and query filter - Updated task status to in_progress in sprint plan Technical Details: - PostgreSQL JSONB type for OldValues/NewValues (flexible schema) - Composite index on (TenantId, EntityType, EntityId) for entity history queries - Timestamp index (DESC) for recent logs queries - UserId index for user activity tracking - Multi-tenant query filter applied to AuditLog 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- .../Entities/AuditLog.cs | 60 +++ ...0251104220842_AddAuditLogTable.Designer.cs | 373 ++++++++++++++++++ .../20251104220842_AddAuditLogTable.cs | 62 +++ .../Migrations/PMDbContextModelSnapshot.cs | 48 +++ .../Configurations/AuditLogConfiguration.cs | 80 ++++ .../Persistence/PMDbContext.cs | 5 + docs/plans/sprint_2_story_1_task_1.md | 3 +- 7 files changed, 630 insertions(+), 1 deletion(-) create mode 100644 colaflow-api/src/Modules/ProjectManagement/ColaFlow.Modules.ProjectManagement.Domain/Entities/AuditLog.cs create mode 100644 colaflow-api/src/Modules/ProjectManagement/ColaFlow.Modules.ProjectManagement.Infrastructure/Migrations/20251104220842_AddAuditLogTable.Designer.cs create mode 100644 colaflow-api/src/Modules/ProjectManagement/ColaFlow.Modules.ProjectManagement.Infrastructure/Migrations/20251104220842_AddAuditLogTable.cs create mode 100644 colaflow-api/src/Modules/ProjectManagement/ColaFlow.Modules.ProjectManagement.Infrastructure/Persistence/Configurations/AuditLogConfiguration.cs diff --git a/colaflow-api/src/Modules/ProjectManagement/ColaFlow.Modules.ProjectManagement.Domain/Entities/AuditLog.cs b/colaflow-api/src/Modules/ProjectManagement/ColaFlow.Modules.ProjectManagement.Domain/Entities/AuditLog.cs new file mode 100644 index 0000000..59e1deb --- /dev/null +++ b/colaflow-api/src/Modules/ProjectManagement/ColaFlow.Modules.ProjectManagement.Domain/Entities/AuditLog.cs @@ -0,0 +1,60 @@ +using ColaFlow.Shared.Kernel.Common; +using ColaFlow.Modules.ProjectManagement.Domain.ValueObjects; + +namespace ColaFlow.Modules.ProjectManagement.Domain.Entities; + +/// +/// AuditLog entity for tracking changes to entities (Create/Update/Delete operations) +/// Supports multi-tenant isolation and stores old/new values as JSON +/// +public class AuditLog : Entity +{ + public TenantId TenantId { get; private set; } + public string EntityType { get; private set; } + public Guid EntityId { get; private set; } + public string Action { get; private set; } // "Create", "Update", "Delete" + public UserId? UserId { get; private set; } + public DateTime Timestamp { get; private set; } + public string? OldValues { get; private set; } // JSONB - serialized old values + public string? NewValues { get; private set; } // JSONB - serialized new values + + // EF Core constructor + private AuditLog() + { + TenantId = null!; + EntityType = null!; + Action = null!; + } + + /// + /// Factory method to create a new AuditLog entry + /// + public static AuditLog Create( + TenantId tenantId, + string entityType, + Guid entityId, + string action, + UserId? userId, + string? oldValues, + string? newValues) + { + if (string.IsNullOrWhiteSpace(entityType)) + throw new ArgumentException("Entity type cannot be empty", nameof(entityType)); + + if (string.IsNullOrWhiteSpace(action)) + throw new ArgumentException("Action cannot be empty", nameof(action)); + + return new AuditLog + { + Id = Guid.NewGuid(), + TenantId = tenantId, + EntityType = entityType, + EntityId = entityId, + Action = action, + UserId = userId, + Timestamp = DateTime.UtcNow, + OldValues = oldValues, + NewValues = newValues + }; + } +} diff --git a/colaflow-api/src/Modules/ProjectManagement/ColaFlow.Modules.ProjectManagement.Infrastructure/Migrations/20251104220842_AddAuditLogTable.Designer.cs b/colaflow-api/src/Modules/ProjectManagement/ColaFlow.Modules.ProjectManagement.Infrastructure/Migrations/20251104220842_AddAuditLogTable.Designer.cs new file mode 100644 index 0000000..20ae080 --- /dev/null +++ b/colaflow-api/src/Modules/ProjectManagement/ColaFlow.Modules.ProjectManagement.Infrastructure/Migrations/20251104220842_AddAuditLogTable.Designer.cs @@ -0,0 +1,373 @@ +// +using System; +using ColaFlow.Modules.ProjectManagement.Infrastructure.Persistence; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace ColaFlow.Modules.ProjectManagement.Infrastructure.Migrations +{ + [DbContext(typeof(PMDbContext))] + [Migration("20251104220842_AddAuditLogTable")] + partial class AddAuditLogTable + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasDefaultSchema("project_management") + .HasAnnotation("ProductVersion", "9.0.10") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("ColaFlow.Modules.ProjectManagement.Domain.Aggregates.ProjectAggregate.Epic", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("CreatedBy") + .HasColumnType("uuid"); + + b.Property("Description") + .IsRequired() + .HasMaxLength(2000) + .HasColumnType("character varying(2000)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("Priority") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("ProjectId") + .HasColumnType("uuid"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("tenant_id"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("CreatedAt"); + + b.HasIndex("ProjectId"); + + b.HasIndex("TenantId") + .HasDatabaseName("ix_epics_tenant_id"); + + b.ToTable("Epics", "project_management"); + }); + + modelBuilder.Entity("ColaFlow.Modules.ProjectManagement.Domain.Aggregates.ProjectAggregate.Project", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Description") + .IsRequired() + .HasMaxLength(2000) + .HasColumnType("character varying(2000)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("OwnerId") + .HasColumnType("uuid"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("CreatedAt"); + + b.HasIndex("OwnerId"); + + b.HasIndex("TenantId"); + + b.ToTable("Projects", "project_management"); + }); + + modelBuilder.Entity("ColaFlow.Modules.ProjectManagement.Domain.Aggregates.ProjectAggregate.Story", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ActualHours") + .HasColumnType("numeric"); + + b.Property("AssigneeId") + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("CreatedBy") + .HasColumnType("uuid"); + + b.Property("Description") + .IsRequired() + .HasMaxLength(4000) + .HasColumnType("character varying(4000)"); + + b.Property("EpicId") + .HasColumnType("uuid"); + + b.Property("EstimatedHours") + .HasColumnType("numeric"); + + b.Property("Priority") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("tenant_id"); + + b.Property("Title") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("AssigneeId"); + + b.HasIndex("CreatedAt"); + + b.HasIndex("EpicId"); + + b.HasIndex("TenantId") + .HasDatabaseName("ix_stories_tenant_id"); + + b.ToTable("Stories", "project_management"); + }); + + modelBuilder.Entity("ColaFlow.Modules.ProjectManagement.Domain.Aggregates.ProjectAggregate.WorkTask", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ActualHours") + .HasColumnType("numeric"); + + b.Property("AssigneeId") + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("CreatedBy") + .HasColumnType("uuid"); + + b.Property("Description") + .IsRequired() + .HasMaxLength(4000) + .HasColumnType("character varying(4000)"); + + b.Property("EstimatedHours") + .HasColumnType("numeric"); + + b.Property("Priority") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("StoryId") + .HasColumnType("uuid"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("tenant_id"); + + b.Property("Title") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("AssigneeId"); + + b.HasIndex("CreatedAt"); + + b.HasIndex("StoryId"); + + b.HasIndex("TenantId") + .HasDatabaseName("ix_tasks_tenant_id"); + + b.ToTable("Tasks", "project_management"); + }); + + modelBuilder.Entity("ColaFlow.Modules.ProjectManagement.Domain.Entities.AuditLog", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("Action") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("character varying(20)"); + + b.Property("EntityId") + .HasColumnType("uuid"); + + b.Property("EntityType") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("NewValues") + .HasColumnType("jsonb"); + + b.Property("OldValues") + .HasColumnType("jsonb"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("Timestamp") + .HasColumnType("timestamp with time zone"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("Timestamp") + .IsDescending() + .HasDatabaseName("IX_AuditLogs_Timestamp"); + + b.HasIndex("UserId") + .HasDatabaseName("IX_AuditLogs_UserId"); + + b.HasIndex("TenantId", "EntityType", "EntityId") + .HasDatabaseName("IX_AuditLogs_TenantId_EntityType_EntityId"); + + b.ToTable("AuditLogs", "project_management"); + }); + + modelBuilder.Entity("ColaFlow.Modules.ProjectManagement.Domain.Aggregates.ProjectAggregate.Epic", b => + { + b.HasOne("ColaFlow.Modules.ProjectManagement.Domain.Aggregates.ProjectAggregate.Project", null) + .WithMany("Epics") + .HasForeignKey("ProjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("ColaFlow.Modules.ProjectManagement.Domain.Aggregates.ProjectAggregate.Project", b => + { + b.OwnsOne("ColaFlow.Modules.ProjectManagement.Domain.ValueObjects.ProjectKey", "Key", b1 => + { + b1.Property("ProjectId") + .HasColumnType("uuid"); + + b1.Property("Value") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("character varying(20)") + .HasColumnName("Key"); + + b1.HasKey("ProjectId"); + + b1.HasIndex("Value") + .IsUnique(); + + b1.ToTable("Projects", "project_management"); + + b1.WithOwner() + .HasForeignKey("ProjectId"); + }); + + b.Navigation("Key") + .IsRequired(); + }); + + modelBuilder.Entity("ColaFlow.Modules.ProjectManagement.Domain.Aggregates.ProjectAggregate.Story", b => + { + b.HasOne("ColaFlow.Modules.ProjectManagement.Domain.Aggregates.ProjectAggregate.Epic", null) + .WithMany("Stories") + .HasForeignKey("EpicId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("ColaFlow.Modules.ProjectManagement.Domain.Aggregates.ProjectAggregate.WorkTask", b => + { + b.HasOne("ColaFlow.Modules.ProjectManagement.Domain.Aggregates.ProjectAggregate.Story", null) + .WithMany("Tasks") + .HasForeignKey("StoryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("ColaFlow.Modules.ProjectManagement.Domain.Aggregates.ProjectAggregate.Epic", b => + { + b.Navigation("Stories"); + }); + + modelBuilder.Entity("ColaFlow.Modules.ProjectManagement.Domain.Aggregates.ProjectAggregate.Project", b => + { + b.Navigation("Epics"); + }); + + modelBuilder.Entity("ColaFlow.Modules.ProjectManagement.Domain.Aggregates.ProjectAggregate.Story", b => + { + b.Navigation("Tasks"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/colaflow-api/src/Modules/ProjectManagement/ColaFlow.Modules.ProjectManagement.Infrastructure/Migrations/20251104220842_AddAuditLogTable.cs b/colaflow-api/src/Modules/ProjectManagement/ColaFlow.Modules.ProjectManagement.Infrastructure/Migrations/20251104220842_AddAuditLogTable.cs new file mode 100644 index 0000000..db88253 --- /dev/null +++ b/colaflow-api/src/Modules/ProjectManagement/ColaFlow.Modules.ProjectManagement.Infrastructure/Migrations/20251104220842_AddAuditLogTable.cs @@ -0,0 +1,62 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace ColaFlow.Modules.ProjectManagement.Infrastructure.Migrations +{ + /// + public partial class AddAuditLogTable : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "AuditLogs", + schema: "project_management", + columns: table => new + { + Id = table.Column(type: "uuid", nullable: false), + TenantId = table.Column(type: "uuid", nullable: false), + EntityType = table.Column(type: "character varying(100)", maxLength: 100, nullable: false), + EntityId = table.Column(type: "uuid", nullable: false), + Action = table.Column(type: "character varying(20)", maxLength: 20, nullable: false), + UserId = table.Column(type: "uuid", nullable: true), + Timestamp = table.Column(type: "timestamp with time zone", nullable: false), + OldValues = table.Column(type: "jsonb", nullable: true), + NewValues = table.Column(type: "jsonb", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AuditLogs", x => x.Id); + }); + + migrationBuilder.CreateIndex( + name: "IX_AuditLogs_TenantId_EntityType_EntityId", + schema: "project_management", + table: "AuditLogs", + columns: new[] { "TenantId", "EntityType", "EntityId" }); + + migrationBuilder.CreateIndex( + name: "IX_AuditLogs_Timestamp", + schema: "project_management", + table: "AuditLogs", + column: "Timestamp", + descending: new bool[0]); + + migrationBuilder.CreateIndex( + name: "IX_AuditLogs_UserId", + schema: "project_management", + table: "AuditLogs", + column: "UserId"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "AuditLogs", + schema: "project_management"); + } + } +} diff --git a/colaflow-api/src/Modules/ProjectManagement/ColaFlow.Modules.ProjectManagement.Infrastructure/Migrations/PMDbContextModelSnapshot.cs b/colaflow-api/src/Modules/ProjectManagement/ColaFlow.Modules.ProjectManagement.Infrastructure/Migrations/PMDbContextModelSnapshot.cs index 28bbdfa..c76ed88 100644 --- a/colaflow-api/src/Modules/ProjectManagement/ColaFlow.Modules.ProjectManagement.Infrastructure/Migrations/PMDbContextModelSnapshot.cs +++ b/colaflow-api/src/Modules/ProjectManagement/ColaFlow.Modules.ProjectManagement.Infrastructure/Migrations/PMDbContextModelSnapshot.cs @@ -247,6 +247,54 @@ namespace ColaFlow.Modules.ProjectManagement.Infrastructure.Migrations b.ToTable("Tasks", "project_management"); }); + modelBuilder.Entity("ColaFlow.Modules.ProjectManagement.Domain.Entities.AuditLog", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("Action") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("character varying(20)"); + + b.Property("EntityId") + .HasColumnType("uuid"); + + b.Property("EntityType") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("NewValues") + .HasColumnType("jsonb"); + + b.Property("OldValues") + .HasColumnType("jsonb"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("Timestamp") + .HasColumnType("timestamp with time zone"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("Timestamp") + .IsDescending() + .HasDatabaseName("IX_AuditLogs_Timestamp"); + + b.HasIndex("UserId") + .HasDatabaseName("IX_AuditLogs_UserId"); + + b.HasIndex("TenantId", "EntityType", "EntityId") + .HasDatabaseName("IX_AuditLogs_TenantId_EntityType_EntityId"); + + b.ToTable("AuditLogs", "project_management"); + }); + modelBuilder.Entity("ColaFlow.Modules.ProjectManagement.Domain.Aggregates.ProjectAggregate.Epic", b => { b.HasOne("ColaFlow.Modules.ProjectManagement.Domain.Aggregates.ProjectAggregate.Project", null) diff --git a/colaflow-api/src/Modules/ProjectManagement/ColaFlow.Modules.ProjectManagement.Infrastructure/Persistence/Configurations/AuditLogConfiguration.cs b/colaflow-api/src/Modules/ProjectManagement/ColaFlow.Modules.ProjectManagement.Infrastructure/Persistence/Configurations/AuditLogConfiguration.cs new file mode 100644 index 0000000..6c241c0 --- /dev/null +++ b/colaflow-api/src/Modules/ProjectManagement/ColaFlow.Modules.ProjectManagement.Infrastructure/Persistence/Configurations/AuditLogConfiguration.cs @@ -0,0 +1,80 @@ +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; +using ColaFlow.Modules.ProjectManagement.Domain.Entities; +using ColaFlow.Modules.ProjectManagement.Domain.ValueObjects; + +namespace ColaFlow.Modules.ProjectManagement.Infrastructure.Persistence.Configurations; + +/// +/// Entity configuration for AuditLog +/// Configures multi-tenant isolation, JSONB columns, and composite indexes +/// +public class AuditLogConfiguration : IEntityTypeConfiguration +{ + public void Configure(EntityTypeBuilder builder) + { + builder.ToTable("AuditLogs"); + + // Primary key + builder.HasKey(a => a.Id); + + builder.Property(a => a.Id) + .IsRequired() + .ValueGeneratedNever(); + + // TenantId conversion (StronglyTypedId to Guid) + builder.Property(a => a.TenantId) + .HasConversion( + id => id.Value, + value => TenantId.From(value)) + .IsRequired(); + + // EntityType - the type name of the entity being audited + builder.Property(a => a.EntityType) + .IsRequired() + .HasMaxLength(100); + + // EntityId - the ID of the entity being audited + builder.Property(a => a.EntityId) + .IsRequired(); + + // Action - Create, Update, Delete + builder.Property(a => a.Action) + .IsRequired() + .HasMaxLength(20); + + // UserId conversion (nullable StronglyTypedId to Guid) + builder.Property(a => a.UserId) + .HasConversion( + id => id != null ? id.Value : (Guid?)null, + value => value.HasValue ? UserId.From(value.Value) : null); + + // Timestamp with UTC + builder.Property(a => a.Timestamp) + .IsRequired(); + + // OldValues as JSONB (PostgreSQL-specific) + builder.Property(a => a.OldValues) + .HasColumnType("jsonb"); + + // NewValues as JSONB (PostgreSQL-specific) + builder.Property(a => a.NewValues) + .HasColumnType("jsonb"); + + // Composite index for efficient entity history queries + // Query pattern: Get all audit logs for a specific entity within a tenant + builder.HasIndex(a => new { a.TenantId, a.EntityType, a.EntityId }) + .HasDatabaseName("IX_AuditLogs_TenantId_EntityType_EntityId"); + + // Index for recent logs queries (DESC order for performance) + // Query pattern: Get most recent audit logs across all entities + builder.HasIndex(a => a.Timestamp) + .HasDatabaseName("IX_AuditLogs_Timestamp") + .IsDescending(); + + // Index for user activity tracking + // Query pattern: Get all actions performed by a specific user + builder.HasIndex(a => a.UserId) + .HasDatabaseName("IX_AuditLogs_UserId"); + } +} diff --git a/colaflow-api/src/Modules/ProjectManagement/ColaFlow.Modules.ProjectManagement.Infrastructure/Persistence/PMDbContext.cs b/colaflow-api/src/Modules/ProjectManagement/ColaFlow.Modules.ProjectManagement.Infrastructure/Persistence/PMDbContext.cs index 62ce26d..192eeeb 100644 --- a/colaflow-api/src/Modules/ProjectManagement/ColaFlow.Modules.ProjectManagement.Infrastructure/Persistence/PMDbContext.cs +++ b/colaflow-api/src/Modules/ProjectManagement/ColaFlow.Modules.ProjectManagement.Infrastructure/Persistence/PMDbContext.cs @@ -2,6 +2,7 @@ using System.Reflection; using Microsoft.AspNetCore.Http; using Microsoft.EntityFrameworkCore; using ColaFlow.Modules.ProjectManagement.Domain.Aggregates.ProjectAggregate; +using ColaFlow.Modules.ProjectManagement.Domain.Entities; using ColaFlow.Modules.ProjectManagement.Domain.ValueObjects; namespace ColaFlow.Modules.ProjectManagement.Infrastructure.Persistence; @@ -23,6 +24,7 @@ public class PMDbContext : DbContext public DbSet Epics => Set(); public DbSet Stories => Set(); public DbSet Tasks => Set(); + public DbSet AuditLogs => Set(); protected override void OnModelCreating(ModelBuilder modelBuilder) { @@ -46,6 +48,9 @@ public class PMDbContext : DbContext modelBuilder.Entity().HasQueryFilter(t => t.TenantId == GetCurrentTenantId()); + + modelBuilder.Entity().HasQueryFilter(a => + a.TenantId == GetCurrentTenantId()); } private TenantId GetCurrentTenantId() diff --git a/docs/plans/sprint_2_story_1_task_1.md b/docs/plans/sprint_2_story_1_task_1.md index 9a4e433..2322e1e 100644 --- a/docs/plans/sprint_2_story_1_task_1.md +++ b/docs/plans/sprint_2_story_1_task_1.md @@ -1,9 +1,10 @@ --- task_id: sprint_2_story_1_task_1 story: sprint_2_story_1 -status: not_started +status: in_progress estimated_hours: 4 created_date: 2025-11-05 +start_date: 2025-11-05 assignee: Backend Team ---