diff --git a/backend/.idea/.idea.Tnsu.ApprovalRoute/.idea/.gitignore b/backend/.idea/.idea.Tnsu.ApprovalRoute/.idea/.gitignore new file mode 100644 index 0000000..e865c8b --- /dev/null +++ b/backend/.idea/.idea.Tnsu.ApprovalRoute/.idea/.gitignore @@ -0,0 +1,15 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Rider ignored files +/.idea.Tnsu.ApprovalRoute.iml +/modules.xml +/projectSettingsUpdater.xml +/contentModel.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Ignored default folder with query files +/queries/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/backend/.idea/.idea.Tnsu.ApprovalRoute/.idea/.name b/backend/.idea/.idea.Tnsu.ApprovalRoute/.idea/.name new file mode 100644 index 0000000..b44cf1f --- /dev/null +++ b/backend/.idea/.idea.Tnsu.ApprovalRoute/.idea/.name @@ -0,0 +1 @@ +Tnsu.ApprovalRoute \ No newline at end of file diff --git a/backend/.idea/.idea.Tnsu.ApprovalRoute/.idea/encodings.xml b/backend/.idea/.idea.Tnsu.ApprovalRoute/.idea/encodings.xml new file mode 100644 index 0000000..df87cf9 --- /dev/null +++ b/backend/.idea/.idea.Tnsu.ApprovalRoute/.idea/encodings.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/backend/.idea/.idea.Tnsu.ApprovalRoute/.idea/indexLayout.xml b/backend/.idea/.idea.Tnsu.ApprovalRoute/.idea/indexLayout.xml new file mode 100644 index 0000000..7b08163 --- /dev/null +++ b/backend/.idea/.idea.Tnsu.ApprovalRoute/.idea/indexLayout.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/backend/.idea/.idea.Tnsu.ApprovalRoute/.idea/vcs.xml b/backend/.idea/.idea.Tnsu.ApprovalRoute/.idea/vcs.xml new file mode 100644 index 0000000..6c0b863 --- /dev/null +++ b/backend/.idea/.idea.Tnsu.ApprovalRoute/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/backend/Directory.Packages.props b/backend/Directory.Packages.props index 775e9b8..0217988 100644 --- a/backend/Directory.Packages.props +++ b/backend/Directory.Packages.props @@ -3,11 +3,14 @@ true - - - - - - + + + + + + + + + - + \ No newline at end of file diff --git a/backend/src/Tnsu.ApprovalRoute.Api/Program.cs b/backend/src/Tnsu.ApprovalRoute.Api/Program.cs index 6a18908..5d1223b 100644 --- a/backend/src/Tnsu.ApprovalRoute.Api/Program.cs +++ b/backend/src/Tnsu.ApprovalRoute.Api/Program.cs @@ -1,3 +1,7 @@ +using Extensions.Hosting.AsyncInitialization; +using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; using Tnsu.ApprovalRoute.Application; using Tnsu.ApprovalRoute.Infrastructure; @@ -15,6 +19,6 @@ if (app.Environment.IsDevelopment()) app.MapHealthChecks("/health"); -app.Run(); +await app.InitAndRunAsync(); public partial class Program; diff --git a/backend/src/Tnsu.ApprovalRoute.Api/Tnsu.ApprovalRoute.Api.csproj b/backend/src/Tnsu.ApprovalRoute.Api/Tnsu.ApprovalRoute.Api.csproj index 24f7ac4..325ff39 100644 --- a/backend/src/Tnsu.ApprovalRoute.Api/Tnsu.ApprovalRoute.Api.csproj +++ b/backend/src/Tnsu.ApprovalRoute.Api/Tnsu.ApprovalRoute.Api.csproj @@ -4,8 +4,13 @@ + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + diff --git a/backend/src/Tnsu.ApprovalRoute.Domain/Entities/RequestType.cs b/backend/src/Tnsu.ApprovalRoute.Domain/Entities/RequestType.cs new file mode 100644 index 0000000..2cd90e7 --- /dev/null +++ b/backend/src/Tnsu.ApprovalRoute.Domain/Entities/RequestType.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; + +namespace Tnsu.ApprovalRoute.Domain.Entities; + +public class RequestType +{ + public Guid Id { get; set; } = Guid.NewGuid(); + public string Name { get; set; } = string.Empty; + public string PageUrl { get; set; } = string.Empty; + + public ICollection Routes { get; set; } = new List(); +} diff --git a/backend/src/Tnsu.ApprovalRoute.Domain/Entities/Route.cs b/backend/src/Tnsu.ApprovalRoute.Domain/Entities/Route.cs new file mode 100644 index 0000000..2df9be2 --- /dev/null +++ b/backend/src/Tnsu.ApprovalRoute.Domain/Entities/Route.cs @@ -0,0 +1,20 @@ +using Tnsu.ApprovalRoute.Domain.Enums; + +namespace Tnsu.ApprovalRoute.Domain.Entities; + +public class Route +{ + public Guid Id { get; set; } = Guid.NewGuid(); + public RouteType RouteType { get; set; } = RouteType.Sequential; + public Guid RequestTypeId { get; set; } + + // Внешние справочники (1С/ZUP) — хранятся как ссылки без FK в этой БД. + public Guid DepartmentId { get; set; } + public Guid CompanyId { get; set; } + public bool ByProject { get; set; } + + public bool RequiresControl { get; set; } + + public RequestType? RequestType { get; set; } + public ICollection Steps { get; set; } = new List(); +} diff --git a/backend/src/Tnsu.ApprovalRoute.Domain/Entities/RouteStep.cs b/backend/src/Tnsu.ApprovalRoute.Domain/Entities/RouteStep.cs new file mode 100644 index 0000000..a70ef8c --- /dev/null +++ b/backend/src/Tnsu.ApprovalRoute.Domain/Entities/RouteStep.cs @@ -0,0 +1,20 @@ +using Tnsu.ApprovalRoute.Domain.Enums; + +namespace Tnsu.ApprovalRoute.Domain.Entities; + +public class RouteStep +{ + public Guid Id { get; set; } = Guid.NewGuid(); + public int OrderNo { get; set; } + + // Внешняя ссылка на пользователя (1С/ZUP) — без локальной таблицы Users. + public string ExecutorEmail { get; set; } = string.Empty; + public string Position { get; set; } = string.Empty; + public ProjectRole ProjectRole { get; set; } = ProjectRole.None; + + public RouteStepStatus Status { get; set; } = RouteStepStatus.Draft; + public Guid RouteId { get; set; } + public bool AllowReassignToOtherApprovers { get; set; } + + public Route? Route { get; set; } +} diff --git a/backend/src/Tnsu.ApprovalRoute.Domain/Enums/ProjectRole.cs b/backend/src/Tnsu.ApprovalRoute.Domain/Enums/ProjectRole.cs new file mode 100644 index 0000000..f27fc56 --- /dev/null +++ b/backend/src/Tnsu.ApprovalRoute.Domain/Enums/ProjectRole.cs @@ -0,0 +1,9 @@ +namespace Tnsu.ApprovalRoute.Domain.Enums; + +public enum ProjectRole +{ + None, + Manager, + Engineer, + Observer +} diff --git a/backend/src/Tnsu.ApprovalRoute.Domain/Enums/RouteStepStatus.cs b/backend/src/Tnsu.ApprovalRoute.Domain/Enums/RouteStepStatus.cs new file mode 100644 index 0000000..77d1367 --- /dev/null +++ b/backend/src/Tnsu.ApprovalRoute.Domain/Enums/RouteStepStatus.cs @@ -0,0 +1,13 @@ +namespace Tnsu.ApprovalRoute.Domain.Enums; + +public enum RouteStepStatus +{ + None, + Draft, + OnApproval, + Approved, + InExecution, + Completed, + Returned, + Closed +} diff --git a/backend/src/Tnsu.ApprovalRoute.Domain/Enums/RouteType.cs b/backend/src/Tnsu.ApprovalRoute.Domain/Enums/RouteType.cs new file mode 100644 index 0000000..8004453 --- /dev/null +++ b/backend/src/Tnsu.ApprovalRoute.Domain/Enums/RouteType.cs @@ -0,0 +1,8 @@ +namespace Tnsu.ApprovalRoute.Domain.Enums; + +public enum RouteType +{ + None, + Parallel, + Sequential +} diff --git a/backend/src/Tnsu.ApprovalRoute.Infrastructure/InfrastructureServiceCollectionExtensions.cs b/backend/src/Tnsu.ApprovalRoute.Infrastructure/InfrastructureServiceCollectionExtensions.cs index b470fd9..a006dd4 100644 --- a/backend/src/Tnsu.ApprovalRoute.Infrastructure/InfrastructureServiceCollectionExtensions.cs +++ b/backend/src/Tnsu.ApprovalRoute.Infrastructure/InfrastructureServiceCollectionExtensions.cs @@ -1,3 +1,4 @@ +using Extensions.Hosting.AsyncInitialization; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; @@ -11,7 +12,9 @@ public static class InfrastructureServiceCollectionExtensions this IServiceCollection services, IConfiguration configuration) { services.AddDbContext(opt => - opt.UseNpgsql(configuration.GetConnectionString("Postgres"))); + opt.UseNpgsql(configuration.GetConnectionString("Postgres")) + .UseSnakeCaseNamingConvention()); + services.AddAsyncInitializer(); return services; } diff --git a/backend/src/Tnsu.ApprovalRoute.Infrastructure/Persistence/ApprovalRouteDbContext.cs b/backend/src/Tnsu.ApprovalRoute.Infrastructure/Persistence/ApprovalRouteDbContext.cs index 6fa2086..080ae1f 100644 --- a/backend/src/Tnsu.ApprovalRoute.Infrastructure/Persistence/ApprovalRouteDbContext.cs +++ b/backend/src/Tnsu.ApprovalRoute.Infrastructure/Persistence/ApprovalRouteDbContext.cs @@ -1,7 +1,39 @@ using Microsoft.EntityFrameworkCore; +using Tnsu.ApprovalRoute.Domain.Entities; namespace Tnsu.ApprovalRoute.Infrastructure.Persistence; public class ApprovalRouteDbContext(DbContextOptions options) : DbContext(options) { + public DbSet RequestTypes => Set(); + public DbSet Routes => Set(); + public DbSet RouteSteps => Set(); + + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + modelBuilder.Entity(e => + { + e.HasKey(x => x.Id); + e.Property(x => x.Name).HasMaxLength(256).IsRequired(); + e.Property(x => x.PageUrl).HasMaxLength(512).IsRequired(); + }); + + modelBuilder.Entity(e => + { + e.HasKey(x => x.Id); + e.Property(x => x.RouteType).HasConversion().HasMaxLength(32).IsRequired(); + e.HasOne(x => x.RequestType).WithMany(x => x.Routes).HasForeignKey(x => x.RequestTypeId); + }); + + modelBuilder.Entity(e => + { + e.HasKey(x => x.Id); + e.Property(x => x.ExecutorEmail).HasMaxLength(256).IsRequired(); + e.Property(x => x.Position).HasMaxLength(128).IsRequired(); + e.Property(x => x.ProjectRole).HasConversion().HasMaxLength(32).IsRequired(); + e.Property(x => x.Status).HasConversion().HasMaxLength(32).IsRequired(); + e.HasOne(x => x.Route).WithMany(x => x.Steps).HasForeignKey(x => x.RouteId); + e.HasIndex(x => new { x.RouteId, x.OrderNo }); + }); + } } diff --git a/backend/src/Tnsu.ApprovalRoute.Infrastructure/Persistence/DatabaseMigrationInitializer.cs b/backend/src/Tnsu.ApprovalRoute.Infrastructure/Persistence/DatabaseMigrationInitializer.cs new file mode 100644 index 0000000..c0e10b5 --- /dev/null +++ b/backend/src/Tnsu.ApprovalRoute.Infrastructure/Persistence/DatabaseMigrationInitializer.cs @@ -0,0 +1,10 @@ +using Extensions.Hosting.AsyncInitialization; +using Microsoft.EntityFrameworkCore; + +namespace Tnsu.ApprovalRoute.Infrastructure.Persistence; + +public sealed class DatabaseMigrationInitializer(ApprovalRouteDbContext db) : IAsyncInitializer +{ + public Task InitializeAsync(CancellationToken cancellationToken) => + db.Database.MigrateAsync(cancellationToken); +} diff --git a/backend/src/Tnsu.ApprovalRoute.Infrastructure/Persistence/Migrations/20260722130455_InitialCreate.Designer.cs b/backend/src/Tnsu.ApprovalRoute.Infrastructure/Persistence/Migrations/20260722130455_InitialCreate.Designer.cs new file mode 100644 index 0000000..475d855 --- /dev/null +++ b/backend/src/Tnsu.ApprovalRoute.Infrastructure/Persistence/Migrations/20260722130455_InitialCreate.Designer.cs @@ -0,0 +1,183 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; +using Tnsu.ApprovalRoute.Infrastructure.Persistence; + +#nullable disable + +namespace Tnsu.ApprovalRoute.Infrastructure.Persistence.Migrations +{ + [DbContext(typeof(ApprovalRouteDbContext))] + [Migration("20260722130455_InitialCreate")] + partial class InitialCreate + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "10.0.10") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("Tnsu.ApprovalRoute.Domain.Entities.RequestType", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("name"); + + b.Property("PageUrl") + .IsRequired() + .HasMaxLength(512) + .HasColumnType("character varying(512)") + .HasColumnName("page_url"); + + b.HasKey("Id") + .HasName("pk_request_types"); + + b.ToTable("request_types", (string)null); + }); + + modelBuilder.Entity("Tnsu.ApprovalRoute.Domain.Entities.Route", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("ByProject") + .HasColumnType("boolean") + .HasColumnName("by_project"); + + b.Property("CompanyId") + .HasColumnType("uuid") + .HasColumnName("company_id"); + + b.Property("DepartmentId") + .HasColumnType("uuid") + .HasColumnName("department_id"); + + b.Property("RequestTypeId") + .HasColumnType("uuid") + .HasColumnName("request_type_id"); + + b.Property("RequiresControl") + .HasColumnType("boolean") + .HasColumnName("requires_control"); + + b.Property("RouteType") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)") + .HasColumnName("route_type"); + + b.HasKey("Id") + .HasName("pk_routes"); + + b.HasIndex("RequestTypeId") + .HasDatabaseName("ix_routes_request_type_id"); + + b.ToTable("routes", (string)null); + }); + + modelBuilder.Entity("Tnsu.ApprovalRoute.Domain.Entities.RouteStep", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("AllowReassignToOtherApprovers") + .HasColumnType("boolean") + .HasColumnName("allow_reassign_to_other_approvers"); + + b.Property("ExecutorEmail") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("executor_email"); + + b.Property("OrderNo") + .HasColumnType("integer") + .HasColumnName("order_no"); + + b.Property("Position") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("character varying(128)") + .HasColumnName("position"); + + b.Property("ProjectRole") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)") + .HasColumnName("project_role"); + + b.Property("RouteId") + .HasColumnType("uuid") + .HasColumnName("route_id"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)") + .HasColumnName("status"); + + b.HasKey("Id") + .HasName("pk_route_steps"); + + b.HasIndex("RouteId", "OrderNo") + .HasDatabaseName("ix_route_steps_route_id_order_no"); + + b.ToTable("route_steps", (string)null); + }); + + modelBuilder.Entity("Tnsu.ApprovalRoute.Domain.Entities.Route", b => + { + b.HasOne("Tnsu.ApprovalRoute.Domain.Entities.RequestType", "RequestType") + .WithMany("Routes") + .HasForeignKey("RequestTypeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_routes_request_types_request_type_id"); + + b.Navigation("RequestType"); + }); + + modelBuilder.Entity("Tnsu.ApprovalRoute.Domain.Entities.RouteStep", b => + { + b.HasOne("Tnsu.ApprovalRoute.Domain.Entities.Route", "Route") + .WithMany("Steps") + .HasForeignKey("RouteId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_route_steps_routes_route_id"); + + b.Navigation("Route"); + }); + + modelBuilder.Entity("Tnsu.ApprovalRoute.Domain.Entities.RequestType", b => + { + b.Navigation("Routes"); + }); + + modelBuilder.Entity("Tnsu.ApprovalRoute.Domain.Entities.Route", b => + { + b.Navigation("Steps"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/backend/src/Tnsu.ApprovalRoute.Infrastructure/Persistence/Migrations/20260722130455_InitialCreate.cs b/backend/src/Tnsu.ApprovalRoute.Infrastructure/Persistence/Migrations/20260722130455_InitialCreate.cs new file mode 100644 index 0000000..772cbab --- /dev/null +++ b/backend/src/Tnsu.ApprovalRoute.Infrastructure/Persistence/Migrations/20260722130455_InitialCreate.cs @@ -0,0 +1,98 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Tnsu.ApprovalRoute.Infrastructure.Persistence.Migrations +{ + /// + public partial class InitialCreate : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "request_types", + columns: table => new + { + id = table.Column(type: "uuid", nullable: false), + name = table.Column(type: "character varying(256)", maxLength: 256, nullable: false), + page_url = table.Column(type: "character varying(512)", maxLength: 512, nullable: false) + }, + constraints: table => + { + table.PrimaryKey("pk_request_types", x => x.id); + }); + + migrationBuilder.CreateTable( + name: "routes", + columns: table => new + { + id = table.Column(type: "uuid", nullable: false), + route_type = table.Column(type: "character varying(32)", maxLength: 32, nullable: false), + request_type_id = table.Column(type: "uuid", nullable: false), + department_id = table.Column(type: "uuid", nullable: false), + company_id = table.Column(type: "uuid", nullable: false), + by_project = table.Column(type: "boolean", nullable: false), + requires_control = table.Column(type: "boolean", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("pk_routes", x => x.id); + table.ForeignKey( + name: "fk_routes_request_types_request_type_id", + column: x => x.request_type_id, + principalTable: "request_types", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "route_steps", + columns: table => new + { + id = table.Column(type: "uuid", nullable: false), + order_no = table.Column(type: "integer", nullable: false), + executor_email = table.Column(type: "character varying(256)", maxLength: 256, nullable: false), + position = table.Column(type: "character varying(128)", maxLength: 128, nullable: false), + project_role = table.Column(type: "character varying(32)", maxLength: 32, nullable: false), + status = table.Column(type: "character varying(32)", maxLength: 32, nullable: false), + route_id = table.Column(type: "uuid", nullable: false), + allow_reassign_to_other_approvers = table.Column(type: "boolean", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("pk_route_steps", x => x.id); + table.ForeignKey( + name: "fk_route_steps_routes_route_id", + column: x => x.route_id, + principalTable: "routes", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateIndex( + name: "ix_route_steps_route_id_order_no", + table: "route_steps", + columns: new[] { "route_id", "order_no" }); + + migrationBuilder.CreateIndex( + name: "ix_routes_request_type_id", + table: "routes", + column: "request_type_id"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "route_steps"); + + migrationBuilder.DropTable( + name: "routes"); + + migrationBuilder.DropTable( + name: "request_types"); + } + } +} diff --git a/backend/src/Tnsu.ApprovalRoute.Infrastructure/Persistence/Migrations/ApprovalRouteDbContextModelSnapshot.cs b/backend/src/Tnsu.ApprovalRoute.Infrastructure/Persistence/Migrations/ApprovalRouteDbContextModelSnapshot.cs new file mode 100644 index 0000000..26f31c4 --- /dev/null +++ b/backend/src/Tnsu.ApprovalRoute.Infrastructure/Persistence/Migrations/ApprovalRouteDbContextModelSnapshot.cs @@ -0,0 +1,180 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; +using Tnsu.ApprovalRoute.Infrastructure.Persistence; + +#nullable disable + +namespace Tnsu.ApprovalRoute.Infrastructure.Persistence.Migrations +{ + [DbContext(typeof(ApprovalRouteDbContext))] + partial class ApprovalRouteDbContextModelSnapshot : ModelSnapshot + { + protected override void BuildModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "10.0.10") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("Tnsu.ApprovalRoute.Domain.Entities.RequestType", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("name"); + + b.Property("PageUrl") + .IsRequired() + .HasMaxLength(512) + .HasColumnType("character varying(512)") + .HasColumnName("page_url"); + + b.HasKey("Id") + .HasName("pk_request_types"); + + b.ToTable("request_types", (string)null); + }); + + modelBuilder.Entity("Tnsu.ApprovalRoute.Domain.Entities.Route", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("ByProject") + .HasColumnType("boolean") + .HasColumnName("by_project"); + + b.Property("CompanyId") + .HasColumnType("uuid") + .HasColumnName("company_id"); + + b.Property("DepartmentId") + .HasColumnType("uuid") + .HasColumnName("department_id"); + + b.Property("RequestTypeId") + .HasColumnType("uuid") + .HasColumnName("request_type_id"); + + b.Property("RequiresControl") + .HasColumnType("boolean") + .HasColumnName("requires_control"); + + b.Property("RouteType") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)") + .HasColumnName("route_type"); + + b.HasKey("Id") + .HasName("pk_routes"); + + b.HasIndex("RequestTypeId") + .HasDatabaseName("ix_routes_request_type_id"); + + b.ToTable("routes", (string)null); + }); + + modelBuilder.Entity("Tnsu.ApprovalRoute.Domain.Entities.RouteStep", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("AllowReassignToOtherApprovers") + .HasColumnType("boolean") + .HasColumnName("allow_reassign_to_other_approvers"); + + b.Property("ExecutorEmail") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("executor_email"); + + b.Property("OrderNo") + .HasColumnType("integer") + .HasColumnName("order_no"); + + b.Property("Position") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("character varying(128)") + .HasColumnName("position"); + + b.Property("ProjectRole") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)") + .HasColumnName("project_role"); + + b.Property("RouteId") + .HasColumnType("uuid") + .HasColumnName("route_id"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)") + .HasColumnName("status"); + + b.HasKey("Id") + .HasName("pk_route_steps"); + + b.HasIndex("RouteId", "OrderNo") + .HasDatabaseName("ix_route_steps_route_id_order_no"); + + b.ToTable("route_steps", (string)null); + }); + + modelBuilder.Entity("Tnsu.ApprovalRoute.Domain.Entities.Route", b => + { + b.HasOne("Tnsu.ApprovalRoute.Domain.Entities.RequestType", "RequestType") + .WithMany("Routes") + .HasForeignKey("RequestTypeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_routes_request_types_request_type_id"); + + b.Navigation("RequestType"); + }); + + modelBuilder.Entity("Tnsu.ApprovalRoute.Domain.Entities.RouteStep", b => + { + b.HasOne("Tnsu.ApprovalRoute.Domain.Entities.Route", "Route") + .WithMany("Steps") + .HasForeignKey("RouteId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_route_steps_routes_route_id"); + + b.Navigation("Route"); + }); + + modelBuilder.Entity("Tnsu.ApprovalRoute.Domain.Entities.RequestType", b => + { + b.Navigation("Routes"); + }); + + modelBuilder.Entity("Tnsu.ApprovalRoute.Domain.Entities.Route", b => + { + b.Navigation("Steps"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/backend/src/Tnsu.ApprovalRoute.Infrastructure/Tnsu.ApprovalRoute.Infrastructure.csproj b/backend/src/Tnsu.ApprovalRoute.Infrastructure/Tnsu.ApprovalRoute.Infrastructure.csproj index f268684..79b63af 100644 --- a/backend/src/Tnsu.ApprovalRoute.Infrastructure/Tnsu.ApprovalRoute.Infrastructure.csproj +++ b/backend/src/Tnsu.ApprovalRoute.Infrastructure/Tnsu.ApprovalRoute.Infrastructure.csproj @@ -4,8 +4,14 @@ + + - + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + +