From 5fb67df9ac43a82f1dd04fa69a2cc602c08df63b Mon Sep 17 00:00:00 2001 From: Hermes Agent Date: Sun, 4 Oct 2026 10:11:28 +0200 Subject: [PATCH] Refactored organisation entities and endpoints --- .../Governance/CreateOrganisationEndpoint.cs | 1 + .../Endpoints/Governance/GetTenantEndpoint.cs | 2 +- .../GetTenantOrganisationsEndpoint.cs | 36 + .../Services/IGovernanceService.cs | 2 +- .../Governance/GovernanceCacheService.cs | 8 +- .../Services/Governance/GovernanceService.cs | 45 +- .../Services/Governance/Records.cs | 4 + .../Entities/Organisation.cs | 9 + PostFundManagement.Domain/Entities/User.cs | 1 + .../Extensions/Mappers.cs | 12 +- .../Models/Organisation.cs | 2 + PostFundManagement.Domain/Models/User.cs | 2 + .../Database/ApplicationDbContext.cs | 8 +- ...dNumberTenantOrgAndUserObjects.Designer.cs | 2473 +++++++++++++++++ ...serIdAndIdNumberTenantOrgAndUserObjects.cs | 60 + .../ApplicationDbContextModelSnapshot.cs | 16 + .../Database/Services/TenantContextService.cs | 3 + 17 files changed, 2664 insertions(+), 20 deletions(-) create mode 100644 PostFundManagement.Api/Endpoints/Governance/GetTenantOrganisationsEndpoint.cs create mode 100644 PostFundManagement.Infrastructure/Database/Migrations/20261004075524_AddedUserIdAndIdNumberTenantOrgAndUserObjects.Designer.cs create mode 100644 PostFundManagement.Infrastructure/Database/Migrations/20261004075524_AddedUserIdAndIdNumberTenantOrgAndUserObjects.cs diff --git a/PostFundManagement.Api/Endpoints/Governance/CreateOrganisationEndpoint.cs b/PostFundManagement.Api/Endpoints/Governance/CreateOrganisationEndpoint.cs index 5f9c473..091e28b 100644 --- a/PostFundManagement.Api/Endpoints/Governance/CreateOrganisationEndpoint.cs +++ b/PostFundManagement.Api/Endpoints/Governance/CreateOrganisationEndpoint.cs @@ -19,6 +19,7 @@ public sealed class CreateOrganisationEndpoint : IEndpoint await service.CreateOrganisationAsync(request, context.GetUserId(), cancellationToken) switch { { IsSuccess: true } => Results.Ok(), + var r when r.HasError() => Results.BadRequest(r.Errors.ToProblems()), var r when r.HasError() => Results.BadRequest(r.Errors.ToProblems()), var r => Results.InternalServerError(r.Errors.ToProblems()) }) diff --git a/PostFundManagement.Api/Endpoints/Governance/GetTenantEndpoint.cs b/PostFundManagement.Api/Endpoints/Governance/GetTenantEndpoint.cs index 5ac8bdb..4a8b71b 100644 --- a/PostFundManagement.Api/Endpoints/Governance/GetTenantEndpoint.cs +++ b/PostFundManagement.Api/Endpoints/Governance/GetTenantEndpoint.cs @@ -23,7 +23,7 @@ public sealed class GetTenantEndpoint : IEndpoint var r when r.HasError() => Results.NotFound(r.Errors.ToProblems()), var r => Results.InternalServerError(r.Errors.ToProblems()) }) - .WithDescription("Gets system tenants") + .WithDescription("Gets a single tenant") .RequireAuthorization(Constants.MainScope) .WithName(typeof(GetTenantsEndpoint).ToEndpointName()) .MapToApiVersion(new ApiVersion(1)) diff --git a/PostFundManagement.Api/Endpoints/Governance/GetTenantOrganisationsEndpoint.cs b/PostFundManagement.Api/Endpoints/Governance/GetTenantOrganisationsEndpoint.cs new file mode 100644 index 0000000..f1251aa --- /dev/null +++ b/PostFundManagement.Api/Endpoints/Governance/GetTenantOrganisationsEndpoint.cs @@ -0,0 +1,36 @@ +using PostFundManagement.Application.Abstractions.Services; +using PostFundManagement.Application.Extensions; +using PostFundManagement.Domain.Abstractions; +using PostFundManagement.Domain.Entities; +using PostFundManagement.Domain.Errors; +using PostFundManagement.Domain.Extensions; +using PostFundManagement.Domain.Security; +using StackExchange.Redis; +using Problems = Microsoft.AspNetCore.Mvc.ProblemDetails; + +namespace PostFundManagement.Api.Endpoints.Governance; + +[ApiVersionTarget(1)] +public sealed class GetTenantOrganisationsEndpoint : IEndpoint +{ + public void Map(IEndpointRouteBuilder builder) + { + builder.MapGet("api/governance/tenants/{tenantIdHash}/organisations", async (IGovernanceService service, string tenantIdHash, + CancellationToken cancellationToken = default) => + await service.GetTenantOrganisationsAsync(tenantIdHash, cancellationToken) switch + { + { IsSuccess: true, Value: var tenantOrganisations } => Results.Ok(tenantOrganisations), + var r when r.HasError() => Results.Forbid(), + var r => Results.InternalServerError(r.Errors.ToProblems()) + }) + .WithDescription("Gets organisations created and managed by one tenant") + .RequireAuthorization(Constants.MainScope) + .WithName(typeof(GetTenantOrganisationsEndpoint).ToEndpointName("Retrieval")) + .MapToApiVersion(new ApiVersion(1)) + .Produces(StatusCodes.Status200OK) + .Produces(StatusCodes.Status403Forbidden) + .Produces(StatusCodes.Status401Unauthorized) + .Produces(StatusCodes.Status500InternalServerError) + .WithTags(EndpointTags.Governance); + } +} diff --git a/PostFundManagement.Application/Abstractions/Services/IGovernanceService.cs b/PostFundManagement.Application/Abstractions/Services/IGovernanceService.cs index cf99b32..f82d6fa 100644 --- a/PostFundManagement.Application/Abstractions/Services/IGovernanceService.cs +++ b/PostFundManagement.Application/Abstractions/Services/IGovernanceService.cs @@ -91,7 +91,7 @@ public interface IGovernanceService Task UpdateTenantOrganisationAsync(string tenantOrganisationIdHash, ActivityStatus status, Guid userId, CancellationToken cancellationToken = default); [Log] - Task> GetTenantOrganisationsAsync(CancellationToken cancellationToken = default); + Task> GetTenantOrganisationsAsync(string tenantIdHash, CancellationToken cancellationToken = default); [Log] Task> GetTenantOrganisationAsync(string tenantOrganisationIdHash, CancellationToken cancellationToken = default); diff --git a/PostFundManagement.Application/Services/Governance/GovernanceCacheService.cs b/PostFundManagement.Application/Services/Governance/GovernanceCacheService.cs index 51578b7..f23dcda 100644 --- a/PostFundManagement.Application/Services/Governance/GovernanceCacheService.cs +++ b/PostFundManagement.Application/Services/Governance/GovernanceCacheService.cs @@ -266,19 +266,19 @@ public sealed class GovernanceCacheService(GovernanceService service, IDistribut return Result.Ok(cached.FromJson()); })); - public async Task> GetTenantOrganisationsAsync(CancellationToken cancellationToken = default) => + public async Task> GetTenantOrganisationsAsync(string tenantIdHash, CancellationToken cancellationToken = default) => await Result.Try((Func>>)(async () => { if (!await featureManager.IsEnabledAsync(ServiceCachingFeature)) - return await service.GetTenantOrganisationsAsync(cancellationToken); + return await service.GetTenantOrganisationsAsync(tenantIdHash, cancellationToken); - var cacheKey = HashService.ToMd5Hash($"gettenantorganisations").Value; + var cacheKey = HashService.ToMd5Hash($"gettenantorganisations-{tenantIdHash}").Value; var cached = await cache.GetStringAsync(cacheKey, cancellationToken); if (string.IsNullOrWhiteSpace(cached)) { - var result = await service.GetTenantOrganisationsAsync(cancellationToken); + var result = await service.GetTenantOrganisationsAsync(tenantIdHash, cancellationToken); if (result.IsFailed) return result; diff --git a/PostFundManagement.Application/Services/Governance/GovernanceService.cs b/PostFundManagement.Application/Services/Governance/GovernanceService.cs index 9fbc489..a8ea813 100644 --- a/PostFundManagement.Application/Services/Governance/GovernanceService.cs +++ b/PostFundManagement.Application/Services/Governance/GovernanceService.cs @@ -138,8 +138,14 @@ public sealed class GovernanceService(IDbContextFactory co var registrationNo = request.RegistrationNo.Clean(); + if(!await context.Users.AnyAsync(u => u.Id == request.OrganisationUser, cancellationToken)) + return Result.Fail(NotFoundError.Create("Organisation user not found")); + + if(!await context.TenantUsers.AnyAsync(u => u.UserId == request.OrganisationUser && u.TenantId == tenantContext.TenantId, cancellationToken)) + return Result.Fail(ValidationError.Create("Organisation user does not belong to the current tenant")); + if (await context.Organisations.AnyAsync(o => o.RegistrationNo == registrationNo, cancellationToken)) - return Result.Fail(CreateError.Create("Organisation with the same registration number already exists")); + return Result.Fail(ValidationError.Create("Organisation with the same registration number already exists")); var organisation = context.Organisations.Add(new Domain.Entities.Organisation { @@ -149,9 +155,17 @@ public sealed class GovernanceService(IDbContextFactory co Type = request.Type, Status = ActivityStatus.Active, CreatedBy = userId, - CreatedAt = DateTime.UtcNow + CreatedAt = DateTime.UtcNow, + UserId = request.OrganisationUser }); + if(!string.IsNullOrWhiteSpace(request.IdNumber)) + { + var linkedUser = await context.Users.FirstOrDefaultAsync(u => u.Id == request.OrganisationUser, cancellationToken); + + linkedUser!.IdNumber = request.IdNumber.Clean(); + } + await context.SaveChangesAsync(cancellationToken); var mapResult = await CreateTenantOrganisationAsync(hashService.HashEncodeLongId(organisation.Entity.Id).Value, @@ -165,6 +179,12 @@ public sealed class GovernanceService(IDbContextFactory co { await using var context = await contextFactory.CreateDbContextAsync(cancellationToken); + if (!await context.Users.AnyAsync(u => u.Id == request.OrganisationUser, cancellationToken)) + return Result.Fail(ValidationError.Create("Organisation user not found")); + + if (!await context.TenantUsers.AnyAsync(u => u.UserId == request.OrganisationUser && u.TenantId == tenantContext.TenantId, cancellationToken)) + return Result.Fail(ValidationError.Create("Organisation user does not belong to the current tenant")); + var changedTotal = await context.Organisations .Where(f => f.Id == request.OrganisationId) .ExecuteUpdateAsync(f => f @@ -181,7 +201,16 @@ public sealed class GovernanceService(IDbContextFactory co var updateResult = await UpdateTenantOrganisationAsync(hashService.HashEncodeLongId(tenantOrganisation.Id).Value, request.Status, userId, cancellationToken); - return Result.OkIf(changedTotal > 0 && updateResult.IsSuccess, UpdateError.Create("Failed to update organisation")); + if (!string.IsNullOrWhiteSpace(request.IdNumber)) + { + var linkedUser = await context.Users.FirstOrDefaultAsync(u => u.Id == request.OrganisationUser, cancellationToken); + + linkedUser!.IdNumber = request.IdNumber.Clean(); + } + + var userUpdated = await context.SaveChangesAsync(cancellationToken) > 0; + + return Result.OkIf(changedTotal > 0 && updateResult.IsSuccess && userUpdated, UpdateError.Create("Failed to update organisation")); })); public async Task CreatePortfolioAsync(CreatePortfolioRequest request, Guid userId, CancellationToken cancellationToken = default) => @@ -403,15 +432,21 @@ public sealed class GovernanceService(IDbContextFactory co return Result.OkIf(changedTotal > 0, UpdateError.Create("Failed to update tenant organisation map")); })); - public async Task> GetTenantOrganisationsAsync(CancellationToken cancellationToken = default) => + public async Task> GetTenantOrganisationsAsync(string tenantIdHash, CancellationToken cancellationToken = default) => await Result.Try((Func>>)(async () => { + var decodeResult = hashService.DecodeLongIdHash(tenantIdHash); + + if (decodeResult.IsFailed) + return Result.Fail(IdDecodeError.Create() + .CausedBy(decodeResult.Errors)); + await using var context = await contextFactory.CreateDbContextAsync(cancellationToken); var tenantOrganisations = await context.TenantOrganisations.AsNoTracking() .Include(i => i.Organisation) .Include(i => i.Tenant) - .Where(f => f.TenantId == tenantContext.TenantId) + .Where(f => f.TenantId == decodeResult.Value) .ToListAsync(); return Result.Ok(tenantOrganisations?.Select(i => i.Map()).ToArray() ?? []); diff --git a/PostFundManagement.Application/Services/Governance/Records.cs b/PostFundManagement.Application/Services/Governance/Records.cs index 51cc316..c777605 100644 --- a/PostFundManagement.Application/Services/Governance/Records.cs +++ b/PostFundManagement.Application/Services/Governance/Records.cs @@ -38,12 +38,16 @@ public sealed record UpdateOrganisationRequest([Required] long OrganisationId, [Required][MaxLength(LabelLength)] string Name, [Required][MaxLength(LabelLength)] string RegistrationNo, [Required][EmailAddress][MaxLength(LabelLength)] string Email, + [Required][EmailAddress][MaxLength(LabelLength)] string IdNumber, + [Required] Guid OrganisationUser, [Required] OrganisationType Type, [Required] ActivityStatus Status); public sealed record CreateOrganisationRequest([Required][MaxLength(LabelLength)] string Name, [Required][MaxLength(LabelLength)] string RegistrationNo, [Required][EmailAddress][MaxLength(LabelLength)] string Email, + [Required][EmailAddress][MaxLength(LabelLength)] string IdNumber, + [Required] Guid OrganisationUser, [Required] OrganisationType Type = OrganisationType.PrivateLimitedCompany); public sealed record Dashboard([Required] decimal PortfolioValue, diff --git a/PostFundManagement.Domain/Entities/Organisation.cs b/PostFundManagement.Domain/Entities/Organisation.cs index eb8a2ef..fce062b 100644 --- a/PostFundManagement.Domain/Entities/Organisation.cs +++ b/PostFundManagement.Domain/Entities/Organisation.cs @@ -5,6 +5,8 @@ namespace PostFundManagement.Domain.Entities; [EntityTypeConfiguration] public class Organisation : Models.Organisation { + public virtual User? User { get; set; } + public virtual User? Creator { get; set; } } @@ -16,6 +18,7 @@ public sealed class OrganisationConfiguration : IEntityTypeConfiguration pk.Id); builder.Property(f => f.CreatedBy).IsRequired(); + builder.Property(f => f.UserId).IsRequired(false); builder.Property(f => f.CreatedAt).IsRequired().HasDefaultValueSql("now()"); builder.Property(f => f.RegistrationNo).IsRequired().HasMaxLength(LabelLength); builder.Property(f => f.Name).IsRequired().HasMaxLength(LabelLength); @@ -25,6 +28,12 @@ public sealed class OrganisationConfiguration : IEntityTypeConfiguration f.Status).IsRequired().HasConversion().HasDefaultValueSql("1") .HasSentinel(ActivityStatus.Active); + builder.HasOne(f => f.User) + .WithMany() + .HasForeignKey(fk => fk.UserId) + .IsRequired(false) + .OnDelete(DeleteBehavior.NoAction); + builder.HasOne(f => f.Creator) .WithMany() .HasForeignKey(fk => fk.CreatedBy) diff --git a/PostFundManagement.Domain/Entities/User.cs b/PostFundManagement.Domain/Entities/User.cs index 01f9f94..270427f 100644 --- a/PostFundManagement.Domain/Entities/User.cs +++ b/PostFundManagement.Domain/Entities/User.cs @@ -14,6 +14,7 @@ public sealed class UserConfiguration : IEntityTypeConfiguration builder.HasKey(pk => pk.Id); builder.Property(f => f.Email).IsRequired().HasMaxLength(LabelLength); builder.Property(f => f.Role).IsRequired(false).HasMaxLength(LabelLength); + builder.Property(f => f.IdNumber).IsRequired(false).HasMaxLength(LabelLength); builder.Property(f => f.Status).IsRequired().HasConversion().HasDefaultValueSql("2") .HasSentinel(ActivityStatus.Inactive); builder.Property(f => f.LastLoginAt).IsRequired(false); diff --git a/PostFundManagement.Domain/Extensions/Mappers.cs b/PostFundManagement.Domain/Extensions/Mappers.cs index 7c4efcc..ab850bc 100644 --- a/PostFundManagement.Domain/Extensions/Mappers.cs +++ b/PostFundManagement.Domain/Extensions/Mappers.cs @@ -11,7 +11,7 @@ public static class Mappers CreatedAt = entity.CreatedAt, CreatedBy = entity.CreatedBy, Status = entity.Status, - UserId = entity.UserId + UserId = entity.UserId }; public static TenantOrganisation Map(this Entities.TenantOrganisation entity) => new() @@ -21,7 +21,7 @@ public static class Mappers CreatedAt = entity.CreatedAt, CreatedBy = entity.CreatedBy, OrganisationId = entity.OrganisationId, - TenantId = entity.TenantId + TenantId = entity.TenantId }; public static Tenant Map(this Entities.Tenant entity) => new() @@ -32,7 +32,7 @@ public static class Mappers CreatedBy = entity.CreatedBy, Status = entity.Status, UpdatedAt = entity.UpdatedAt, - UpdatedBy = entity.UpdatedBy + UpdatedBy = entity.UpdatedBy }; public static Activity Map(this Entities.Activity entity) => new() @@ -270,7 +270,8 @@ public static class Mappers Name = entity.Name, RegistrationNo = entity.RegistrationNo, Status = entity.Status, - Type = entity.Type + Type = entity.Type, + UserId = entity.UserId }; public static Outcome Map(this Entities.Outcome entity) => new() @@ -392,6 +393,7 @@ public static class Mappers Email = entity.Email, LastLoginAt = entity.LastLoginAt, Status = entity.Status, - Role = entity.Role + Role = entity.Role, + IdNumber = entity.IdNumber }; } \ No newline at end of file diff --git a/PostFundManagement.Domain/Models/Organisation.cs b/PostFundManagement.Domain/Models/Organisation.cs index b3e1821..701eee7 100644 --- a/PostFundManagement.Domain/Models/Organisation.cs +++ b/PostFundManagement.Domain/Models/Organisation.cs @@ -14,6 +14,8 @@ public class Organisation public string? Email { get; set; } + public Guid? UserId { get; set; } + public OrganisationType Type { get; set; } public ActivityStatus Status { get; set; } diff --git a/PostFundManagement.Domain/Models/User.cs b/PostFundManagement.Domain/Models/User.cs index b4421f6..a5f701a 100644 --- a/PostFundManagement.Domain/Models/User.cs +++ b/PostFundManagement.Domain/Models/User.cs @@ -10,5 +10,7 @@ public class User public string? Role { get; set; } + public string? IdNumber { get; set; } + public ActivityStatus Status { get; set; } } \ No newline at end of file diff --git a/PostFundManagement.Infrastructure/Database/ApplicationDbContext.cs b/PostFundManagement.Infrastructure/Database/ApplicationDbContext.cs index 8e8415d..92c806b 100644 --- a/PostFundManagement.Infrastructure/Database/ApplicationDbContext.cs +++ b/PostFundManagement.Infrastructure/Database/ApplicationDbContext.cs @@ -6,7 +6,7 @@ namespace PostFundManagement.Infrastructure.Database; public sealed class ApplicationDbContext(DbContextOptions options, ITenantContextService tenantService) : DbContext(options) { - private bool BypassFilter => tenantService.IsAdmin || tenantService.ByPassTenantQueryFilter; + private bool BypassFilter => tenantService.ByPassTenantQueryFilter; private long CurrentTenantId => tenantService.TenantId; public DbSet TenantUsers => Set(); @@ -84,14 +84,14 @@ public sealed class ApplicationDbContext(DbContextOptions } } - modelBuilder.Entity().HasQueryFilter(o => BypassFilter == false && + modelBuilder.Entity().HasQueryFilter(o => BypassFilter || Set().Any(to => to.TenantId == CurrentTenantId && to.OrganisationId == o.Id)); modelBuilder.Entity() - .HasQueryFilter(to => BypassFilter == false && to.TenantId == CurrentTenantId); + .HasQueryFilter(to => BypassFilter || to.TenantId == CurrentTenantId); modelBuilder.Entity() - .HasQueryFilter(to => BypassFilter == false && to.TenantId == CurrentTenantId); + .HasQueryFilter(to => BypassFilter || to.TenantId == CurrentTenantId); } public override Task SaveChangesAsync(CancellationToken cancellationToken = default) diff --git a/PostFundManagement.Infrastructure/Database/Migrations/20261004075524_AddedUserIdAndIdNumberTenantOrgAndUserObjects.Designer.cs b/PostFundManagement.Infrastructure/Database/Migrations/20261004075524_AddedUserIdAndIdNumberTenantOrgAndUserObjects.Designer.cs new file mode 100644 index 0000000..14acda3 --- /dev/null +++ b/PostFundManagement.Infrastructure/Database/Migrations/20261004075524_AddedUserIdAndIdNumberTenantOrgAndUserObjects.Designer.cs @@ -0,0 +1,2473 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; +using PostFundManagement.Infrastructure.Database; + +#nullable disable + +namespace PostFundManagement.Infrastructure.Database.Migrations +{ + [DbContext(typeof(ApplicationDbContext))] + [Migration("20261004075524_AddedUserIdAndIdNumberTenantOrgAndUserObjects")] + partial class AddedUserIdAndIdNumberTenantOrgAndUserObjects + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "10.0.12") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("PostFundManagement.Domain.Entities.Activity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Amount") + .HasPrecision(18, 2) + .HasColumnType("numeric(18,2)"); + + b.Property("ApprovedBy") + .HasColumnType("uuid"); + + b.Property("Category") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("CreatedAt") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasDefaultValueSql("now()"); + + b.Property("CreatedBy") + .HasColumnType("uuid"); + + b.Property("Description") + .IsRequired() + .HasMaxLength(1024) + .HasColumnType("character varying(1024)"); + + b.Property("MilestoneId") + .HasColumnType("bigint"); + + b.Property("PerformedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ProjectId") + .HasColumnType("bigint"); + + b.Property("Status") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasDefaultValueSql("1"); + + b.Property("TenantId") + .HasColumnType("bigint"); + + b.Property("Title") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("UpdatedBy") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("ApprovedBy"); + + b.HasIndex("CreatedBy"); + + b.HasIndex("MilestoneId"); + + b.HasIndex("ProjectId"); + + b.HasIndex("TenantId"); + + b.HasIndex("UpdatedBy"); + + b.ToTable("Activities", (string)null); + }); + + modelBuilder.Entity("PostFundManagement.Domain.Entities.AuditLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Action") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.PrimitiveCollection("Changes") + .HasColumnType("text[]"); + + b.Property("EntityId") + .IsRequired() + .HasColumnType("text"); + + b.Property("EntityName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("PerformedBy") + .HasColumnType("uuid"); + + b.Property("TenantId") + .HasColumnType("bigint"); + + b.Property("Timestamp") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasDefaultValueSql("now()"); + + b.HasKey("Id"); + + b.ToTable("AuditLogs", (string)null); + }); + + modelBuilder.Entity("PostFundManagement.Domain.Entities.Award", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Amount") + .HasPrecision(18, 2) + .HasColumnType("numeric(18,2)"); + + b.Property("ApprovedBy") + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasDefaultValueSql("now()"); + + b.Property("CreatedBy") + .HasColumnType("uuid"); + + b.Property("OrganisationId") + .HasColumnType("bigint"); + + b.Property("ProgrammeId") + .HasColumnType("bigint"); + + b.Property("ProjectId") + .HasColumnType("bigint"); + + b.Property("Status") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasDefaultValueSql("1"); + + b.Property("TenantId") + .HasColumnType("bigint"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("UpdatedBy") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("ApprovedBy"); + + b.HasIndex("CreatedBy"); + + b.HasIndex("OrganisationId"); + + b.HasIndex("ProgrammeId"); + + b.HasIndex("ProjectId"); + + b.HasIndex("TenantId"); + + b.HasIndex("UpdatedBy"); + + b.ToTable("Awards", (string)null); + }); + + modelBuilder.Entity("PostFundManagement.Domain.Entities.Beneficiary", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Category") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("CreatedAt") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasDefaultValueSql("now()"); + + b.Property("CreatedBy") + .HasColumnType("uuid"); + + b.Property("Location") + .IsRequired() + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("ProjectId") + .HasColumnType("bigint"); + + b.Property("ReachedCount") + .HasColumnType("integer"); + + b.Property("TargetCount") + .HasColumnType("integer"); + + b.Property("TenantId") + .HasColumnType("bigint"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("CreatedBy"); + + b.HasIndex("ProjectId"); + + b.HasIndex("TenantId"); + + b.HasIndex("UserId"); + + b.ToTable("Beneficiaries", (string)null); + }); + + modelBuilder.Entity("PostFundManagement.Domain.Entities.Budget", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Amount") + .HasPrecision(18, 2) + .HasColumnType("numeric(18,2)"); + + b.Property("ApprovedBy") + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasDefaultValueSql("now()"); + + b.Property("CreatedBy") + .HasColumnType("uuid"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("ProjectId") + .HasColumnType("bigint"); + + b.Property("Status") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasDefaultValueSql("1"); + + b.Property("TenantId") + .HasColumnType("bigint"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("ApprovedBy"); + + b.HasIndex("CreatedBy"); + + b.HasIndex("ProjectId"); + + b.HasIndex("TenantId"); + + b.ToTable("Budgets", (string)null); + }); + + modelBuilder.Entity("PostFundManagement.Domain.Entities.ChangeRequest", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ApprovedBy") + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasDefaultValueSql("now()"); + + b.Property("CreatedBy") + .HasColumnType("uuid"); + + b.Property("Justification") + .IsRequired() + .HasMaxLength(1024) + .HasColumnType("character varying(1024)"); + + b.Property("ProjectId") + .HasColumnType("bigint"); + + b.Property("RevisedBudget") + .HasPrecision(18, 2) + .HasColumnType("numeric(18,2)"); + + b.Property("RevisedEndedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Status") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasDefaultValueSql("1"); + + b.Property("TenantId") + .HasColumnType("bigint"); + + b.Property("Title") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("ApprovedBy"); + + b.HasIndex("CreatedBy"); + + b.HasIndex("ProjectId"); + + b.HasIndex("TenantId"); + + b.ToTable("ChangeRequests", (string)null); + }); + + modelBuilder.Entity("PostFundManagement.Domain.Entities.ComplianceItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedAt") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasDefaultValueSql("now()"); + + b.Property("CreatedBy") + .HasColumnType("uuid"); + + b.Property("ProjectId") + .HasColumnType("bigint"); + + b.Property("Requirements") + .IsRequired() + .HasMaxLength(2048) + .HasColumnType("character varying(2048)"); + + b.Property("Status") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasDefaultValueSql("1"); + + b.Property("TenantId") + .HasColumnType("bigint"); + + b.Property("Title") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("VerifiedBy") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("CreatedBy"); + + b.HasIndex("ProjectId"); + + b.HasIndex("TenantId"); + + b.HasIndex("VerifiedBy"); + + b.ToTable("ComplianceItems", (string)null); + }); + + modelBuilder.Entity("PostFundManagement.Domain.Entities.Contract", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AwardId") + .HasColumnType("bigint"); + + b.Property("CreatedAt") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasDefaultValueSql("now()"); + + b.Property("CreatedBy") + .HasColumnType("uuid"); + + b.Property("EffectiveAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ExpiresAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ExternalSignatureId") + .HasColumnType("text"); + + b.Property("SignedDocumentUrl") + .HasColumnType("text"); + + b.Property("Status") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasDefaultValueSql("1"); + + b.Property("TenantId") + .HasColumnType("bigint"); + + b.Property("TotalValue") + .HasPrecision(18, 2) + .HasColumnType("numeric(18,2)"); + + b.HasKey("Id"); + + b.HasIndex("AwardId") + .IsUnique(); + + b.HasIndex("CreatedBy"); + + b.HasIndex("TenantId"); + + b.ToTable("Contracts", (string)null); + }); + + modelBuilder.Entity("PostFundManagement.Domain.Entities.Disbursement", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Amount") + .HasPrecision(18, 2) + .HasColumnType("numeric(18,2)"); + + b.Property("CreatedAt") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasDefaultValueSql("now()"); + + b.Property("CreatedBy") + .HasColumnType("uuid"); + + b.Property("MilestoneId") + .HasColumnType("bigint"); + + b.Property("ProjectId") + .HasColumnType("bigint"); + + b.Property("Status") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasDefaultValueSql("1"); + + b.Property("TenantId") + .HasColumnType("bigint"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("UpdatedBy") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("CreatedBy"); + + b.HasIndex("MilestoneId"); + + b.HasIndex("ProjectId"); + + b.HasIndex("TenantId"); + + b.HasIndex("UpdatedBy"); + + b.ToTable("Disbursements", (string)null); + }); + + modelBuilder.Entity("PostFundManagement.Domain.Entities.Evidence", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ActivityId") + .HasColumnType("bigint"); + + b.Property("CreatedAt") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasDefaultValueSql("now()"); + + b.Property("CreatedBy") + .HasColumnType("uuid"); + + b.Property("DocumentUrl") + .IsRequired() + .HasColumnType("text"); + + b.Property("IndicatorId") + .HasColumnType("bigint"); + + b.Property("MilestoneId") + .HasColumnType("bigint"); + + b.Property("ProjectId") + .HasColumnType("bigint"); + + b.Property("Status") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasDefaultValueSql("1"); + + b.Property("TenantId") + .HasColumnType("bigint"); + + b.Property("Type") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasDefaultValueSql("9"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("UpdatedBy") + .HasColumnType("uuid"); + + b.Property("Version") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasDefaultValue(1); + + b.HasKey("Id"); + + b.HasIndex("ActivityId"); + + b.HasIndex("CreatedBy"); + + b.HasIndex("IndicatorId"); + + b.HasIndex("MilestoneId"); + + b.HasIndex("ProjectId"); + + b.HasIndex("TenantId"); + + b.HasIndex("UpdatedBy"); + + b.ToTable("Evidences", (string)null); + }); + + modelBuilder.Entity("PostFundManagement.Domain.Entities.Indicator", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ActualAmount") + .HasPrecision(18, 2) + .HasColumnType("numeric(18,2)"); + + b.Property("BaselineAmount") + .HasPrecision(18, 2) + .HasColumnType("numeric(18,2)"); + + b.Property("CreatedAt") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasDefaultValueSql("now()"); + + b.Property("CreatedBy") + .HasColumnType("uuid"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("ProjectId") + .HasColumnType("bigint"); + + b.Property("TargetAmount") + .HasPrecision(18, 2) + .HasColumnType("numeric(18,2)"); + + b.Property("TenantId") + .HasColumnType("bigint"); + + b.Property("UnitOfMeasure") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasDefaultValueSql("2"); + + b.HasKey("Id"); + + b.HasIndex("CreatedBy"); + + b.HasIndex("ProjectId"); + + b.HasIndex("TenantId"); + + b.ToTable("Indicators", (string)null); + }); + + modelBuilder.Entity("PostFundManagement.Domain.Entities.Instrument", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Code") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("CreatedAt") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasDefaultValueSql("now()"); + + b.Property("CreatedBy") + .HasColumnType("uuid"); + + b.Property("Description") + .HasMaxLength(1024) + .HasColumnType("character varying(1024)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("ProgrammeId") + .HasColumnType("bigint"); + + b.Property("Status") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasDefaultValueSql("2"); + + b.Property("TenantId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("CreatedBy"); + + b.HasIndex("ProgrammeId"); + + b.HasIndex("TenantId"); + + b.ToTable("Instruments", (string)null); + }); + + modelBuilder.Entity("PostFundManagement.Domain.Entities.Invite", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AwardId") + .HasColumnType("bigint"); + + b.Property("ContractId") + .HasColumnType("bigint"); + + b.Property("CreatedAt") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasDefaultValueSql("now()"); + + b.Property("CreatedBy") + .HasColumnType("uuid"); + + b.Property("InvitedOrganisationId") + .HasColumnType("bigint"); + + b.Property("OrganisationId") + .HasColumnType("bigint"); + + b.Property("Recipient") + .HasColumnType("uuid"); + + b.Property("TenantId") + .HasColumnType("bigint"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("UpdatedBy") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("AwardId"); + + b.HasIndex("ContractId"); + + b.HasIndex("InvitedOrganisationId"); + + b.HasIndex("OrganisationId"); + + b.HasIndex("Recipient"); + + b.HasIndex("TenantId"); + + b.ToTable("Invites", (string)null); + }); + + modelBuilder.Entity("PostFundManagement.Domain.Entities.Issue", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AssignedTo") + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasDefaultValueSql("now()"); + + b.Property("CreatedBy") + .HasColumnType("uuid"); + + b.Property("Description") + .IsRequired() + .HasMaxLength(1024) + .HasColumnType("character varying(1024)"); + + b.Property("Priority") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasDefaultValueSql("1"); + + b.Property("ProjectId") + .HasColumnType("bigint"); + + b.Property("Resolution") + .HasColumnType("text"); + + b.Property("ResolvedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Status") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasDefaultValueSql("1"); + + b.Property("TenantId") + .HasColumnType("bigint"); + + b.Property("Title") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.HasKey("Id"); + + b.HasIndex("AssignedTo"); + + b.HasIndex("CreatedBy"); + + b.HasIndex("ProjectId"); + + b.HasIndex("TenantId"); + + b.ToTable("Issues", (string)null); + }); + + modelBuilder.Entity("PostFundManagement.Domain.Entities.Milestone", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedAt") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasDefaultValueSql("now()"); + + b.Property("CreatedBy") + .HasColumnType("uuid"); + + b.Property("DueAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("Priority") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasDefaultValueSql("1"); + + b.Property("ProjectId") + .HasColumnType("bigint"); + + b.Property("Status") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasDefaultValueSql("1"); + + b.Property("TenantId") + .HasColumnType("bigint"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("UpdatedBy") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("CreatedBy"); + + b.HasIndex("ProjectId"); + + b.HasIndex("TenantId"); + + b.HasIndex("UpdatedBy"); + + b.ToTable("Milestones", (string)null); + }); + + modelBuilder.Entity("PostFundManagement.Domain.Entities.Notification", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedAt") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasDefaultValueSql("now()"); + + b.Property("Destination") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("Error") + .HasColumnType("text"); + + b.Property("Message") + .IsRequired() + .HasMaxLength(4096) + .HasColumnType("character varying(4096)"); + + b.Property("OrganisationId") + .HasColumnType("bigint"); + + b.Property("Platform") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasDefaultValueSql("1"); + + b.Property("Recipient") + .HasColumnType("uuid"); + + b.Property("SentAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Status") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasDefaultValueSql("1"); + + b.Property("Subject") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("TenantId") + .HasColumnType("bigint"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("OrganisationId"); + + b.HasIndex("Recipient"); + + b.HasIndex("TenantId"); + + b.ToTable("Notifications", (string)null); + }); + + modelBuilder.Entity("PostFundManagement.Domain.Entities.Organisation", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedAt") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasDefaultValueSql("now()"); + + b.Property("CreatedBy") + .HasColumnType("uuid"); + + b.Property("Email") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("RegistrationNo") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("Status") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasDefaultValueSql("1"); + + b.Property("Type") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasDefaultValueSql("5"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("CreatedBy"); + + b.HasIndex("UserId"); + + b.ToTable("Organisations", (string)null); + }); + + modelBuilder.Entity("PostFundManagement.Domain.Entities.Outcome", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("BeneficiaryId") + .HasColumnType("bigint"); + + b.Property("CreatedAt") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasDefaultValueSql("now()"); + + b.Property("CreatedBy") + .HasColumnType("uuid"); + + b.Property("Description") + .IsRequired() + .HasMaxLength(1024) + .HasColumnType("character varying(1024)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("TenantId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("BeneficiaryId"); + + b.HasIndex("CreatedBy"); + + b.HasIndex("TenantId"); + + b.ToTable("Outcomes", (string)null); + }); + + modelBuilder.Entity("PostFundManagement.Domain.Entities.Portfolio", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedAt") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasDefaultValueSql("now()"); + + b.Property("CreatedBy") + .HasColumnType("uuid"); + + b.Property("Description") + .HasMaxLength(1024) + .HasColumnType("character varying(1024)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("OrganisationId") + .HasColumnType("bigint"); + + b.Property("OwnedBy") + .HasColumnType("uuid"); + + b.Property("TenantId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("CreatedBy"); + + b.HasIndex("OrganisationId"); + + b.HasIndex("OwnedBy"); + + b.HasIndex("TenantId"); + + b.ToTable("Portfolios", (string)null); + }); + + modelBuilder.Entity("PostFundManagement.Domain.Entities.Programme", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedAt") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasDefaultValueSql("now()"); + + b.Property("CreatedBy") + .HasColumnType("uuid"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("OwnedBy") + .HasColumnType("uuid"); + + b.Property("PortfolioId") + .HasColumnType("bigint"); + + b.Property("Status") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasDefaultValueSql("1"); + + b.Property("TenantId") + .HasColumnType("bigint"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("UpdatedBy") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("CreatedBy"); + + b.HasIndex("OwnedBy"); + + b.HasIndex("PortfolioId"); + + b.HasIndex("TenantId"); + + b.ToTable("Programmes", (string)null); + }); + + modelBuilder.Entity("PostFundManagement.Domain.Entities.Project", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedAt") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasDefaultValueSql("now()"); + + b.Property("CreatedBy") + .HasColumnType("uuid"); + + b.Property("Description") + .IsRequired() + .HasMaxLength(1024) + .HasColumnType("character varying(1024)"); + + b.Property("EndedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("ProgrammeId") + .HasColumnType("bigint"); + + b.Property("ProjectType") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasDefaultValueSql("10"); + + b.Property("Sector") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasDefaultValueSql("11"); + + b.Property("StartedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Status") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasDefaultValueSql("1"); + + b.Property("TenantId") + .HasColumnType("bigint"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("UpdatedBy") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("CreatedBy"); + + b.HasIndex("ProgrammeId"); + + b.HasIndex("TenantId"); + + b.HasIndex("UpdatedBy"); + + b.ToTable("Projects", (string)null); + }); + + modelBuilder.Entity("PostFundManagement.Domain.Entities.Risk", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedAt") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasDefaultValueSql("now()"); + + b.Property("CreatedBy") + .HasColumnType("uuid"); + + b.Property("Description") + .IsRequired() + .HasMaxLength(1024) + .HasColumnType("character varying(1024)"); + + b.Property("Impact") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasDefaultValueSql("1"); + + b.Property("Likelihood") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasDefaultValueSql("3"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("ProjectId") + .HasColumnType("bigint"); + + b.Property("TenantId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("CreatedBy"); + + b.HasIndex("ProjectId"); + + b.HasIndex("TenantId"); + + b.ToTable("Risks", (string)null); + }); + + modelBuilder.Entity("PostFundManagement.Domain.Entities.Rule", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedAt") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasDefaultValueSql("now()"); + + b.Property("CreatedBy") + .HasColumnType("uuid"); + + b.Property("Description") + .HasMaxLength(1024) + .HasColumnType("character varying(1024)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("ProgrammeId") + .HasColumnType("bigint"); + + b.Property("Status") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasDefaultValueSql("2"); + + b.Property("TenantId") + .HasColumnType("bigint"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("UpdatedBy") + .HasColumnType("uuid"); + + b.Property("Version") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasDefaultValue(1); + + b.HasKey("Id"); + + b.HasIndex("CreatedBy"); + + b.HasIndex("ProgrammeId"); + + b.HasIndex("TenantId"); + + b.HasIndex("UpdatedBy"); + + b.ToTable("Rules", (string)null); + }); + + modelBuilder.Entity("PostFundManagement.Domain.Entities.SiteVisit", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedAt") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasDefaultValueSql("now()"); + + b.Property("CreatedBy") + .HasColumnType("uuid"); + + b.Property("Findings") + .HasMaxLength(4096) + .HasColumnType("character varying(4096)"); + + b.Property("InspectorName") + .IsRequired() + .HasColumnType("text"); + + b.Property("ProjectId") + .HasColumnType("bigint"); + + b.Property("Status") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasDefaultValueSql("1"); + + b.Property("TenantId") + .HasColumnType("bigint"); + + b.Property("VisitedAt") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("CreatedBy"); + + b.HasIndex("ProjectId"); + + b.HasIndex("TenantId"); + + b.ToTable("SiteVisits", (string)null); + }); + + modelBuilder.Entity("PostFundManagement.Domain.Entities.Tenant", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedAt") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasDefaultValueSql("now()"); + + b.Property("CreatedBy") + .HasColumnType("uuid"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("Status") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasDefaultValueSql("1"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("UpdatedBy") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("CreatedBy"); + + b.HasIndex("UpdatedBy"); + + b.ToTable("Tenants", (string)null); + }); + + modelBuilder.Entity("PostFundManagement.Domain.Entities.TenantOrganisation", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedAt") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasDefaultValueSql("now()"); + + b.Property("CreatedBy") + .HasColumnType("uuid"); + + b.Property("OrganisationId") + .HasColumnType("bigint"); + + b.Property("Status") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasDefaultValueSql("1"); + + b.Property("TenantId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("CreatedBy"); + + b.HasIndex("OrganisationId"); + + b.HasIndex("TenantId"); + + b.ToTable("TenantOrganisations", (string)null); + }); + + modelBuilder.Entity("PostFundManagement.Domain.Entities.TenantUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedAt") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasDefaultValueSql("now()"); + + b.Property("CreatedBy") + .HasColumnType("uuid"); + + b.Property("Status") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasDefaultValueSql("1"); + + b.Property("TenantId") + .HasColumnType("bigint"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("CreatedBy"); + + b.HasIndex("TenantId"); + + b.HasIndex("UserId"); + + b.ToTable("TenantUsers", (string)null); + }); + + modelBuilder.Entity("PostFundManagement.Domain.Entities.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Email") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("IdNumber") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("LastLoginAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Role") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("Status") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasDefaultValueSql("2"); + + b.HasKey("Id"); + + b.ToTable("Users", (string)null); + }); + + modelBuilder.Entity("PostFundManagement.Domain.Entities.Activity", b => + { + b.HasOne("PostFundManagement.Domain.Entities.User", "Approver") + .WithMany() + .HasForeignKey("ApprovedBy") + .OnDelete(DeleteBehavior.NoAction); + + b.HasOne("PostFundManagement.Domain.Entities.User", "Creator") + .WithMany() + .HasForeignKey("CreatedBy") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("PostFundManagement.Domain.Entities.Milestone", "Milestone") + .WithMany() + .HasForeignKey("MilestoneId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("PostFundManagement.Domain.Entities.Project", "Project") + .WithMany() + .HasForeignKey("ProjectId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("PostFundManagement.Domain.Entities.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("PostFundManagement.Domain.Entities.User", "Updator") + .WithMany() + .HasForeignKey("UpdatedBy") + .OnDelete(DeleteBehavior.NoAction); + + b.Navigation("Approver"); + + b.Navigation("Creator"); + + b.Navigation("Milestone"); + + b.Navigation("Project"); + + b.Navigation("Tenant"); + + b.Navigation("Updator"); + }); + + modelBuilder.Entity("PostFundManagement.Domain.Entities.Award", b => + { + b.HasOne("PostFundManagement.Domain.Entities.User", "Approver") + .WithMany() + .HasForeignKey("ApprovedBy") + .OnDelete(DeleteBehavior.NoAction); + + b.HasOne("PostFundManagement.Domain.Entities.User", "Creator") + .WithMany() + .HasForeignKey("CreatedBy") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("PostFundManagement.Domain.Entities.Organisation", "Organisation") + .WithMany() + .HasForeignKey("OrganisationId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("PostFundManagement.Domain.Entities.Programme", "Programme") + .WithMany("Awards") + .HasForeignKey("ProgrammeId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("PostFundManagement.Domain.Entities.Project", "Project") + .WithMany("Awards") + .HasForeignKey("ProjectId") + .OnDelete(DeleteBehavior.SetNull); + + b.HasOne("PostFundManagement.Domain.Entities.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("PostFundManagement.Domain.Entities.User", "Updator") + .WithMany() + .HasForeignKey("UpdatedBy") + .OnDelete(DeleteBehavior.NoAction); + + b.Navigation("Approver"); + + b.Navigation("Creator"); + + b.Navigation("Organisation"); + + b.Navigation("Programme"); + + b.Navigation("Project"); + + b.Navigation("Tenant"); + + b.Navigation("Updator"); + }); + + modelBuilder.Entity("PostFundManagement.Domain.Entities.Beneficiary", b => + { + b.HasOne("PostFundManagement.Domain.Entities.User", "Creator") + .WithMany() + .HasForeignKey("CreatedBy") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("PostFundManagement.Domain.Entities.Project", "Project") + .WithMany() + .HasForeignKey("ProjectId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("PostFundManagement.Domain.Entities.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("PostFundManagement.Domain.Entities.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.Navigation("Creator"); + + b.Navigation("Project"); + + b.Navigation("Tenant"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("PostFundManagement.Domain.Entities.Budget", b => + { + b.HasOne("PostFundManagement.Domain.Entities.User", "Approver") + .WithMany() + .HasForeignKey("ApprovedBy") + .OnDelete(DeleteBehavior.NoAction); + + b.HasOne("PostFundManagement.Domain.Entities.User", "Creator") + .WithMany() + .HasForeignKey("CreatedBy") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("PostFundManagement.Domain.Entities.Project", "Project") + .WithMany() + .HasForeignKey("ProjectId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("PostFundManagement.Domain.Entities.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.Navigation("Approver"); + + b.Navigation("Creator"); + + b.Navigation("Project"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("PostFundManagement.Domain.Entities.ChangeRequest", b => + { + b.HasOne("PostFundManagement.Domain.Entities.User", "Approver") + .WithMany() + .HasForeignKey("ApprovedBy") + .OnDelete(DeleteBehavior.NoAction); + + b.HasOne("PostFundManagement.Domain.Entities.User", "Creator") + .WithMany() + .HasForeignKey("CreatedBy") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("PostFundManagement.Domain.Entities.Project", "Project") + .WithMany() + .HasForeignKey("ProjectId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("PostFundManagement.Domain.Entities.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.Navigation("Approver"); + + b.Navigation("Creator"); + + b.Navigation("Project"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("PostFundManagement.Domain.Entities.ComplianceItem", b => + { + b.HasOne("PostFundManagement.Domain.Entities.User", "Creator") + .WithMany() + .HasForeignKey("CreatedBy") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("PostFundManagement.Domain.Entities.Project", "Project") + .WithMany() + .HasForeignKey("ProjectId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("PostFundManagement.Domain.Entities.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("PostFundManagement.Domain.Entities.User", "Verifier") + .WithMany() + .HasForeignKey("VerifiedBy") + .OnDelete(DeleteBehavior.NoAction); + + b.Navigation("Creator"); + + b.Navigation("Project"); + + b.Navigation("Tenant"); + + b.Navigation("Verifier"); + }); + + modelBuilder.Entity("PostFundManagement.Domain.Entities.Contract", b => + { + b.HasOne("PostFundManagement.Domain.Entities.Award", "Award") + .WithOne("Contract") + .HasForeignKey("PostFundManagement.Domain.Entities.Contract", "AwardId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("PostFundManagement.Domain.Entities.User", "Creator") + .WithMany() + .HasForeignKey("CreatedBy") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("PostFundManagement.Domain.Entities.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.Navigation("Award"); + + b.Navigation("Creator"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("PostFundManagement.Domain.Entities.Disbursement", b => + { + b.HasOne("PostFundManagement.Domain.Entities.User", "Creator") + .WithMany() + .HasForeignKey("CreatedBy") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("PostFundManagement.Domain.Entities.Milestone", "Milestone") + .WithMany() + .HasForeignKey("MilestoneId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("PostFundManagement.Domain.Entities.Project", "Project") + .WithMany() + .HasForeignKey("ProjectId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("PostFundManagement.Domain.Entities.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("PostFundManagement.Domain.Entities.User", "Updator") + .WithMany() + .HasForeignKey("UpdatedBy") + .OnDelete(DeleteBehavior.NoAction); + + b.Navigation("Creator"); + + b.Navigation("Milestone"); + + b.Navigation("Project"); + + b.Navigation("Tenant"); + + b.Navigation("Updator"); + }); + + modelBuilder.Entity("PostFundManagement.Domain.Entities.Evidence", b => + { + b.HasOne("PostFundManagement.Domain.Entities.Activity", "Activity") + .WithMany("Evidences") + .HasForeignKey("ActivityId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("PostFundManagement.Domain.Entities.User", "Creator") + .WithMany() + .HasForeignKey("CreatedBy") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("PostFundManagement.Domain.Entities.Indicator", "Indicator") + .WithMany() + .HasForeignKey("IndicatorId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("PostFundManagement.Domain.Entities.Milestone", "Milestone") + .WithMany() + .HasForeignKey("MilestoneId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("PostFundManagement.Domain.Entities.Project", "Project") + .WithMany() + .HasForeignKey("ProjectId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("PostFundManagement.Domain.Entities.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("PostFundManagement.Domain.Entities.User", "Updator") + .WithMany() + .HasForeignKey("UpdatedBy") + .OnDelete(DeleteBehavior.NoAction); + + b.Navigation("Activity"); + + b.Navigation("Creator"); + + b.Navigation("Indicator"); + + b.Navigation("Milestone"); + + b.Navigation("Project"); + + b.Navigation("Tenant"); + + b.Navigation("Updator"); + }); + + modelBuilder.Entity("PostFundManagement.Domain.Entities.Indicator", b => + { + b.HasOne("PostFundManagement.Domain.Entities.User", "Creator") + .WithMany() + .HasForeignKey("CreatedBy") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("PostFundManagement.Domain.Entities.Project", "Project") + .WithMany() + .HasForeignKey("ProjectId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("PostFundManagement.Domain.Entities.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.Navigation("Creator"); + + b.Navigation("Project"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("PostFundManagement.Domain.Entities.Instrument", b => + { + b.HasOne("PostFundManagement.Domain.Entities.User", "Creator") + .WithMany() + .HasForeignKey("CreatedBy") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("PostFundManagement.Domain.Entities.Programme", "Programme") + .WithMany("Instruments") + .HasForeignKey("ProgrammeId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("PostFundManagement.Domain.Entities.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.Navigation("Creator"); + + b.Navigation("Programme"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("PostFundManagement.Domain.Entities.Invite", b => + { + b.HasOne("PostFundManagement.Domain.Entities.Award", "Award") + .WithMany() + .HasForeignKey("AwardId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("PostFundManagement.Domain.Entities.Contract", "Contract") + .WithMany() + .HasForeignKey("ContractId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("PostFundManagement.Domain.Entities.Organisation", "InvitedOrganisation") + .WithMany() + .HasForeignKey("InvitedOrganisationId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("PostFundManagement.Domain.Entities.Organisation", "Organisation") + .WithMany() + .HasForeignKey("OrganisationId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("PostFundManagement.Domain.Entities.User", "RecipientUser") + .WithMany() + .HasForeignKey("Recipient") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("PostFundManagement.Domain.Entities.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.Navigation("Award"); + + b.Navigation("Contract"); + + b.Navigation("InvitedOrganisation"); + + b.Navigation("Organisation"); + + b.Navigation("RecipientUser"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("PostFundManagement.Domain.Entities.Issue", b => + { + b.HasOne("PostFundManagement.Domain.Entities.User", "Assignee") + .WithMany() + .HasForeignKey("AssignedTo") + .OnDelete(DeleteBehavior.SetNull) + .IsRequired(); + + b.HasOne("PostFundManagement.Domain.Entities.User", "Creator") + .WithMany() + .HasForeignKey("CreatedBy") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("PostFundManagement.Domain.Entities.Project", "Project") + .WithMany() + .HasForeignKey("ProjectId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("PostFundManagement.Domain.Entities.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.Navigation("Assignee"); + + b.Navigation("Creator"); + + b.Navigation("Project"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("PostFundManagement.Domain.Entities.Milestone", b => + { + b.HasOne("PostFundManagement.Domain.Entities.User", "Creator") + .WithMany() + .HasForeignKey("CreatedBy") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("PostFundManagement.Domain.Entities.Project", "Project") + .WithMany() + .HasForeignKey("ProjectId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("PostFundManagement.Domain.Entities.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("PostFundManagement.Domain.Entities.User", "Updator") + .WithMany() + .HasForeignKey("UpdatedBy") + .OnDelete(DeleteBehavior.NoAction); + + b.Navigation("Creator"); + + b.Navigation("Project"); + + b.Navigation("Tenant"); + + b.Navigation("Updator"); + }); + + modelBuilder.Entity("PostFundManagement.Domain.Entities.Notification", b => + { + b.HasOne("PostFundManagement.Domain.Entities.Organisation", "Organisation") + .WithMany() + .HasForeignKey("OrganisationId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("PostFundManagement.Domain.Entities.User", "RecipientUser") + .WithMany() + .HasForeignKey("Recipient") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("PostFundManagement.Domain.Entities.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Organisation"); + + b.Navigation("RecipientUser"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("PostFundManagement.Domain.Entities.Organisation", b => + { + b.HasOne("PostFundManagement.Domain.Entities.User", "Creator") + .WithMany() + .HasForeignKey("CreatedBy") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("PostFundManagement.Domain.Entities.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.NoAction); + + b.Navigation("Creator"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("PostFundManagement.Domain.Entities.Outcome", b => + { + b.HasOne("PostFundManagement.Domain.Entities.Beneficiary", "Beneficiary") + .WithMany() + .HasForeignKey("BeneficiaryId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("PostFundManagement.Domain.Entities.User", "Creator") + .WithMany() + .HasForeignKey("CreatedBy") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("PostFundManagement.Domain.Entities.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.Navigation("Beneficiary"); + + b.Navigation("Creator"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("PostFundManagement.Domain.Entities.Portfolio", b => + { + b.HasOne("PostFundManagement.Domain.Entities.User", "Creator") + .WithMany() + .HasForeignKey("CreatedBy") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("PostFundManagement.Domain.Entities.Organisation", "Organisation") + .WithMany() + .HasForeignKey("OrganisationId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("PostFundManagement.Domain.Entities.User", "Owner") + .WithMany() + .HasForeignKey("OwnedBy") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("PostFundManagement.Domain.Entities.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Creator"); + + b.Navigation("Organisation"); + + b.Navigation("Owner"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("PostFundManagement.Domain.Entities.Programme", b => + { + b.HasOne("PostFundManagement.Domain.Entities.User", "Creator") + .WithMany() + .HasForeignKey("CreatedBy") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("PostFundManagement.Domain.Entities.User", "Owner") + .WithMany() + .HasForeignKey("OwnedBy") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("PostFundManagement.Domain.Entities.Portfolio", "Portfolio") + .WithMany("Programmes") + .HasForeignKey("PortfolioId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("PostFundManagement.Domain.Entities.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.Navigation("Creator"); + + b.Navigation("Owner"); + + b.Navigation("Portfolio"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("PostFundManagement.Domain.Entities.Project", b => + { + b.HasOne("PostFundManagement.Domain.Entities.User", "Creator") + .WithMany() + .HasForeignKey("CreatedBy") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("PostFundManagement.Domain.Entities.Programme", "Programme") + .WithMany("Projects") + .HasForeignKey("ProgrammeId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("PostFundManagement.Domain.Entities.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("PostFundManagement.Domain.Entities.User", "Updator") + .WithMany() + .HasForeignKey("UpdatedBy") + .OnDelete(DeleteBehavior.NoAction); + + b.Navigation("Creator"); + + b.Navigation("Programme"); + + b.Navigation("Tenant"); + + b.Navigation("Updator"); + }); + + modelBuilder.Entity("PostFundManagement.Domain.Entities.Risk", b => + { + b.HasOne("PostFundManagement.Domain.Entities.User", "Creator") + .WithMany() + .HasForeignKey("CreatedBy") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("PostFundManagement.Domain.Entities.Project", "Project") + .WithMany() + .HasForeignKey("ProjectId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("PostFundManagement.Domain.Entities.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.Navigation("Creator"); + + b.Navigation("Project"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("PostFundManagement.Domain.Entities.Rule", b => + { + b.HasOne("PostFundManagement.Domain.Entities.User", "Creator") + .WithMany() + .HasForeignKey("CreatedBy") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("PostFundManagement.Domain.Entities.Programme", "Programme") + .WithMany("Rules") + .HasForeignKey("ProgrammeId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("PostFundManagement.Domain.Entities.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("PostFundManagement.Domain.Entities.User", "Updator") + .WithMany() + .HasForeignKey("UpdatedBy") + .OnDelete(DeleteBehavior.NoAction); + + b.Navigation("Creator"); + + b.Navigation("Programme"); + + b.Navigation("Tenant"); + + b.Navigation("Updator"); + }); + + modelBuilder.Entity("PostFundManagement.Domain.Entities.SiteVisit", b => + { + b.HasOne("PostFundManagement.Domain.Entities.User", "Creator") + .WithMany() + .HasForeignKey("CreatedBy") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("PostFundManagement.Domain.Entities.Project", "Project") + .WithMany() + .HasForeignKey("ProjectId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("PostFundManagement.Domain.Entities.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.Navigation("Creator"); + + b.Navigation("Project"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("PostFundManagement.Domain.Entities.Tenant", b => + { + b.HasOne("PostFundManagement.Domain.Entities.User", "Creator") + .WithMany() + .HasForeignKey("CreatedBy") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("PostFundManagement.Domain.Entities.User", "Updator") + .WithMany() + .HasForeignKey("UpdatedBy") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("Creator"); + + b.Navigation("Updator"); + }); + + modelBuilder.Entity("PostFundManagement.Domain.Entities.TenantOrganisation", b => + { + b.HasOne("PostFundManagement.Domain.Entities.User", "Creator") + .WithMany() + .HasForeignKey("CreatedBy") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("PostFundManagement.Domain.Entities.Organisation", "Organisation") + .WithMany() + .HasForeignKey("OrganisationId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("PostFundManagement.Domain.Entities.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Creator"); + + b.Navigation("Organisation"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("PostFundManagement.Domain.Entities.TenantUser", b => + { + b.HasOne("PostFundManagement.Domain.Entities.User", "Creator") + .WithMany() + .HasForeignKey("CreatedBy") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("PostFundManagement.Domain.Entities.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("PostFundManagement.Domain.Entities.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Creator"); + + b.Navigation("Tenant"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("PostFundManagement.Domain.Entities.Activity", b => + { + b.Navigation("Evidences"); + }); + + modelBuilder.Entity("PostFundManagement.Domain.Entities.Award", b => + { + b.Navigation("Contract"); + }); + + modelBuilder.Entity("PostFundManagement.Domain.Entities.Portfolio", b => + { + b.Navigation("Programmes"); + }); + + modelBuilder.Entity("PostFundManagement.Domain.Entities.Programme", b => + { + b.Navigation("Awards"); + + b.Navigation("Instruments"); + + b.Navigation("Projects"); + + b.Navigation("Rules"); + }); + + modelBuilder.Entity("PostFundManagement.Domain.Entities.Project", b => + { + b.Navigation("Awards"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/PostFundManagement.Infrastructure/Database/Migrations/20261004075524_AddedUserIdAndIdNumberTenantOrgAndUserObjects.cs b/PostFundManagement.Infrastructure/Database/Migrations/20261004075524_AddedUserIdAndIdNumberTenantOrgAndUserObjects.cs new file mode 100644 index 0000000..899c9b2 --- /dev/null +++ b/PostFundManagement.Infrastructure/Database/Migrations/20261004075524_AddedUserIdAndIdNumberTenantOrgAndUserObjects.cs @@ -0,0 +1,60 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace PostFundManagement.Infrastructure.Database.Migrations +{ + /// + public partial class AddedUserIdAndIdNumberTenantOrgAndUserObjects : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "IdNumber", + table: "Users", + type: "character varying(256)", + maxLength: 256, + nullable: true); + + migrationBuilder.AddColumn( + name: "UserId", + table: "Organisations", + type: "uuid", + nullable: true); + + migrationBuilder.CreateIndex( + name: "IX_Organisations_UserId", + table: "Organisations", + column: "UserId"); + + migrationBuilder.AddForeignKey( + name: "FK_Organisations_Users_UserId", + table: "Organisations", + column: "UserId", + principalTable: "Users", + principalColumn: "Id"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_Organisations_Users_UserId", + table: "Organisations"); + + migrationBuilder.DropIndex( + name: "IX_Organisations_UserId", + table: "Organisations"); + + migrationBuilder.DropColumn( + name: "IdNumber", + table: "Users"); + + migrationBuilder.DropColumn( + name: "UserId", + table: "Organisations"); + } + } +} diff --git a/PostFundManagement.Infrastructure/Database/Migrations/ApplicationDbContextModelSnapshot.cs b/PostFundManagement.Infrastructure/Database/Migrations/ApplicationDbContextModelSnapshot.cs index 5c4a632..ae5b0a7 100644 --- a/PostFundManagement.Infrastructure/Database/Migrations/ApplicationDbContextModelSnapshot.cs +++ b/PostFundManagement.Infrastructure/Database/Migrations/ApplicationDbContextModelSnapshot.cs @@ -1017,10 +1017,15 @@ namespace PostFundManagement.Infrastructure.Database.Migrations .HasColumnType("integer") .HasDefaultValueSql("5"); + b.Property("UserId") + .HasColumnType("uuid"); + b.HasKey("Id"); b.HasIndex("CreatedBy"); + b.HasIndex("UserId"); + b.ToTable("Organisations", (string)null); }); @@ -1530,6 +1535,10 @@ namespace PostFundManagement.Infrastructure.Database.Migrations .HasMaxLength(256) .HasColumnType("character varying(256)"); + b.Property("IdNumber") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + b.Property("LastLoginAt") .HasColumnType("timestamp with time zone"); @@ -2124,7 +2133,14 @@ namespace PostFundManagement.Infrastructure.Database.Migrations .OnDelete(DeleteBehavior.NoAction) .IsRequired(); + b.HasOne("PostFundManagement.Domain.Entities.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.NoAction); + b.Navigation("Creator"); + + b.Navigation("User"); }); modelBuilder.Entity("PostFundManagement.Domain.Entities.Outcome", b => diff --git a/PostFundManagement.Infrastructure/Database/Services/TenantContextService.cs b/PostFundManagement.Infrastructure/Database/Services/TenantContextService.cs index cf81640..082b0a4 100644 --- a/PostFundManagement.Infrastructure/Database/Services/TenantContextService.cs +++ b/PostFundManagement.Infrastructure/Database/Services/TenantContextService.cs @@ -19,6 +19,9 @@ public sealed class TenantContextService : ITenantContextService var user = httpContextAccessor.HttpContext?.User; IsAdmin = user?.IsInRole("Admin") == true || user?.HasClaim("role", "Admin") == true; + ByPassTenantQueryFilter = user?.IsInRole("Partner") == true || user?.HasClaim("role", "Partner") == true; + + ByPassTenantQueryFilter = ByPassTenantQueryFilter || IsAdmin; HasTenantFilter = !IsAdmin; -- 2.47.3