From 7aae87d012661026650c3deb8a91a03b69d07d1f Mon Sep 17 00:00:00 2001 From: "gorbenko.pavel" Date: Wed, 22 Jul 2026 15:05:44 +0500 Subject: [PATCH 1/9] =?UTF-8?q?=D1=81=D0=BE=D0=B7=D0=B4=D0=B0=D0=BD=D1=8B?= =?UTF-8?q?=20=D0=BC=D0=BE=D0=B4=D0=B5=D0=BB=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../.idea.Tnsu.ApprovalRoute/.idea/.gitignore | 15 +++++++++ .../.idea.Tnsu.ApprovalRoute/.idea/.name | 1 + .../.idea/encodings.xml | 4 +++ .../.idea/indexLayout.xml | 8 +++++ .../.idea.Tnsu.ApprovalRoute/.idea/vcs.xml | 6 ++++ backend/src/Tnsu.ApprovalRoute.Api/Program.cs | 3 ++ .../Entities/RequestType.cs | 13 ++++++++ .../Entities/Route.cs | 20 +++++++++++ .../Entities/RouteStep.cs | 19 +++++++++++ .../Enums/RouteStepStatus.cs | 12 +++++++ .../Enums/RouteType.cs | 7 ++++ .../Persistence/ApprovalRouteDbContext.cs | 33 +++++++++++++++++++ 12 files changed, 141 insertions(+) create mode 100644 backend/.idea/.idea.Tnsu.ApprovalRoute/.idea/.gitignore create mode 100644 backend/.idea/.idea.Tnsu.ApprovalRoute/.idea/.name create mode 100644 backend/.idea/.idea.Tnsu.ApprovalRoute/.idea/encodings.xml create mode 100644 backend/.idea/.idea.Tnsu.ApprovalRoute/.idea/indexLayout.xml create mode 100644 backend/.idea/.idea.Tnsu.ApprovalRoute/.idea/vcs.xml create mode 100644 backend/src/Tnsu.ApprovalRoute.Domain/Entities/RequestType.cs create mode 100644 backend/src/Tnsu.ApprovalRoute.Domain/Entities/Route.cs create mode 100644 backend/src/Tnsu.ApprovalRoute.Domain/Entities/RouteStep.cs create mode 100644 backend/src/Tnsu.ApprovalRoute.Domain/Enums/RouteStepStatus.cs create mode 100644 backend/src/Tnsu.ApprovalRoute.Domain/Enums/RouteType.cs 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/src/Tnsu.ApprovalRoute.Api/Program.cs b/backend/src/Tnsu.ApprovalRoute.Api/Program.cs index 6a18908..a1dac74 100644 --- a/backend/src/Tnsu.ApprovalRoute.Api/Program.cs +++ b/backend/src/Tnsu.ApprovalRoute.Api/Program.cs @@ -1,3 +1,6 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; using Tnsu.ApprovalRoute.Application; using Tnsu.ApprovalRoute.Infrastructure; 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..8e531aa --- /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 Guid ProjectId { 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..bf01d87 --- /dev/null +++ b/backend/src/Tnsu.ApprovalRoute.Domain/Entities/RouteStep.cs @@ -0,0 +1,19 @@ +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 Guid ExecutorUserId { get; set; } + public string Position { get; set; } = string.Empty; + + 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/RouteStepStatus.cs b/backend/src/Tnsu.ApprovalRoute.Domain/Enums/RouteStepStatus.cs new file mode 100644 index 0000000..147d9d6 --- /dev/null +++ b/backend/src/Tnsu.ApprovalRoute.Domain/Enums/RouteStepStatus.cs @@ -0,0 +1,12 @@ +namespace Tnsu.ApprovalRoute.Domain.Enums; + +public enum RouteStepStatus +{ + 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..4a042fa --- /dev/null +++ b/backend/src/Tnsu.ApprovalRoute.Domain/Enums/RouteType.cs @@ -0,0 +1,7 @@ +namespace Tnsu.ApprovalRoute.Domain.Enums; + +public enum RouteType +{ + Parallel, + Sequential +} diff --git a/backend/src/Tnsu.ApprovalRoute.Infrastructure/Persistence/ApprovalRouteDbContext.cs b/backend/src/Tnsu.ApprovalRoute.Infrastructure/Persistence/ApprovalRouteDbContext.cs index 6fa2086..c845852 100644 --- a/backend/src/Tnsu.ApprovalRoute.Infrastructure/Persistence/ApprovalRouteDbContext.cs +++ b/backend/src/Tnsu.ApprovalRoute.Infrastructure/Persistence/ApprovalRouteDbContext.cs @@ -1,7 +1,40 @@ 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.ToTable("request_types"); + 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.ToTable("routes"); + 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.ToTable("route_steps"); + e.HasKey(x => x.Id); + e.Property(x => x.Position).HasMaxLength(128).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 }); + }); + } } -- 2.34.1 From 94a1c21ff250cdb829af902a94a8fb04d575257f Mon Sep 17 00:00:00 2001 From: "gorbenko.pavel" Date: Wed, 22 Jul 2026 15:12:59 +0500 Subject: [PATCH 2/9] =?UTF-8?q?=D0=BC=D0=B8=D0=B3=D1=80=D0=B0=D1=86=D0=B8?= =?UTF-8?q?=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../20260722100629_InitialCreate.Designer.cs | 151 ++++++++++++++++++ .../20260722100629_InitialCreate.cs | 97 +++++++++++ .../ApprovalRouteDbContextModelSnapshot.cs | 148 +++++++++++++++++ 3 files changed, 396 insertions(+) create mode 100644 backend/src/Tnsu.ApprovalRoute.Infrastructure/Persistence/Migrations/20260722100629_InitialCreate.Designer.cs create mode 100644 backend/src/Tnsu.ApprovalRoute.Infrastructure/Persistence/Migrations/20260722100629_InitialCreate.cs create mode 100644 backend/src/Tnsu.ApprovalRoute.Infrastructure/Persistence/Migrations/ApprovalRouteDbContextModelSnapshot.cs diff --git a/backend/src/Tnsu.ApprovalRoute.Infrastructure/Persistence/Migrations/20260722100629_InitialCreate.Designer.cs b/backend/src/Tnsu.ApprovalRoute.Infrastructure/Persistence/Migrations/20260722100629_InitialCreate.Designer.cs new file mode 100644 index 0000000..1cc4994 --- /dev/null +++ b/backend/src/Tnsu.ApprovalRoute.Infrastructure/Persistence/Migrations/20260722100629_InitialCreate.Designer.cs @@ -0,0 +1,151 @@ +// +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("20260722100629_InitialCreate")] + partial class InitialCreate + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "10.0.0") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("Tnsu.ApprovalRoute.Domain.Entities.RequestType", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("PageUrl") + .IsRequired() + .HasMaxLength(512) + .HasColumnType("character varying(512)"); + + b.HasKey("Id"); + + b.ToTable("request_types", (string)null); + }); + + modelBuilder.Entity("Tnsu.ApprovalRoute.Domain.Entities.Route", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CompanyId") + .HasColumnType("uuid"); + + b.Property("DepartmentId") + .HasColumnType("uuid"); + + b.Property("ProjectId") + .HasColumnType("uuid"); + + b.Property("RequestTypeId") + .HasColumnType("uuid"); + + b.Property("RequiresControl") + .HasColumnType("boolean"); + + b.Property("RouteType") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)"); + + b.HasKey("Id"); + + b.HasIndex("RequestTypeId"); + + b.ToTable("routes", (string)null); + }); + + modelBuilder.Entity("Tnsu.ApprovalRoute.Domain.Entities.RouteStep", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AllowReassignToOtherApprovers") + .HasColumnType("boolean"); + + b.Property("ExecutorUserId") + .HasColumnType("uuid"); + + b.Property("OrderNo") + .HasColumnType("integer"); + + b.Property("Position") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.Property("RouteId") + .HasColumnType("uuid"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)"); + + b.HasKey("Id"); + + b.HasIndex("RouteId", "OrderNo"); + + 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(); + + 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(); + + 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/20260722100629_InitialCreate.cs b/backend/src/Tnsu.ApprovalRoute.Infrastructure/Persistence/Migrations/20260722100629_InitialCreate.cs new file mode 100644 index 0000000..45c15a9 --- /dev/null +++ b/backend/src/Tnsu.ApprovalRoute.Infrastructure/Persistence/Migrations/20260722100629_InitialCreate.cs @@ -0,0 +1,97 @@ +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), + PageUrl = 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), + RouteType = table.Column(type: "character varying(32)", maxLength: 32, nullable: false), + RequestTypeId = table.Column(type: "uuid", nullable: false), + DepartmentId = table.Column(type: "uuid", nullable: false), + CompanyId = table.Column(type: "uuid", nullable: false), + ProjectId = table.Column(type: "uuid", nullable: false), + RequiresControl = table.Column(type: "boolean", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_routes", x => x.Id); + table.ForeignKey( + name: "FK_routes_request_types_RequestTypeId", + column: x => x.RequestTypeId, + principalTable: "request_types", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "route_steps", + columns: table => new + { + Id = table.Column(type: "uuid", nullable: false), + OrderNo = table.Column(type: "integer", nullable: false), + ExecutorUserId = table.Column(type: "uuid", nullable: false), + Position = table.Column(type: "character varying(128)", maxLength: 128, nullable: false), + Status = table.Column(type: "character varying(32)", maxLength: 32, nullable: false), + RouteId = table.Column(type: "uuid", nullable: false), + AllowReassignToOtherApprovers = table.Column(type: "boolean", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_route_steps", x => x.Id); + table.ForeignKey( + name: "FK_route_steps_routes_RouteId", + column: x => x.RouteId, + principalTable: "routes", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateIndex( + name: "IX_route_steps_RouteId_OrderNo", + table: "route_steps", + columns: new[] { "RouteId", "OrderNo" }); + + migrationBuilder.CreateIndex( + name: "IX_routes_RequestTypeId", + table: "routes", + column: "RequestTypeId"); + } + + /// + 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..80351d9 --- /dev/null +++ b/backend/src/Tnsu.ApprovalRoute.Infrastructure/Persistence/Migrations/ApprovalRouteDbContextModelSnapshot.cs @@ -0,0 +1,148 @@ +// +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.0") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("Tnsu.ApprovalRoute.Domain.Entities.RequestType", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("PageUrl") + .IsRequired() + .HasMaxLength(512) + .HasColumnType("character varying(512)"); + + b.HasKey("Id"); + + b.ToTable("request_types", (string)null); + }); + + modelBuilder.Entity("Tnsu.ApprovalRoute.Domain.Entities.Route", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CompanyId") + .HasColumnType("uuid"); + + b.Property("DepartmentId") + .HasColumnType("uuid"); + + b.Property("ProjectId") + .HasColumnType("uuid"); + + b.Property("RequestTypeId") + .HasColumnType("uuid"); + + b.Property("RequiresControl") + .HasColumnType("boolean"); + + b.Property("RouteType") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)"); + + b.HasKey("Id"); + + b.HasIndex("RequestTypeId"); + + b.ToTable("routes", (string)null); + }); + + modelBuilder.Entity("Tnsu.ApprovalRoute.Domain.Entities.RouteStep", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AllowReassignToOtherApprovers") + .HasColumnType("boolean"); + + b.Property("ExecutorUserId") + .HasColumnType("uuid"); + + b.Property("OrderNo") + .HasColumnType("integer"); + + b.Property("Position") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.Property("RouteId") + .HasColumnType("uuid"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)"); + + b.HasKey("Id"); + + b.HasIndex("RouteId", "OrderNo"); + + 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(); + + 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(); + + 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 + } + } +} -- 2.34.1 From 1d594acfda3b4b14eeb327f1725a0e092046507b Mon Sep 17 00:00:00 2001 From: "gorbenko.pavel" Date: Wed, 22 Jul 2026 15:52:37 +0500 Subject: [PATCH 3/9] =?UTF-8?q?=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=20=D0=B8=D0=BD=D0=B8=D1=86=D0=B8=D0=B0=D0=BB=D0=B8=D0=B7?= =?UTF-8?q?=D0=B0=D1=82=D0=BE=D1=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/Directory.Packages.props | 3 ++- backend/src/Tnsu.ApprovalRoute.Api/Program.cs | 3 ++- .../Tnsu.ApprovalRoute.Api.csproj | 1 + .../Tnsu.ApprovalRoute.Domain/Enums/RouteStepStatus.cs | 1 + .../src/Tnsu.ApprovalRoute.Domain/Enums/RouteType.cs | 1 + .../InfrastructureServiceCollectionExtensions.cs | 2 ++ .../Persistence/DatabaseMigrationInitializer.cs | 10 ++++++++++ .../Tnsu.ApprovalRoute.Infrastructure.csproj | 1 + 8 files changed, 20 insertions(+), 2 deletions(-) create mode 100644 backend/src/Tnsu.ApprovalRoute.Infrastructure/Persistence/DatabaseMigrationInitializer.cs diff --git a/backend/Directory.Packages.props b/backend/Directory.Packages.props index 775e9b8..6dc7798 100644 --- a/backend/Directory.Packages.props +++ b/backend/Directory.Packages.props @@ -3,6 +3,7 @@ true + @@ -10,4 +11,4 @@ - + \ 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 a1dac74..5d1223b 100644 --- a/backend/src/Tnsu.ApprovalRoute.Api/Program.cs +++ b/backend/src/Tnsu.ApprovalRoute.Api/Program.cs @@ -1,3 +1,4 @@ +using Extensions.Hosting.AsyncInitialization; using Microsoft.AspNetCore.Builder; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; @@ -18,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..efc7fdf 100644 --- a/backend/src/Tnsu.ApprovalRoute.Api/Tnsu.ApprovalRoute.Api.csproj +++ b/backend/src/Tnsu.ApprovalRoute.Api/Tnsu.ApprovalRoute.Api.csproj @@ -4,6 +4,7 @@ + diff --git a/backend/src/Tnsu.ApprovalRoute.Domain/Enums/RouteStepStatus.cs b/backend/src/Tnsu.ApprovalRoute.Domain/Enums/RouteStepStatus.cs index 147d9d6..77d1367 100644 --- a/backend/src/Tnsu.ApprovalRoute.Domain/Enums/RouteStepStatus.cs +++ b/backend/src/Tnsu.ApprovalRoute.Domain/Enums/RouteStepStatus.cs @@ -2,6 +2,7 @@ namespace Tnsu.ApprovalRoute.Domain.Enums; public enum RouteStepStatus { + None, Draft, OnApproval, Approved, diff --git a/backend/src/Tnsu.ApprovalRoute.Domain/Enums/RouteType.cs b/backend/src/Tnsu.ApprovalRoute.Domain/Enums/RouteType.cs index 4a042fa..8004453 100644 --- a/backend/src/Tnsu.ApprovalRoute.Domain/Enums/RouteType.cs +++ b/backend/src/Tnsu.ApprovalRoute.Domain/Enums/RouteType.cs @@ -2,6 +2,7 @@ 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..7a70fcf 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; @@ -12,6 +13,7 @@ public static class InfrastructureServiceCollectionExtensions { services.AddDbContext(opt => opt.UseNpgsql(configuration.GetConnectionString("Postgres"))); + services.AddAsyncInitializer(); return services; } 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/Tnsu.ApprovalRoute.Infrastructure.csproj b/backend/src/Tnsu.ApprovalRoute.Infrastructure/Tnsu.ApprovalRoute.Infrastructure.csproj index f268684..ef0f30b 100644 --- a/backend/src/Tnsu.ApprovalRoute.Infrastructure/Tnsu.ApprovalRoute.Infrastructure.csproj +++ b/backend/src/Tnsu.ApprovalRoute.Infrastructure/Tnsu.ApprovalRoute.Infrastructure.csproj @@ -4,6 +4,7 @@ + -- 2.34.1 From 9cb2a86aaa13036ae0cb1a78d6cbe4d7fab479e9 Mon Sep 17 00:00:00 2001 From: "gorbenko.pavel" Date: Wed, 22 Jul 2026 16:06:56 +0500 Subject: [PATCH 4/9] use snakecase naming convention --- backend/Directory.Packages.props | 13 +++++++------ .../InfrastructureServiceCollectionExtensions.cs | 3 ++- .../Persistence/ApprovalRouteDbContext.cs | 3 --- .../Tnsu.ApprovalRoute.Infrastructure.csproj | 6 +++++- 4 files changed, 14 insertions(+), 11 deletions(-) diff --git a/backend/Directory.Packages.props b/backend/Directory.Packages.props index 6dc7798..8efa8f5 100644 --- a/backend/Directory.Packages.props +++ b/backend/Directory.Packages.props @@ -3,12 +3,13 @@ true + - - - - - - + + + + + + \ No newline at end of file diff --git a/backend/src/Tnsu.ApprovalRoute.Infrastructure/InfrastructureServiceCollectionExtensions.cs b/backend/src/Tnsu.ApprovalRoute.Infrastructure/InfrastructureServiceCollectionExtensions.cs index 7a70fcf..a006dd4 100644 --- a/backend/src/Tnsu.ApprovalRoute.Infrastructure/InfrastructureServiceCollectionExtensions.cs +++ b/backend/src/Tnsu.ApprovalRoute.Infrastructure/InfrastructureServiceCollectionExtensions.cs @@ -12,7 +12,8 @@ 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 c845852..1dba8f5 100644 --- a/backend/src/Tnsu.ApprovalRoute.Infrastructure/Persistence/ApprovalRouteDbContext.cs +++ b/backend/src/Tnsu.ApprovalRoute.Infrastructure/Persistence/ApprovalRouteDbContext.cs @@ -13,7 +13,6 @@ public class ApprovalRouteDbContext(DbContextOptions opt { modelBuilder.Entity(e => { - e.ToTable("request_types"); e.HasKey(x => x.Id); e.Property(x => x.Name).HasMaxLength(256).IsRequired(); e.Property(x => x.PageUrl).HasMaxLength(512).IsRequired(); @@ -21,7 +20,6 @@ public class ApprovalRouteDbContext(DbContextOptions opt modelBuilder.Entity(e => { - e.ToTable("routes"); 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); @@ -29,7 +27,6 @@ public class ApprovalRouteDbContext(DbContextOptions opt modelBuilder.Entity(e => { - e.ToTable("route_steps"); e.HasKey(x => x.Id); e.Property(x => x.Position).HasMaxLength(128).IsRequired(); e.Property(x => x.Status).HasConversion().HasMaxLength(32).IsRequired(); diff --git a/backend/src/Tnsu.ApprovalRoute.Infrastructure/Tnsu.ApprovalRoute.Infrastructure.csproj b/backend/src/Tnsu.ApprovalRoute.Infrastructure/Tnsu.ApprovalRoute.Infrastructure.csproj index ef0f30b..7e08a20 100644 --- a/backend/src/Tnsu.ApprovalRoute.Infrastructure/Tnsu.ApprovalRoute.Infrastructure.csproj +++ b/backend/src/Tnsu.ApprovalRoute.Infrastructure/Tnsu.ApprovalRoute.Infrastructure.csproj @@ -4,9 +4,13 @@ + - + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + -- 2.34.1 From 53ebb2306a855d2d85541ab05aa9828dca41cdfc Mon Sep 17 00:00:00 2001 From: "gorbenko.pavel" Date: Wed, 22 Jul 2026 16:10:06 +0500 Subject: [PATCH 5/9] =?UTF-8?q?=D1=83=D0=B4=D0=B0=D0=BB=D0=B8=D0=BB=20?= =?UTF-8?q?=D0=BC=D0=B8=D0=B3=D1=80=D0=B0=D1=86=D0=B8=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../20260722100629_InitialCreate.Designer.cs | 151 ------------------ .../20260722100629_InitialCreate.cs | 97 ----------- .../ApprovalRouteDbContextModelSnapshot.cs | 148 ----------------- .../Tnsu.ApprovalRoute.Infrastructure.csproj | 3 + 4 files changed, 3 insertions(+), 396 deletions(-) delete mode 100644 backend/src/Tnsu.ApprovalRoute.Infrastructure/Persistence/Migrations/20260722100629_InitialCreate.Designer.cs delete mode 100644 backend/src/Tnsu.ApprovalRoute.Infrastructure/Persistence/Migrations/20260722100629_InitialCreate.cs delete mode 100644 backend/src/Tnsu.ApprovalRoute.Infrastructure/Persistence/Migrations/ApprovalRouteDbContextModelSnapshot.cs diff --git a/backend/src/Tnsu.ApprovalRoute.Infrastructure/Persistence/Migrations/20260722100629_InitialCreate.Designer.cs b/backend/src/Tnsu.ApprovalRoute.Infrastructure/Persistence/Migrations/20260722100629_InitialCreate.Designer.cs deleted file mode 100644 index 1cc4994..0000000 --- a/backend/src/Tnsu.ApprovalRoute.Infrastructure/Persistence/Migrations/20260722100629_InitialCreate.Designer.cs +++ /dev/null @@ -1,151 +0,0 @@ -// -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("20260722100629_InitialCreate")] - partial class InitialCreate - { - /// - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "10.0.0") - .HasAnnotation("Relational:MaxIdentifierLength", 63); - - NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); - - modelBuilder.Entity("Tnsu.ApprovalRoute.Domain.Entities.RequestType", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.Property("PageUrl") - .IsRequired() - .HasMaxLength(512) - .HasColumnType("character varying(512)"); - - b.HasKey("Id"); - - b.ToTable("request_types", (string)null); - }); - - modelBuilder.Entity("Tnsu.ApprovalRoute.Domain.Entities.Route", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("CompanyId") - .HasColumnType("uuid"); - - b.Property("DepartmentId") - .HasColumnType("uuid"); - - b.Property("ProjectId") - .HasColumnType("uuid"); - - b.Property("RequestTypeId") - .HasColumnType("uuid"); - - b.Property("RequiresControl") - .HasColumnType("boolean"); - - b.Property("RouteType") - .IsRequired() - .HasMaxLength(32) - .HasColumnType("character varying(32)"); - - b.HasKey("Id"); - - b.HasIndex("RequestTypeId"); - - b.ToTable("routes", (string)null); - }); - - modelBuilder.Entity("Tnsu.ApprovalRoute.Domain.Entities.RouteStep", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("AllowReassignToOtherApprovers") - .HasColumnType("boolean"); - - b.Property("ExecutorUserId") - .HasColumnType("uuid"); - - b.Property("OrderNo") - .HasColumnType("integer"); - - b.Property("Position") - .IsRequired() - .HasMaxLength(128) - .HasColumnType("character varying(128)"); - - b.Property("RouteId") - .HasColumnType("uuid"); - - b.Property("Status") - .IsRequired() - .HasMaxLength(32) - .HasColumnType("character varying(32)"); - - b.HasKey("Id"); - - b.HasIndex("RouteId", "OrderNo"); - - 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(); - - 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(); - - 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/20260722100629_InitialCreate.cs b/backend/src/Tnsu.ApprovalRoute.Infrastructure/Persistence/Migrations/20260722100629_InitialCreate.cs deleted file mode 100644 index 45c15a9..0000000 --- a/backend/src/Tnsu.ApprovalRoute.Infrastructure/Persistence/Migrations/20260722100629_InitialCreate.cs +++ /dev/null @@ -1,97 +0,0 @@ -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), - PageUrl = 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), - RouteType = table.Column(type: "character varying(32)", maxLength: 32, nullable: false), - RequestTypeId = table.Column(type: "uuid", nullable: false), - DepartmentId = table.Column(type: "uuid", nullable: false), - CompanyId = table.Column(type: "uuid", nullable: false), - ProjectId = table.Column(type: "uuid", nullable: false), - RequiresControl = table.Column(type: "boolean", nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_routes", x => x.Id); - table.ForeignKey( - name: "FK_routes_request_types_RequestTypeId", - column: x => x.RequestTypeId, - principalTable: "request_types", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "route_steps", - columns: table => new - { - Id = table.Column(type: "uuid", nullable: false), - OrderNo = table.Column(type: "integer", nullable: false), - ExecutorUserId = table.Column(type: "uuid", nullable: false), - Position = table.Column(type: "character varying(128)", maxLength: 128, nullable: false), - Status = table.Column(type: "character varying(32)", maxLength: 32, nullable: false), - RouteId = table.Column(type: "uuid", nullable: false), - AllowReassignToOtherApprovers = table.Column(type: "boolean", nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_route_steps", x => x.Id); - table.ForeignKey( - name: "FK_route_steps_routes_RouteId", - column: x => x.RouteId, - principalTable: "routes", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateIndex( - name: "IX_route_steps_RouteId_OrderNo", - table: "route_steps", - columns: new[] { "RouteId", "OrderNo" }); - - migrationBuilder.CreateIndex( - name: "IX_routes_RequestTypeId", - table: "routes", - column: "RequestTypeId"); - } - - /// - 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 deleted file mode 100644 index 80351d9..0000000 --- a/backend/src/Tnsu.ApprovalRoute.Infrastructure/Persistence/Migrations/ApprovalRouteDbContextModelSnapshot.cs +++ /dev/null @@ -1,148 +0,0 @@ -// -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.0") - .HasAnnotation("Relational:MaxIdentifierLength", 63); - - NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); - - modelBuilder.Entity("Tnsu.ApprovalRoute.Domain.Entities.RequestType", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.Property("PageUrl") - .IsRequired() - .HasMaxLength(512) - .HasColumnType("character varying(512)"); - - b.HasKey("Id"); - - b.ToTable("request_types", (string)null); - }); - - modelBuilder.Entity("Tnsu.ApprovalRoute.Domain.Entities.Route", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("CompanyId") - .HasColumnType("uuid"); - - b.Property("DepartmentId") - .HasColumnType("uuid"); - - b.Property("ProjectId") - .HasColumnType("uuid"); - - b.Property("RequestTypeId") - .HasColumnType("uuid"); - - b.Property("RequiresControl") - .HasColumnType("boolean"); - - b.Property("RouteType") - .IsRequired() - .HasMaxLength(32) - .HasColumnType("character varying(32)"); - - b.HasKey("Id"); - - b.HasIndex("RequestTypeId"); - - b.ToTable("routes", (string)null); - }); - - modelBuilder.Entity("Tnsu.ApprovalRoute.Domain.Entities.RouteStep", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("AllowReassignToOtherApprovers") - .HasColumnType("boolean"); - - b.Property("ExecutorUserId") - .HasColumnType("uuid"); - - b.Property("OrderNo") - .HasColumnType("integer"); - - b.Property("Position") - .IsRequired() - .HasMaxLength(128) - .HasColumnType("character varying(128)"); - - b.Property("RouteId") - .HasColumnType("uuid"); - - b.Property("Status") - .IsRequired() - .HasMaxLength(32) - .HasColumnType("character varying(32)"); - - b.HasKey("Id"); - - b.HasIndex("RouteId", "OrderNo"); - - 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(); - - 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(); - - 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 7e08a20..7822620 100644 --- a/backend/src/Tnsu.ApprovalRoute.Infrastructure/Tnsu.ApprovalRoute.Infrastructure.csproj +++ b/backend/src/Tnsu.ApprovalRoute.Infrastructure/Tnsu.ApprovalRoute.Infrastructure.csproj @@ -13,4 +13,7 @@ + + + -- 2.34.1 From 0bf14e705558e6efffbd437228204dfc611391cd Mon Sep 17 00:00:00 2001 From: "gorbenko.pavel" Date: Wed, 22 Jul 2026 16:23:48 +0500 Subject: [PATCH 6/9] =?UTF-8?q?=D0=BD=D0=B5=D0=B4=D0=BE=D1=81=D1=82=D0=B0?= =?UTF-8?q?=D1=8E=D1=89=D0=B8=D0=B9=20=D0=BF=D0=B0=D0=BA=D0=B5=D1=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/Directory.Packages.props | 1 + .../Tnsu.ApprovalRoute.Infrastructure.csproj | 1 + 2 files changed, 2 insertions(+) diff --git a/backend/Directory.Packages.props b/backend/Directory.Packages.props index 8efa8f5..0217988 100644 --- a/backend/Directory.Packages.props +++ b/backend/Directory.Packages.props @@ -9,6 +9,7 @@ + diff --git a/backend/src/Tnsu.ApprovalRoute.Infrastructure/Tnsu.ApprovalRoute.Infrastructure.csproj b/backend/src/Tnsu.ApprovalRoute.Infrastructure/Tnsu.ApprovalRoute.Infrastructure.csproj index 7822620..848894b 100644 --- a/backend/src/Tnsu.ApprovalRoute.Infrastructure/Tnsu.ApprovalRoute.Infrastructure.csproj +++ b/backend/src/Tnsu.ApprovalRoute.Infrastructure/Tnsu.ApprovalRoute.Infrastructure.csproj @@ -11,6 +11,7 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive + -- 2.34.1 From 4cf282887dae9ec7dee6d23822bc6483e882d814 Mon Sep 17 00:00:00 2001 From: "gorbenko.pavel" Date: Wed, 22 Jul 2026 16:26:12 +0500 Subject: [PATCH 7/9] =?UTF-8?q?=D0=BF=D0=B0=D0=BA=D0=B5=D1=82=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/Tnsu.ApprovalRoute.Api/Tnsu.ApprovalRoute.Api.csproj | 4 ++++ .../Tnsu.ApprovalRoute.Infrastructure.csproj | 3 --- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/backend/src/Tnsu.ApprovalRoute.Api/Tnsu.ApprovalRoute.Api.csproj b/backend/src/Tnsu.ApprovalRoute.Api/Tnsu.ApprovalRoute.Api.csproj index efc7fdf..325ff39 100644 --- a/backend/src/Tnsu.ApprovalRoute.Api/Tnsu.ApprovalRoute.Api.csproj +++ b/backend/src/Tnsu.ApprovalRoute.Api/Tnsu.ApprovalRoute.Api.csproj @@ -8,5 +8,9 @@ + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + diff --git a/backend/src/Tnsu.ApprovalRoute.Infrastructure/Tnsu.ApprovalRoute.Infrastructure.csproj b/backend/src/Tnsu.ApprovalRoute.Infrastructure/Tnsu.ApprovalRoute.Infrastructure.csproj index 848894b..79b63af 100644 --- a/backend/src/Tnsu.ApprovalRoute.Infrastructure/Tnsu.ApprovalRoute.Infrastructure.csproj +++ b/backend/src/Tnsu.ApprovalRoute.Infrastructure/Tnsu.ApprovalRoute.Infrastructure.csproj @@ -14,7 +14,4 @@ - - - -- 2.34.1 From 30a70c208de56cdca0d24c047964d70b1250c739 Mon Sep 17 00:00:00 2001 From: "gorbenko.pavel" Date: Wed, 22 Jul 2026 16:26:55 +0500 Subject: [PATCH 8/9] =?UTF-8?q?=D0=BC=D0=B8=D0=B3=D1=80=D0=B0=D1=86=D0=B8?= =?UTF-8?q?=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../20260722112539_InitialCreate.Designer.cs | 175 ++++++++++++++++++ .../20260722112539_InitialCreate.cs | 97 ++++++++++ .../ApprovalRouteDbContextModelSnapshot.cs | 172 +++++++++++++++++ 3 files changed, 444 insertions(+) create mode 100644 backend/src/Tnsu.ApprovalRoute.Infrastructure/Persistence/Migrations/20260722112539_InitialCreate.Designer.cs create mode 100644 backend/src/Tnsu.ApprovalRoute.Infrastructure/Persistence/Migrations/20260722112539_InitialCreate.cs create mode 100644 backend/src/Tnsu.ApprovalRoute.Infrastructure/Persistence/Migrations/ApprovalRouteDbContextModelSnapshot.cs diff --git a/backend/src/Tnsu.ApprovalRoute.Infrastructure/Persistence/Migrations/20260722112539_InitialCreate.Designer.cs b/backend/src/Tnsu.ApprovalRoute.Infrastructure/Persistence/Migrations/20260722112539_InitialCreate.Designer.cs new file mode 100644 index 0000000..25f2078 --- /dev/null +++ b/backend/src/Tnsu.ApprovalRoute.Infrastructure/Persistence/Migrations/20260722112539_InitialCreate.Designer.cs @@ -0,0 +1,175 @@ +// +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("20260722112539_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("CompanyId") + .HasColumnType("uuid") + .HasColumnName("company_id"); + + b.Property("DepartmentId") + .HasColumnType("uuid") + .HasColumnName("department_id"); + + b.Property("ProjectId") + .HasColumnType("uuid") + .HasColumnName("project_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("ExecutorUserId") + .HasColumnType("uuid") + .HasColumnName("executor_user_id"); + + b.Property("OrderNo") + .HasColumnType("integer") + .HasColumnName("order_no"); + + b.Property("Position") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("character varying(128)") + .HasColumnName("position"); + + 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/20260722112539_InitialCreate.cs b/backend/src/Tnsu.ApprovalRoute.Infrastructure/Persistence/Migrations/20260722112539_InitialCreate.cs new file mode 100644 index 0000000..9d893ca --- /dev/null +++ b/backend/src/Tnsu.ApprovalRoute.Infrastructure/Persistence/Migrations/20260722112539_InitialCreate.cs @@ -0,0 +1,97 @@ +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), + project_id = table.Column(type: "uuid", 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_user_id = table.Column(type: "uuid", nullable: false), + position = table.Column(type: "character varying(128)", maxLength: 128, 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..bc98f9b --- /dev/null +++ b/backend/src/Tnsu.ApprovalRoute.Infrastructure/Persistence/Migrations/ApprovalRouteDbContextModelSnapshot.cs @@ -0,0 +1,172 @@ +// +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("CompanyId") + .HasColumnType("uuid") + .HasColumnName("company_id"); + + b.Property("DepartmentId") + .HasColumnType("uuid") + .HasColumnName("department_id"); + + b.Property("ProjectId") + .HasColumnType("uuid") + .HasColumnName("project_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("ExecutorUserId") + .HasColumnType("uuid") + .HasColumnName("executor_user_id"); + + b.Property("OrderNo") + .HasColumnType("integer") + .HasColumnName("order_no"); + + b.Property("Position") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("character varying(128)") + .HasColumnName("position"); + + 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 + } + } +} -- 2.34.1 From db566529f10c31dc97bc3d039290788369be9119 Mon Sep 17 00:00:00 2001 From: "gorbenko.pavel" Date: Wed, 22 Jul 2026 18:06:23 +0500 Subject: [PATCH 9/9] =?UTF-8?q?=D0=BF=D1=80=D0=B0=D0=B2=D0=BA=D0=B8=20?= =?UTF-8?q?=D0=BF=D0=BE=20=D1=80=D0=B5=D0=B2=D1=8C=D1=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Entities/Route.cs | 2 +- .../Entities/RouteStep.cs | 3 ++- .../Enums/ProjectRole.cs | 9 +++++++ .../Persistence/ApprovalRouteDbContext.cs | 2 ++ ... 20260722130455_InitialCreate.Designer.cs} | 24 ++++++++++++------- ...ate.cs => 20260722130455_InitialCreate.cs} | 5 ++-- .../ApprovalRouteDbContextModelSnapshot.cs | 22 +++++++++++------ 7 files changed, 48 insertions(+), 19 deletions(-) create mode 100644 backend/src/Tnsu.ApprovalRoute.Domain/Enums/ProjectRole.cs rename backend/src/Tnsu.ApprovalRoute.Infrastructure/Persistence/Migrations/{20260722112539_InitialCreate.Designer.cs => 20260722130455_InitialCreate.Designer.cs} (89%) rename backend/src/Tnsu.ApprovalRoute.Infrastructure/Persistence/Migrations/{20260722112539_InitialCreate.cs => 20260722130455_InitialCreate.cs} (92%) diff --git a/backend/src/Tnsu.ApprovalRoute.Domain/Entities/Route.cs b/backend/src/Tnsu.ApprovalRoute.Domain/Entities/Route.cs index 8e531aa..2df9be2 100644 --- a/backend/src/Tnsu.ApprovalRoute.Domain/Entities/Route.cs +++ b/backend/src/Tnsu.ApprovalRoute.Domain/Entities/Route.cs @@ -11,7 +11,7 @@ public class Route // Внешние справочники (1С/ZUP) — хранятся как ссылки без FK в этой БД. public Guid DepartmentId { get; set; } public Guid CompanyId { get; set; } - public Guid ProjectId { get; set; } + public bool ByProject { get; set; } public bool RequiresControl { get; set; } diff --git a/backend/src/Tnsu.ApprovalRoute.Domain/Entities/RouteStep.cs b/backend/src/Tnsu.ApprovalRoute.Domain/Entities/RouteStep.cs index bf01d87..a70ef8c 100644 --- a/backend/src/Tnsu.ApprovalRoute.Domain/Entities/RouteStep.cs +++ b/backend/src/Tnsu.ApprovalRoute.Domain/Entities/RouteStep.cs @@ -8,8 +8,9 @@ public class RouteStep public int OrderNo { get; set; } // Внешняя ссылка на пользователя (1С/ZUP) — без локальной таблицы Users. - public Guid ExecutorUserId { get; set; } + 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; } 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.Infrastructure/Persistence/ApprovalRouteDbContext.cs b/backend/src/Tnsu.ApprovalRoute.Infrastructure/Persistence/ApprovalRouteDbContext.cs index 1dba8f5..080ae1f 100644 --- a/backend/src/Tnsu.ApprovalRoute.Infrastructure/Persistence/ApprovalRouteDbContext.cs +++ b/backend/src/Tnsu.ApprovalRoute.Infrastructure/Persistence/ApprovalRouteDbContext.cs @@ -28,7 +28,9 @@ public class ApprovalRouteDbContext(DbContextOptions opt 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/Migrations/20260722112539_InitialCreate.Designer.cs b/backend/src/Tnsu.ApprovalRoute.Infrastructure/Persistence/Migrations/20260722130455_InitialCreate.Designer.cs similarity index 89% rename from backend/src/Tnsu.ApprovalRoute.Infrastructure/Persistence/Migrations/20260722112539_InitialCreate.Designer.cs rename to backend/src/Tnsu.ApprovalRoute.Infrastructure/Persistence/Migrations/20260722130455_InitialCreate.Designer.cs index 25f2078..475d855 100644 --- a/backend/src/Tnsu.ApprovalRoute.Infrastructure/Persistence/Migrations/20260722112539_InitialCreate.Designer.cs +++ b/backend/src/Tnsu.ApprovalRoute.Infrastructure/Persistence/Migrations/20260722130455_InitialCreate.Designer.cs @@ -12,7 +12,7 @@ using Tnsu.ApprovalRoute.Infrastructure.Persistence; namespace Tnsu.ApprovalRoute.Infrastructure.Persistence.Migrations { [DbContext(typeof(ApprovalRouteDbContext))] - [Migration("20260722112539_InitialCreate")] + [Migration("20260722130455_InitialCreate")] partial class InitialCreate { /// @@ -57,6 +57,10 @@ namespace Tnsu.ApprovalRoute.Infrastructure.Persistence.Migrations .HasColumnType("uuid") .HasColumnName("id"); + b.Property("ByProject") + .HasColumnType("boolean") + .HasColumnName("by_project"); + b.Property("CompanyId") .HasColumnType("uuid") .HasColumnName("company_id"); @@ -65,10 +69,6 @@ namespace Tnsu.ApprovalRoute.Infrastructure.Persistence.Migrations .HasColumnType("uuid") .HasColumnName("department_id"); - b.Property("ProjectId") - .HasColumnType("uuid") - .HasColumnName("project_id"); - b.Property("RequestTypeId") .HasColumnType("uuid") .HasColumnName("request_type_id"); @@ -103,9 +103,11 @@ namespace Tnsu.ApprovalRoute.Infrastructure.Persistence.Migrations .HasColumnType("boolean") .HasColumnName("allow_reassign_to_other_approvers"); - b.Property("ExecutorUserId") - .HasColumnType("uuid") - .HasColumnName("executor_user_id"); + b.Property("ExecutorEmail") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("executor_email"); b.Property("OrderNo") .HasColumnType("integer") @@ -117,6 +119,12 @@ namespace Tnsu.ApprovalRoute.Infrastructure.Persistence.Migrations .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"); diff --git a/backend/src/Tnsu.ApprovalRoute.Infrastructure/Persistence/Migrations/20260722112539_InitialCreate.cs b/backend/src/Tnsu.ApprovalRoute.Infrastructure/Persistence/Migrations/20260722130455_InitialCreate.cs similarity index 92% rename from backend/src/Tnsu.ApprovalRoute.Infrastructure/Persistence/Migrations/20260722112539_InitialCreate.cs rename to backend/src/Tnsu.ApprovalRoute.Infrastructure/Persistence/Migrations/20260722130455_InitialCreate.cs index 9d893ca..772cbab 100644 --- a/backend/src/Tnsu.ApprovalRoute.Infrastructure/Persistence/Migrations/20260722112539_InitialCreate.cs +++ b/backend/src/Tnsu.ApprovalRoute.Infrastructure/Persistence/Migrations/20260722130455_InitialCreate.cs @@ -33,7 +33,7 @@ namespace Tnsu.ApprovalRoute.Infrastructure.Persistence.Migrations 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), - project_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 => @@ -53,8 +53,9 @@ namespace Tnsu.ApprovalRoute.Infrastructure.Persistence.Migrations { id = table.Column(type: "uuid", nullable: false), order_no = table.Column(type: "integer", nullable: false), - executor_user_id = table.Column(type: "uuid", 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) diff --git a/backend/src/Tnsu.ApprovalRoute.Infrastructure/Persistence/Migrations/ApprovalRouteDbContextModelSnapshot.cs b/backend/src/Tnsu.ApprovalRoute.Infrastructure/Persistence/Migrations/ApprovalRouteDbContextModelSnapshot.cs index bc98f9b..26f31c4 100644 --- a/backend/src/Tnsu.ApprovalRoute.Infrastructure/Persistence/Migrations/ApprovalRouteDbContextModelSnapshot.cs +++ b/backend/src/Tnsu.ApprovalRoute.Infrastructure/Persistence/Migrations/ApprovalRouteDbContextModelSnapshot.cs @@ -54,6 +54,10 @@ namespace Tnsu.ApprovalRoute.Infrastructure.Persistence.Migrations .HasColumnType("uuid") .HasColumnName("id"); + b.Property("ByProject") + .HasColumnType("boolean") + .HasColumnName("by_project"); + b.Property("CompanyId") .HasColumnType("uuid") .HasColumnName("company_id"); @@ -62,10 +66,6 @@ namespace Tnsu.ApprovalRoute.Infrastructure.Persistence.Migrations .HasColumnType("uuid") .HasColumnName("department_id"); - b.Property("ProjectId") - .HasColumnType("uuid") - .HasColumnName("project_id"); - b.Property("RequestTypeId") .HasColumnType("uuid") .HasColumnName("request_type_id"); @@ -100,9 +100,11 @@ namespace Tnsu.ApprovalRoute.Infrastructure.Persistence.Migrations .HasColumnType("boolean") .HasColumnName("allow_reassign_to_other_approvers"); - b.Property("ExecutorUserId") - .HasColumnType("uuid") - .HasColumnName("executor_user_id"); + b.Property("ExecutorEmail") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("executor_email"); b.Property("OrderNo") .HasColumnType("integer") @@ -114,6 +116,12 @@ namespace Tnsu.ApprovalRoute.Infrastructure.Persistence.Migrations .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"); -- 2.34.1