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
+
+