refactor(gateway): 优化网关服务逻辑,修改Id类型并引入存储接口
Some checks failed
Build / build (push) Failing after 41s
Deploy to K8s / deploy (push) Failing after 2s
Build and Push Docker / build (push) Failing after 17s

- 将网关服务相关实体Id类型由long改为string,统一使用Guid V7格式Id
- 新增ConsoleDbContext,配置数据库表命名规范,适配PostgreSQL约定
- 引入IRouteStore和IInstanceStore接口,替代直接使用DbContext访问数据库
- 修改GatewayService实现,调用存储接口进行数据操作以支持解耦扩展
- 调整GatewayController中实例Id参数类型为string,保证一致性
- 更新GatewayDto中各实体的Id类型为string,确保与数据库模型匹配
- 在项目配置中添加EntityFrameworkCore.Design依赖及版本更新
- 新增DesignTimeDbContextFactory方便迁移和设计时上下文创建
- 删除appsettings.json中的GatewayConnection配置,简化连接字符串配置
This commit is contained in:
movingsam 2026-03-01 13:33:02 +08:00
parent 634e6fe455
commit 7f645ddd13
14 changed files with 2702 additions and 117 deletions

View File

@ -4,7 +4,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<!-- Microsoft Packages --> <!-- Microsoft Packages -->
<PackageVersion Include="Fengling.Platform.Infrastructure" Version="1.0.10" /> <PackageVersion Include="Fengling.Platform.Infrastructure" Version="1.0.11" />
<PackageVersion Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="10.0.3" /> <PackageVersion Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="10.0.3" />
<PackageVersion Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="10.0.3" /> <PackageVersion Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="10.0.3" />
<PackageVersion Include="Microsoft.AspNetCore.OpenApi" Version="10.0.2" /> <PackageVersion Include="Microsoft.AspNetCore.OpenApi" Version="10.0.2" />
@ -13,6 +13,7 @@
<PackageVersion Include="NetCorePal.Extensions.AspNetCore" Version="3.2.1" /> <PackageVersion Include="NetCorePal.Extensions.AspNetCore" Version="3.2.1" />
<PackageVersion Include="NetCorePal.Extensions.DistributedLocks.Redis" Version="3.2.1" /> <PackageVersion Include="NetCorePal.Extensions.DistributedLocks.Redis" Version="3.2.1" />
<!-- Database --> <!-- Database -->
<PackageVersion Include="Microsoft.EntityFrameworkCore.Design" Version="10.0.0" />
<PackageVersion Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="10.0.0" /> <PackageVersion Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="10.0.0" />
<!-- OpenIddict (version must match Fengling.Platform) --> <!-- OpenIddict (version must match Fengling.Platform) -->
<PackageVersion Include="OpenIddict.Abstractions" Version="7.2.0" /> <PackageVersion Include="OpenIddict.Abstractions" Version="7.2.0" />
@ -26,4 +27,4 @@
<PackageVersion Include="SkiaSharp" Version="3.119.2" /> <PackageVersion Include="SkiaSharp" Version="3.119.2" />
<PackageVersion Include="QRCoder" Version="1.7.0" /> <PackageVersion Include="QRCoder" Version="1.7.0" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -285,7 +285,7 @@ public class GatewayController(IGatewayService gatewayService, ILogger<GatewayCo
[ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(typeof(object), StatusCodes.Status404NotFound)] [ProducesResponseType(typeof(object), StatusCodes.Status404NotFound)]
[ProducesResponseType(typeof(object), StatusCodes.Status500InternalServerError)] [ProducesResponseType(typeof(object), StatusCodes.Status500InternalServerError)]
public async Task<ActionResult> RemoveInstance(long instanceId) public async Task<ActionResult> RemoveInstance(string instanceId)
{ {
try try
{ {
@ -317,7 +317,7 @@ public class GatewayController(IGatewayService gatewayService, ILogger<GatewayCo
[ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(typeof(object), StatusCodes.Status404NotFound)] [ProducesResponseType(typeof(object), StatusCodes.Status404NotFound)]
[ProducesResponseType(typeof(object), StatusCodes.Status500InternalServerError)] [ProducesResponseType(typeof(object), StatusCodes.Status500InternalServerError)]
public async Task<ActionResult> UpdateWeight(long instanceId, [FromBody] GatewayUpdateWeightDto dto) public async Task<ActionResult> UpdateWeight(string instanceId, [FromBody] GatewayUpdateWeightDto dto)
{ {
try try
{ {

View File

@ -0,0 +1,77 @@
using Fengling.Platform.Domain.AggregatesModel.GatewayAggregate;
using Fengling.Platform.Domain.AggregatesModel.RoleAggregate;
using Fengling.Platform.Domain.AggregatesModel.TenantAggregate;
using Fengling.Platform.Domain.AggregatesModel.UserAggregate;
using Fengling.Platform.Infrastructure;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
namespace Fengling.Console.Data;
/// <summary>
/// Console 项目的 DbContext继承 PlatformDbContext 并配置表命名规范
/// PostgreSQL 命名规范:小写字母 + 下划线,模块前缀
/// </summary>
public class ConsoleDbContext : PlatformDbContext
{
public ConsoleDbContext(DbContextOptions<ConsoleDbContext> options) : base(options)
{
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
// ========== Gateway 模块 ==========
modelBuilder.Entity<GwTenant>(entity =>
{
entity.ToTable("gw_tenants");
});
modelBuilder.Entity<GwTenantRoute>(entity =>
{
entity.ToTable("gw_tenant_routes");
});
modelBuilder.Entity<GwServiceInstance>(entity =>
{
entity.ToTable("gw_service_instances");
});
// ========== Tenant 模块 ==========
modelBuilder.Entity<Tenant>(entity =>
{
entity.ToTable("sys_tenants");
});
// ========== Audit 模块 ==========
modelBuilder.Entity<AccessLog>(entity =>
{
entity.ToTable("sys_access_logs");
});
modelBuilder.Entity<AuditLog>(entity =>
{
entity.ToTable("sys_audit_logs");
});
// ========== Identity 模块 ==========
modelBuilder.Entity<ApplicationUser>(entity =>
{
entity.ToTable("idn_users");
});
modelBuilder.Entity<ApplicationRole>(entity =>
{
entity.ToTable("idn_roles");
});
// Identity tables - custom names
modelBuilder.Entity<IdentityUserClaim<long>>(entity => entity.ToTable("idn_user_claims"));
modelBuilder.Entity<IdentityRoleClaim<long>>(entity => entity.ToTable("idn_role_claims"));
modelBuilder.Entity<IdentityUserLogin<long>>(entity => entity.ToTable("idn_user_logins"));
modelBuilder.Entity<IdentityUserToken<long>>(entity => entity.ToTable("idn_user_tokens"));
modelBuilder.Entity<IdentityUserRole<long>>(entity => entity.ToTable("idn_user_roles"));
}
}

View File

@ -0,0 +1,15 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Design;
using Microsoft.EntityFrameworkCore.Infrastructure;
namespace Fengling.Console.Data;
public class DesignTimeDbContextFactory : IDesignTimeDbContextFactory<ConsoleDbContext>
{
public ConsoleDbContext CreateDbContext(string[] args)
{
var optionsBuilder = new DbContextOptionsBuilder<ConsoleDbContext>();
optionsBuilder.UseNpgsql("Host=81.68.223.70;Port=15432;Database=fengling_auth;Username=movingsam;Password=sl52788542");
return new ConsoleDbContext(optionsBuilder.Options);
}
}

View File

@ -19,6 +19,7 @@
<PackageReference Include="Fengling.Platform.Infrastructure" /> <PackageReference Include="Fengling.Platform.Infrastructure" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" /> <PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" />
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" /> <PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" />
<PackageReference Include="Microsoft.OpenApi" /> <PackageReference Include="Microsoft.OpenApi" />
<PackageReference Include="NetCorePal.Extensions.AspNetCore" /> <PackageReference Include="NetCorePal.Extensions.AspNetCore" />
<PackageReference Include="NetCorePal.Extensions.DistributedLocks.Redis" /> <PackageReference Include="NetCorePal.Extensions.DistributedLocks.Redis" />
@ -33,5 +34,4 @@
<PackageReference Include="Swashbuckle.AspNetCore" /> <PackageReference Include="Swashbuckle.AspNetCore" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -0,0 +1,254 @@
CREATE TABLE IF NOT EXISTS "__EFMigrationsHistory" (
"MigrationId" character varying(150) NOT NULL,
"ProductVersion" character varying(32) NOT NULL,
CONSTRAINT "PK___EFMigrationsHistory" PRIMARY KEY ("MigrationId")
);
START TRANSACTION;
CREATE TABLE gw_service_instances (
"Id" text NOT NULL,
"ClusterId" character varying(100) NOT NULL,
"DestinationId" character varying(100) NOT NULL,
"Address" character varying(200) NOT NULL,
"Health" integer NOT NULL,
"Weight" integer NOT NULL,
"Status" integer NOT NULL,
"CreatedBy" bigint,
"CreatedTime" timestamp with time zone NOT NULL,
"UpdatedBy" bigint,
"UpdatedTime" timestamp with time zone,
"IsDeleted" boolean NOT NULL,
"Version" integer NOT NULL,
CONSTRAINT "PK_gw_service_instances" PRIMARY KEY ("Id")
);
CREATE TABLE gw_tenant_routes (
"Id" text NOT NULL,
"TenantCode" character varying(50) NOT NULL,
"ServiceName" character varying(100) NOT NULL,
"ClusterId" character varying(100) NOT NULL,
"PathPattern" character varying(200) NOT NULL,
"Priority" integer NOT NULL,
"Status" integer NOT NULL,
"IsGlobal" boolean NOT NULL,
"CreatedBy" bigint,
"CreatedTime" timestamp with time zone NOT NULL,
"UpdatedBy" bigint,
"UpdatedTime" timestamp with time zone,
"IsDeleted" boolean NOT NULL,
"Version" integer NOT NULL,
CONSTRAINT "PK_gw_tenant_routes" PRIMARY KEY ("Id")
);
CREATE TABLE gw_tenants (
"Id" bigint GENERATED BY DEFAULT AS IDENTITY,
"TenantCode" character varying(50) NOT NULL,
"TenantName" character varying(100) NOT NULL,
"Status" integer NOT NULL,
"CreatedBy" bigint,
"CreatedTime" timestamp with time zone NOT NULL,
"UpdatedBy" bigint,
"UpdatedTime" timestamp with time zone,
"IsDeleted" boolean NOT NULL,
"Version" integer NOT NULL,
CONSTRAINT "PK_gw_tenants" PRIMARY KEY ("Id")
);
CREATE TABLE idn_roles (
"Id" bigint GENERATED BY DEFAULT AS IDENTITY,
"Description" character varying(200),
"CreatedTime" timestamp with time zone NOT NULL,
"TenantId" bigint,
"IsSystem" boolean NOT NULL,
"DisplayName" text,
"Permissions" text[],
"Name" character varying(256),
"NormalizedName" character varying(256),
"ConcurrencyStamp" text,
CONSTRAINT "PK_idn_roles" PRIMARY KEY ("Id")
);
CREATE TABLE idn_users (
"Id" bigint GENERATED BY DEFAULT AS IDENTITY,
"RealName" text NOT NULL,
"TenantId" bigint,
"TenantCode" text,
"TenantName" text,
"CreatedTime" timestamp with time zone NOT NULL,
"UpdatedTime" timestamp with time zone,
"IsDeleted" boolean NOT NULL,
"UserName" character varying(256),
"NormalizedUserName" character varying(256),
"Email" character varying(256),
"NormalizedEmail" character varying(256),
"EmailConfirmed" boolean NOT NULL,
"PasswordHash" text,
"SecurityStamp" text,
"ConcurrencyStamp" text,
"PhoneNumber" character varying(20),
"PhoneNumberConfirmed" boolean NOT NULL,
"TwoFactorEnabled" boolean NOT NULL,
"LockoutEnd" timestamp with time zone,
"LockoutEnabled" boolean NOT NULL,
"AccessFailedCount" integer NOT NULL,
CONSTRAINT "PK_idn_users" PRIMARY KEY ("Id")
);
CREATE TABLE sys_access_logs (
"Id" bigint GENERATED BY DEFAULT AS IDENTITY,
"UserName" character varying(50),
"TenantId" character varying(50),
"Action" character varying(20) NOT NULL,
"Resource" character varying(200),
"Method" character varying(10),
"IpAddress" character varying(50),
"UserAgent" character varying(500),
"Status" character varying(20) NOT NULL,
"Duration" integer NOT NULL,
"RequestData" text,
"ResponseData" text,
"ErrorMessage" text,
"CreatedAt" timestamp with time zone NOT NULL,
CONSTRAINT "PK_sys_access_logs" PRIMARY KEY ("Id")
);
CREATE TABLE sys_audit_logs (
"Id" bigint GENERATED BY DEFAULT AS IDENTITY,
"Operator" character varying(50) NOT NULL,
"TenantId" character varying(50),
"Operation" character varying(20) NOT NULL,
"Action" character varying(20) NOT NULL,
"TargetType" character varying(50),
"TargetId" bigint,
"TargetName" character varying(100),
"IpAddress" character varying(50) NOT NULL,
"Description" character varying(500),
"OldValue" text,
"NewValue" text,
"ErrorMessage" text,
"Status" character varying(20) NOT NULL,
"CreatedAt" timestamp with time zone NOT NULL,
CONSTRAINT "PK_sys_audit_logs" PRIMARY KEY ("Id")
);
CREATE TABLE sys_tenants (
"Id" bigint GENERATED BY DEFAULT AS IDENTITY,
"TenantCode" character varying(50) NOT NULL,
"Name" character varying(100) NOT NULL,
"ContactName" character varying(50) NOT NULL,
"ContactEmail" character varying(100) NOT NULL,
"ContactPhone" character varying(20),
"MaxUsers" integer,
"CreatedAt" timestamp with time zone NOT NULL,
"UpdatedAt" timestamp with time zone,
"ExpiresAt" timestamp with time zone,
"Description" character varying(500),
"Status" integer NOT NULL,
"IsDeleted" boolean NOT NULL,
"RowVersion" bigint NOT NULL,
CONSTRAINT "PK_sys_tenants" PRIMARY KEY ("Id")
);
CREATE TABLE idn_role_claims (
"Id" integer GENERATED BY DEFAULT AS IDENTITY,
"RoleId" bigint NOT NULL,
"ClaimType" text,
"ClaimValue" text,
CONSTRAINT "PK_idn_role_claims" PRIMARY KEY ("Id"),
CONSTRAINT "FK_idn_role_claims_idn_roles_RoleId" FOREIGN KEY ("RoleId") REFERENCES idn_roles ("Id") ON DELETE CASCADE
);
CREATE TABLE idn_user_claims (
"Id" integer GENERATED BY DEFAULT AS IDENTITY,
"UserId" bigint NOT NULL,
"ClaimType" text,
"ClaimValue" text,
CONSTRAINT "PK_idn_user_claims" PRIMARY KEY ("Id"),
CONSTRAINT "FK_idn_user_claims_idn_users_UserId" FOREIGN KEY ("UserId") REFERENCES idn_users ("Id") ON DELETE CASCADE
);
CREATE TABLE idn_user_logins (
"LoginProvider" text NOT NULL,
"ProviderKey" text NOT NULL,
"ProviderDisplayName" text,
"UserId" bigint NOT NULL,
CONSTRAINT "PK_idn_user_logins" PRIMARY KEY ("LoginProvider", "ProviderKey"),
CONSTRAINT "FK_idn_user_logins_idn_users_UserId" FOREIGN KEY ("UserId") REFERENCES idn_users ("Id") ON DELETE CASCADE
);
CREATE TABLE idn_user_roles (
"UserId" bigint NOT NULL,
"RoleId" bigint NOT NULL,
CONSTRAINT "PK_idn_user_roles" PRIMARY KEY ("UserId", "RoleId"),
CONSTRAINT "FK_idn_user_roles_idn_roles_RoleId" FOREIGN KEY ("RoleId") REFERENCES idn_roles ("Id") ON DELETE CASCADE,
CONSTRAINT "FK_idn_user_roles_idn_users_UserId" FOREIGN KEY ("UserId") REFERENCES idn_users ("Id") ON DELETE CASCADE
);
CREATE TABLE idn_user_tokens (
"UserId" bigint NOT NULL,
"LoginProvider" text NOT NULL,
"Name" text NOT NULL,
"Value" text,
CONSTRAINT "PK_idn_user_tokens" PRIMARY KEY ("UserId", "LoginProvider", "Name"),
CONSTRAINT "FK_idn_user_tokens_idn_users_UserId" FOREIGN KEY ("UserId") REFERENCES idn_users ("Id") ON DELETE CASCADE
);
CREATE UNIQUE INDEX "IX_gw_service_instances_ClusterId_DestinationId" ON gw_service_instances ("ClusterId", "DestinationId");
CREATE INDEX "IX_gw_service_instances_Health" ON gw_service_instances ("Health");
CREATE INDEX "IX_gw_tenant_routes_ClusterId" ON gw_tenant_routes ("ClusterId");
CREATE INDEX "IX_gw_tenant_routes_ServiceName" ON gw_tenant_routes ("ServiceName");
CREATE INDEX "IX_gw_tenant_routes_ServiceName_IsGlobal_Status" ON gw_tenant_routes ("ServiceName", "IsGlobal", "Status");
CREATE INDEX "IX_gw_tenant_routes_TenantCode" ON gw_tenant_routes ("TenantCode");
CREATE UNIQUE INDEX "IX_gw_tenants_TenantCode" ON gw_tenants ("TenantCode");
CREATE INDEX "IX_idn_role_claims_RoleId" ON idn_role_claims ("RoleId");
CREATE UNIQUE INDEX "RoleNameIndex" ON idn_roles ("NormalizedName");
CREATE INDEX "IX_idn_user_claims_UserId" ON idn_user_claims ("UserId");
CREATE INDEX "IX_idn_user_logins_UserId" ON idn_user_logins ("UserId");
CREATE INDEX "IX_idn_user_roles_RoleId" ON idn_user_roles ("RoleId");
CREATE INDEX "EmailIndex" ON idn_users ("NormalizedEmail");
CREATE UNIQUE INDEX "IX_idn_users_PhoneNumber" ON idn_users ("PhoneNumber");
CREATE UNIQUE INDEX "UserNameIndex" ON idn_users ("NormalizedUserName");
CREATE INDEX "IX_sys_access_logs_Action" ON sys_access_logs ("Action");
CREATE INDEX "IX_sys_access_logs_CreatedAt" ON sys_access_logs ("CreatedAt");
CREATE INDEX "IX_sys_access_logs_Status" ON sys_access_logs ("Status");
CREATE INDEX "IX_sys_access_logs_TenantId" ON sys_access_logs ("TenantId");
CREATE INDEX "IX_sys_access_logs_UserName" ON sys_access_logs ("UserName");
CREATE INDEX "IX_sys_audit_logs_Action" ON sys_audit_logs ("Action");
CREATE INDEX "IX_sys_audit_logs_CreatedAt" ON sys_audit_logs ("CreatedAt");
CREATE INDEX "IX_sys_audit_logs_Operation" ON sys_audit_logs ("Operation");
CREATE INDEX "IX_sys_audit_logs_Operator" ON sys_audit_logs ("Operator");
CREATE INDEX "IX_sys_audit_logs_TenantId" ON sys_audit_logs ("TenantId");
CREATE INDEX "IX_sys_tenants_Status" ON sys_tenants ("Status");
CREATE UNIQUE INDEX "IX_sys_tenants_TenantCode" ON sys_tenants ("TenantCode");
INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion")
VALUES ('20260301040647_Initial', '10.0.3');
COMMIT;

View File

@ -0,0 +1,734 @@
// <auto-generated />
using System;
using System.Collections.Generic;
using Fengling.Console.Data;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
#nullable disable
namespace Fengling.Console.Migrations
{
[DbContext(typeof(ConsoleDbContext))]
[Migration("20260301040647_Initial")]
partial class Initial
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "10.0.3")
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("Fengling.Platform.Domain.AggregatesModel.GatewayAggregate.GwServiceInstance", b =>
{
b.Property<string>("Id")
.HasColumnType("text");
b.Property<string>("Address")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("character varying(200)");
b.Property<string>("ClusterId")
.IsRequired()
.HasMaxLength(100)
.HasColumnType("character varying(100)");
b.Property<long?>("CreatedBy")
.HasColumnType("bigint");
b.Property<DateTime>("CreatedTime")
.HasColumnType("timestamp with time zone");
b.Property<string>("DestinationId")
.IsRequired()
.HasMaxLength(100)
.HasColumnType("character varying(100)");
b.Property<int>("Health")
.HasColumnType("integer");
b.Property<bool>("IsDeleted")
.HasColumnType("boolean");
b.Property<int>("Status")
.HasColumnType("integer");
b.Property<long?>("UpdatedBy")
.HasColumnType("bigint");
b.Property<DateTime?>("UpdatedTime")
.HasColumnType("timestamp with time zone");
b.Property<int>("Version")
.HasColumnType("integer");
b.Property<int>("Weight")
.HasColumnType("integer");
b.HasKey("Id");
b.HasIndex("Health");
b.HasIndex("ClusterId", "DestinationId")
.IsUnique();
b.ToTable("gw_service_instances", (string)null);
});
modelBuilder.Entity("Fengling.Platform.Domain.AggregatesModel.GatewayAggregate.GwTenant", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("bigint");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
b.Property<long?>("CreatedBy")
.HasColumnType("bigint");
b.Property<DateTime>("CreatedTime")
.HasColumnType("timestamp with time zone");
b.Property<bool>("IsDeleted")
.HasColumnType("boolean");
b.Property<int>("Status")
.HasColumnType("integer");
b.Property<string>("TenantCode")
.IsRequired()
.HasMaxLength(50)
.HasColumnType("character varying(50)");
b.Property<string>("TenantName")
.IsRequired()
.HasMaxLength(100)
.HasColumnType("character varying(100)");
b.Property<long?>("UpdatedBy")
.HasColumnType("bigint");
b.Property<DateTime?>("UpdatedTime")
.HasColumnType("timestamp with time zone");
b.Property<int>("Version")
.HasColumnType("integer");
b.HasKey("Id");
b.HasIndex("TenantCode")
.IsUnique();
b.ToTable("gw_tenants", (string)null);
});
modelBuilder.Entity("Fengling.Platform.Domain.AggregatesModel.GatewayAggregate.GwTenantRoute", b =>
{
b.Property<string>("Id")
.HasColumnType("text");
b.Property<string>("ClusterId")
.IsRequired()
.HasMaxLength(100)
.HasColumnType("character varying(100)");
b.Property<long?>("CreatedBy")
.HasColumnType("bigint");
b.Property<DateTime>("CreatedTime")
.HasColumnType("timestamp with time zone");
b.Property<bool>("IsDeleted")
.HasColumnType("boolean");
b.Property<bool>("IsGlobal")
.HasColumnType("boolean");
b.Property<string>("PathPattern")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("character varying(200)");
b.Property<int>("Priority")
.HasColumnType("integer");
b.Property<string>("ServiceName")
.IsRequired()
.HasMaxLength(100)
.HasColumnType("character varying(100)");
b.Property<int>("Status")
.HasColumnType("integer");
b.Property<string>("TenantCode")
.IsRequired()
.HasMaxLength(50)
.HasColumnType("character varying(50)");
b.Property<long?>("UpdatedBy")
.HasColumnType("bigint");
b.Property<DateTime?>("UpdatedTime")
.HasColumnType("timestamp with time zone");
b.Property<int>("Version")
.HasColumnType("integer");
b.HasKey("Id");
b.HasIndex("ClusterId");
b.HasIndex("ServiceName");
b.HasIndex("TenantCode");
b.HasIndex("ServiceName", "IsGlobal", "Status");
b.ToTable("gw_tenant_routes", (string)null);
});
modelBuilder.Entity("Fengling.Platform.Domain.AggregatesModel.RoleAggregate.ApplicationRole", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("bigint");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasColumnType("text");
b.Property<DateTimeOffset>("CreatedTime")
.HasColumnType("timestamp with time zone");
b.Property<string>("Description")
.HasMaxLength(200)
.HasColumnType("character varying(200)");
b.Property<string>("DisplayName")
.HasColumnType("text");
b.Property<bool>("IsSystem")
.HasColumnType("boolean");
b.Property<string>("Name")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.Property<string>("NormalizedName")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.PrimitiveCollection<List<string>>("Permissions")
.HasColumnType("text[]");
b.Property<long?>("TenantId")
.HasColumnType("bigint");
b.HasKey("Id");
b.HasIndex("NormalizedName")
.IsUnique()
.HasDatabaseName("RoleNameIndex");
b.ToTable("idn_roles", (string)null);
});
modelBuilder.Entity("Fengling.Platform.Domain.AggregatesModel.TenantAggregate.Tenant", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("bigint");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
b.Property<string>("ContactEmail")
.IsRequired()
.HasMaxLength(100)
.HasColumnType("character varying(100)");
b.Property<string>("ContactName")
.IsRequired()
.HasMaxLength(50)
.HasColumnType("character varying(50)");
b.Property<string>("ContactPhone")
.HasMaxLength(20)
.HasColumnType("character varying(20)");
b.Property<DateTime>("CreatedAt")
.HasColumnType("timestamp with time zone");
b.Property<string>("Description")
.HasMaxLength(500)
.HasColumnType("character varying(500)");
b.Property<DateTime?>("ExpiresAt")
.HasColumnType("timestamp with time zone");
b.Property<bool>("IsDeleted")
.HasColumnType("boolean");
b.Property<int?>("MaxUsers")
.HasColumnType("integer");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(100)
.HasColumnType("character varying(100)");
b.Property<long>("RowVersion")
.HasColumnType("bigint");
b.Property<int>("Status")
.HasColumnType("integer");
b.Property<string>("TenantCode")
.IsRequired()
.HasMaxLength(50)
.HasColumnType("character varying(50)");
b.Property<DateTime?>("UpdatedAt")
.HasColumnType("timestamp with time zone");
b.HasKey("Id");
b.HasIndex("Status");
b.HasIndex("TenantCode")
.IsUnique();
b.ToTable("sys_tenants", (string)null);
});
modelBuilder.Entity("Fengling.Platform.Domain.AggregatesModel.UserAggregate.AccessLog", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("bigint");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
b.Property<string>("Action")
.IsRequired()
.HasMaxLength(20)
.HasColumnType("character varying(20)");
b.Property<DateTime>("CreatedAt")
.HasColumnType("timestamp with time zone");
b.Property<int>("Duration")
.HasColumnType("integer");
b.Property<string>("ErrorMessage")
.HasColumnType("text");
b.Property<string>("IpAddress")
.HasMaxLength(50)
.HasColumnType("character varying(50)");
b.Property<string>("Method")
.HasMaxLength(10)
.HasColumnType("character varying(10)");
b.Property<string>("RequestData")
.HasColumnType("text");
b.Property<string>("Resource")
.HasMaxLength(200)
.HasColumnType("character varying(200)");
b.Property<string>("ResponseData")
.HasColumnType("text");
b.Property<string>("Status")
.IsRequired()
.HasMaxLength(20)
.HasColumnType("character varying(20)");
b.Property<string>("TenantId")
.HasMaxLength(50)
.HasColumnType("character varying(50)");
b.Property<string>("UserAgent")
.HasMaxLength(500)
.HasColumnType("character varying(500)");
b.Property<string>("UserName")
.HasMaxLength(50)
.HasColumnType("character varying(50)");
b.HasKey("Id");
b.HasIndex("Action");
b.HasIndex("CreatedAt");
b.HasIndex("Status");
b.HasIndex("TenantId");
b.HasIndex("UserName");
b.ToTable("sys_access_logs", (string)null);
});
modelBuilder.Entity("Fengling.Platform.Domain.AggregatesModel.UserAggregate.ApplicationUser", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("bigint");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
b.Property<int>("AccessFailedCount")
.HasColumnType("integer");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasColumnType("text");
b.Property<DateTimeOffset>("CreatedTime")
.HasColumnType("timestamp with time zone");
b.Property<string>("Email")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.Property<bool>("EmailConfirmed")
.HasColumnType("boolean");
b.Property<bool>("IsDeleted")
.HasColumnType("boolean");
b.Property<bool>("LockoutEnabled")
.HasColumnType("boolean");
b.Property<DateTimeOffset?>("LockoutEnd")
.HasColumnType("timestamp with time zone");
b.Property<string>("NormalizedEmail")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.Property<string>("NormalizedUserName")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.Property<string>("PasswordHash")
.HasColumnType("text");
b.Property<string>("PhoneNumber")
.HasMaxLength(20)
.HasColumnType("character varying(20)");
b.Property<bool>("PhoneNumberConfirmed")
.HasColumnType("boolean");
b.Property<string>("RealName")
.IsRequired()
.HasColumnType("text");
b.Property<string>("SecurityStamp")
.HasColumnType("text");
b.Property<bool>("TwoFactorEnabled")
.HasColumnType("boolean");
b.Property<DateTimeOffset?>("UpdatedTime")
.HasColumnType("timestamp with time zone");
b.Property<string>("UserName")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.HasKey("Id");
b.HasIndex("NormalizedEmail")
.HasDatabaseName("EmailIndex");
b.HasIndex("NormalizedUserName")
.IsUnique()
.HasDatabaseName("UserNameIndex");
b.HasIndex("PhoneNumber")
.IsUnique();
b.ToTable("idn_users", (string)null);
});
modelBuilder.Entity("Fengling.Platform.Domain.AggregatesModel.UserAggregate.AuditLog", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("bigint");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
b.Property<string>("Action")
.IsRequired()
.HasMaxLength(20)
.HasColumnType("character varying(20)");
b.Property<DateTime>("CreatedAt")
.HasColumnType("timestamp with time zone");
b.Property<string>("Description")
.HasMaxLength(500)
.HasColumnType("character varying(500)");
b.Property<string>("ErrorMessage")
.HasColumnType("text");
b.Property<string>("IpAddress")
.IsRequired()
.HasMaxLength(50)
.HasColumnType("character varying(50)");
b.Property<string>("NewValue")
.HasColumnType("text");
b.Property<string>("OldValue")
.HasColumnType("text");
b.Property<string>("Operation")
.IsRequired()
.HasMaxLength(20)
.HasColumnType("character varying(20)");
b.Property<string>("Operator")
.IsRequired()
.HasMaxLength(50)
.HasColumnType("character varying(50)");
b.Property<string>("Status")
.IsRequired()
.HasMaxLength(20)
.HasColumnType("character varying(20)");
b.Property<long?>("TargetId")
.HasColumnType("bigint");
b.Property<string>("TargetName")
.HasMaxLength(100)
.HasColumnType("character varying(100)");
b.Property<string>("TargetType")
.HasMaxLength(50)
.HasColumnType("character varying(50)");
b.Property<string>("TenantId")
.HasMaxLength(50)
.HasColumnType("character varying(50)");
b.HasKey("Id");
b.HasIndex("Action");
b.HasIndex("CreatedAt");
b.HasIndex("Operation");
b.HasIndex("Operator");
b.HasIndex("TenantId");
b.ToTable("sys_audit_logs", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<long>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<string>("ClaimType")
.HasColumnType("text");
b.Property<string>("ClaimValue")
.HasColumnType("text");
b.Property<long>("RoleId")
.HasColumnType("bigint");
b.HasKey("Id");
b.HasIndex("RoleId");
b.ToTable("idn_role_claims", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<long>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<string>("ClaimType")
.HasColumnType("text");
b.Property<string>("ClaimValue")
.HasColumnType("text");
b.Property<long>("UserId")
.HasColumnType("bigint");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("idn_user_claims", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<long>", b =>
{
b.Property<string>("LoginProvider")
.HasColumnType("text");
b.Property<string>("ProviderKey")
.HasColumnType("text");
b.Property<string>("ProviderDisplayName")
.HasColumnType("text");
b.Property<long>("UserId")
.HasColumnType("bigint");
b.HasKey("LoginProvider", "ProviderKey");
b.HasIndex("UserId");
b.ToTable("idn_user_logins", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<long>", b =>
{
b.Property<long>("UserId")
.HasColumnType("bigint");
b.Property<long>("RoleId")
.HasColumnType("bigint");
b.HasKey("UserId", "RoleId");
b.HasIndex("RoleId");
b.ToTable("idn_user_roles", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<long>", b =>
{
b.Property<long>("UserId")
.HasColumnType("bigint");
b.Property<string>("LoginProvider")
.HasColumnType("text");
b.Property<string>("Name")
.HasColumnType("text");
b.Property<string>("Value")
.HasColumnType("text");
b.HasKey("UserId", "LoginProvider", "Name");
b.ToTable("idn_user_tokens", (string)null);
});
modelBuilder.Entity("Fengling.Platform.Domain.AggregatesModel.UserAggregate.ApplicationUser", b =>
{
b.OwnsOne("Fengling.Platform.Domain.AggregatesModel.TenantAggregate.TenantInfo", "TenantInfo", b1 =>
{
b1.Property<long>("ApplicationUserId")
.HasColumnType("bigint");
b1.Property<string>("TenantCode")
.HasColumnType("text")
.HasColumnName("TenantCode");
b1.Property<long?>("TenantId")
.HasColumnType("bigint")
.HasColumnName("TenantId");
b1.Property<string>("TenantName")
.HasColumnType("text")
.HasColumnName("TenantName");
b1.HasKey("ApplicationUserId");
b1.ToTable("idn_users");
b1.WithOwner()
.HasForeignKey("ApplicationUserId");
});
b.Navigation("TenantInfo");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<long>", b =>
{
b.HasOne("Fengling.Platform.Domain.AggregatesModel.RoleAggregate.ApplicationRole", null)
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<long>", b =>
{
b.HasOne("Fengling.Platform.Domain.AggregatesModel.UserAggregate.ApplicationUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<long>", b =>
{
b.HasOne("Fengling.Platform.Domain.AggregatesModel.UserAggregate.ApplicationUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<long>", b =>
{
b.HasOne("Fengling.Platform.Domain.AggregatesModel.RoleAggregate.ApplicationRole", null)
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("Fengling.Platform.Domain.AggregatesModel.UserAggregate.ApplicationUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<long>", b =>
{
b.HasOne("Fengling.Platform.Domain.AggregatesModel.UserAggregate.ApplicationUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
#pragma warning restore 612, 618
}
}
}

View File

@ -0,0 +1,505 @@
using System;
using System.Collections.Generic;
using Microsoft.EntityFrameworkCore.Migrations;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
#nullable disable
namespace Fengling.Console.Migrations
{
/// <inheritdoc />
public partial class Initial : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "gw_service_instances",
columns: table => new
{
Id = table.Column<string>(type: "text", nullable: false),
ClusterId = table.Column<string>(type: "character varying(100)", maxLength: 100, nullable: false),
DestinationId = table.Column<string>(type: "character varying(100)", maxLength: 100, nullable: false),
Address = table.Column<string>(type: "character varying(200)", maxLength: 200, nullable: false),
Health = table.Column<int>(type: "integer", nullable: false),
Weight = table.Column<int>(type: "integer", nullable: false),
Status = table.Column<int>(type: "integer", nullable: false),
CreatedBy = table.Column<long>(type: "bigint", nullable: true),
CreatedTime = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
UpdatedBy = table.Column<long>(type: "bigint", nullable: true),
UpdatedTime = table.Column<DateTime>(type: "timestamp with time zone", nullable: true),
IsDeleted = table.Column<bool>(type: "boolean", nullable: false),
Version = table.Column<int>(type: "integer", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_gw_service_instances", x => x.Id);
});
migrationBuilder.CreateTable(
name: "gw_tenant_routes",
columns: table => new
{
Id = table.Column<string>(type: "text", nullable: false),
TenantCode = table.Column<string>(type: "character varying(50)", maxLength: 50, nullable: false),
ServiceName = table.Column<string>(type: "character varying(100)", maxLength: 100, nullable: false),
ClusterId = table.Column<string>(type: "character varying(100)", maxLength: 100, nullable: false),
PathPattern = table.Column<string>(type: "character varying(200)", maxLength: 200, nullable: false),
Priority = table.Column<int>(type: "integer", nullable: false),
Status = table.Column<int>(type: "integer", nullable: false),
IsGlobal = table.Column<bool>(type: "boolean", nullable: false),
CreatedBy = table.Column<long>(type: "bigint", nullable: true),
CreatedTime = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
UpdatedBy = table.Column<long>(type: "bigint", nullable: true),
UpdatedTime = table.Column<DateTime>(type: "timestamp with time zone", nullable: true),
IsDeleted = table.Column<bool>(type: "boolean", nullable: false),
Version = table.Column<int>(type: "integer", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_gw_tenant_routes", x => x.Id);
});
migrationBuilder.CreateTable(
name: "gw_tenants",
columns: table => new
{
Id = table.Column<long>(type: "bigint", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
TenantCode = table.Column<string>(type: "character varying(50)", maxLength: 50, nullable: false),
TenantName = table.Column<string>(type: "character varying(100)", maxLength: 100, nullable: false),
Status = table.Column<int>(type: "integer", nullable: false),
CreatedBy = table.Column<long>(type: "bigint", nullable: true),
CreatedTime = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
UpdatedBy = table.Column<long>(type: "bigint", nullable: true),
UpdatedTime = table.Column<DateTime>(type: "timestamp with time zone", nullable: true),
IsDeleted = table.Column<bool>(type: "boolean", nullable: false),
Version = table.Column<int>(type: "integer", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_gw_tenants", x => x.Id);
});
migrationBuilder.CreateTable(
name: "idn_roles",
columns: table => new
{
Id = table.Column<long>(type: "bigint", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
Description = table.Column<string>(type: "character varying(200)", maxLength: 200, nullable: true),
CreatedTime = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false),
TenantId = table.Column<long>(type: "bigint", nullable: true),
IsSystem = table.Column<bool>(type: "boolean", nullable: false),
DisplayName = table.Column<string>(type: "text", nullable: true),
Permissions = table.Column<List<string>>(type: "text[]", nullable: true),
Name = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true),
NormalizedName = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true),
ConcurrencyStamp = table.Column<string>(type: "text", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_idn_roles", x => x.Id);
});
migrationBuilder.CreateTable(
name: "idn_users",
columns: table => new
{
Id = table.Column<long>(type: "bigint", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
RealName = table.Column<string>(type: "text", nullable: false),
TenantId = table.Column<long>(type: "bigint", nullable: true),
TenantCode = table.Column<string>(type: "text", nullable: true),
TenantName = table.Column<string>(type: "text", nullable: true),
CreatedTime = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false),
UpdatedTime = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: true),
IsDeleted = table.Column<bool>(type: "boolean", nullable: false),
UserName = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true),
NormalizedUserName = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true),
Email = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true),
NormalizedEmail = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true),
EmailConfirmed = table.Column<bool>(type: "boolean", nullable: false),
PasswordHash = table.Column<string>(type: "text", nullable: true),
SecurityStamp = table.Column<string>(type: "text", nullable: true),
ConcurrencyStamp = table.Column<string>(type: "text", nullable: true),
PhoneNumber = table.Column<string>(type: "character varying(20)", maxLength: 20, nullable: true),
PhoneNumberConfirmed = table.Column<bool>(type: "boolean", nullable: false),
TwoFactorEnabled = table.Column<bool>(type: "boolean", nullable: false),
LockoutEnd = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: true),
LockoutEnabled = table.Column<bool>(type: "boolean", nullable: false),
AccessFailedCount = table.Column<int>(type: "integer", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_idn_users", x => x.Id);
});
migrationBuilder.CreateTable(
name: "sys_access_logs",
columns: table => new
{
Id = table.Column<long>(type: "bigint", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
UserName = table.Column<string>(type: "character varying(50)", maxLength: 50, nullable: true),
TenantId = table.Column<string>(type: "character varying(50)", maxLength: 50, nullable: true),
Action = table.Column<string>(type: "character varying(20)", maxLength: 20, nullable: false),
Resource = table.Column<string>(type: "character varying(200)", maxLength: 200, nullable: true),
Method = table.Column<string>(type: "character varying(10)", maxLength: 10, nullable: true),
IpAddress = table.Column<string>(type: "character varying(50)", maxLength: 50, nullable: true),
UserAgent = table.Column<string>(type: "character varying(500)", maxLength: 500, nullable: true),
Status = table.Column<string>(type: "character varying(20)", maxLength: 20, nullable: false),
Duration = table.Column<int>(type: "integer", nullable: false),
RequestData = table.Column<string>(type: "text", nullable: true),
ResponseData = table.Column<string>(type: "text", nullable: true),
ErrorMessage = table.Column<string>(type: "text", nullable: true),
CreatedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_sys_access_logs", x => x.Id);
});
migrationBuilder.CreateTable(
name: "sys_audit_logs",
columns: table => new
{
Id = table.Column<long>(type: "bigint", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
Operator = table.Column<string>(type: "character varying(50)", maxLength: 50, nullable: false),
TenantId = table.Column<string>(type: "character varying(50)", maxLength: 50, nullable: true),
Operation = table.Column<string>(type: "character varying(20)", maxLength: 20, nullable: false),
Action = table.Column<string>(type: "character varying(20)", maxLength: 20, nullable: false),
TargetType = table.Column<string>(type: "character varying(50)", maxLength: 50, nullable: true),
TargetId = table.Column<long>(type: "bigint", nullable: true),
TargetName = table.Column<string>(type: "character varying(100)", maxLength: 100, nullable: true),
IpAddress = table.Column<string>(type: "character varying(50)", maxLength: 50, nullable: false),
Description = table.Column<string>(type: "character varying(500)", maxLength: 500, nullable: true),
OldValue = table.Column<string>(type: "text", nullable: true),
NewValue = table.Column<string>(type: "text", nullable: true),
ErrorMessage = table.Column<string>(type: "text", nullable: true),
Status = table.Column<string>(type: "character varying(20)", maxLength: 20, nullable: false),
CreatedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_sys_audit_logs", x => x.Id);
});
migrationBuilder.CreateTable(
name: "sys_tenants",
columns: table => new
{
Id = table.Column<long>(type: "bigint", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
TenantCode = table.Column<string>(type: "character varying(50)", maxLength: 50, nullable: false),
Name = table.Column<string>(type: "character varying(100)", maxLength: 100, nullable: false),
ContactName = table.Column<string>(type: "character varying(50)", maxLength: 50, nullable: false),
ContactEmail = table.Column<string>(type: "character varying(100)", maxLength: 100, nullable: false),
ContactPhone = table.Column<string>(type: "character varying(20)", maxLength: 20, nullable: true),
MaxUsers = table.Column<int>(type: "integer", nullable: true),
CreatedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
UpdatedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: true),
ExpiresAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: true),
Description = table.Column<string>(type: "character varying(500)", maxLength: 500, nullable: true),
Status = table.Column<int>(type: "integer", nullable: false),
IsDeleted = table.Column<bool>(type: "boolean", nullable: false),
RowVersion = table.Column<long>(type: "bigint", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_sys_tenants", x => x.Id);
});
migrationBuilder.CreateTable(
name: "idn_role_claims",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
RoleId = table.Column<long>(type: "bigint", nullable: false),
ClaimType = table.Column<string>(type: "text", nullable: true),
ClaimValue = table.Column<string>(type: "text", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_idn_role_claims", x => x.Id);
table.ForeignKey(
name: "FK_idn_role_claims_idn_roles_RoleId",
column: x => x.RoleId,
principalTable: "idn_roles",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "idn_user_claims",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
UserId = table.Column<long>(type: "bigint", nullable: false),
ClaimType = table.Column<string>(type: "text", nullable: true),
ClaimValue = table.Column<string>(type: "text", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_idn_user_claims", x => x.Id);
table.ForeignKey(
name: "FK_idn_user_claims_idn_users_UserId",
column: x => x.UserId,
principalTable: "idn_users",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "idn_user_logins",
columns: table => new
{
LoginProvider = table.Column<string>(type: "text", nullable: false),
ProviderKey = table.Column<string>(type: "text", nullable: false),
ProviderDisplayName = table.Column<string>(type: "text", nullable: true),
UserId = table.Column<long>(type: "bigint", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_idn_user_logins", x => new { x.LoginProvider, x.ProviderKey });
table.ForeignKey(
name: "FK_idn_user_logins_idn_users_UserId",
column: x => x.UserId,
principalTable: "idn_users",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "idn_user_roles",
columns: table => new
{
UserId = table.Column<long>(type: "bigint", nullable: false),
RoleId = table.Column<long>(type: "bigint", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_idn_user_roles", x => new { x.UserId, x.RoleId });
table.ForeignKey(
name: "FK_idn_user_roles_idn_roles_RoleId",
column: x => x.RoleId,
principalTable: "idn_roles",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_idn_user_roles_idn_users_UserId",
column: x => x.UserId,
principalTable: "idn_users",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "idn_user_tokens",
columns: table => new
{
UserId = table.Column<long>(type: "bigint", nullable: false),
LoginProvider = table.Column<string>(type: "text", nullable: false),
Name = table.Column<string>(type: "text", nullable: false),
Value = table.Column<string>(type: "text", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_idn_user_tokens", x => new { x.UserId, x.LoginProvider, x.Name });
table.ForeignKey(
name: "FK_idn_user_tokens_idn_users_UserId",
column: x => x.UserId,
principalTable: "idn_users",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateIndex(
name: "IX_gw_service_instances_ClusterId_DestinationId",
table: "gw_service_instances",
columns: new[] { "ClusterId", "DestinationId" },
unique: true);
migrationBuilder.CreateIndex(
name: "IX_gw_service_instances_Health",
table: "gw_service_instances",
column: "Health");
migrationBuilder.CreateIndex(
name: "IX_gw_tenant_routes_ClusterId",
table: "gw_tenant_routes",
column: "ClusterId");
migrationBuilder.CreateIndex(
name: "IX_gw_tenant_routes_ServiceName",
table: "gw_tenant_routes",
column: "ServiceName");
migrationBuilder.CreateIndex(
name: "IX_gw_tenant_routes_ServiceName_IsGlobal_Status",
table: "gw_tenant_routes",
columns: new[] { "ServiceName", "IsGlobal", "Status" });
migrationBuilder.CreateIndex(
name: "IX_gw_tenant_routes_TenantCode",
table: "gw_tenant_routes",
column: "TenantCode");
migrationBuilder.CreateIndex(
name: "IX_gw_tenants_TenantCode",
table: "gw_tenants",
column: "TenantCode",
unique: true);
migrationBuilder.CreateIndex(
name: "IX_idn_role_claims_RoleId",
table: "idn_role_claims",
column: "RoleId");
migrationBuilder.CreateIndex(
name: "RoleNameIndex",
table: "idn_roles",
column: "NormalizedName",
unique: true);
migrationBuilder.CreateIndex(
name: "IX_idn_user_claims_UserId",
table: "idn_user_claims",
column: "UserId");
migrationBuilder.CreateIndex(
name: "IX_idn_user_logins_UserId",
table: "idn_user_logins",
column: "UserId");
migrationBuilder.CreateIndex(
name: "IX_idn_user_roles_RoleId",
table: "idn_user_roles",
column: "RoleId");
migrationBuilder.CreateIndex(
name: "EmailIndex",
table: "idn_users",
column: "NormalizedEmail");
migrationBuilder.CreateIndex(
name: "IX_idn_users_PhoneNumber",
table: "idn_users",
column: "PhoneNumber",
unique: true);
migrationBuilder.CreateIndex(
name: "UserNameIndex",
table: "idn_users",
column: "NormalizedUserName",
unique: true);
migrationBuilder.CreateIndex(
name: "IX_sys_access_logs_Action",
table: "sys_access_logs",
column: "Action");
migrationBuilder.CreateIndex(
name: "IX_sys_access_logs_CreatedAt",
table: "sys_access_logs",
column: "CreatedAt");
migrationBuilder.CreateIndex(
name: "IX_sys_access_logs_Status",
table: "sys_access_logs",
column: "Status");
migrationBuilder.CreateIndex(
name: "IX_sys_access_logs_TenantId",
table: "sys_access_logs",
column: "TenantId");
migrationBuilder.CreateIndex(
name: "IX_sys_access_logs_UserName",
table: "sys_access_logs",
column: "UserName");
migrationBuilder.CreateIndex(
name: "IX_sys_audit_logs_Action",
table: "sys_audit_logs",
column: "Action");
migrationBuilder.CreateIndex(
name: "IX_sys_audit_logs_CreatedAt",
table: "sys_audit_logs",
column: "CreatedAt");
migrationBuilder.CreateIndex(
name: "IX_sys_audit_logs_Operation",
table: "sys_audit_logs",
column: "Operation");
migrationBuilder.CreateIndex(
name: "IX_sys_audit_logs_Operator",
table: "sys_audit_logs",
column: "Operator");
migrationBuilder.CreateIndex(
name: "IX_sys_audit_logs_TenantId",
table: "sys_audit_logs",
column: "TenantId");
migrationBuilder.CreateIndex(
name: "IX_sys_tenants_Status",
table: "sys_tenants",
column: "Status");
migrationBuilder.CreateIndex(
name: "IX_sys_tenants_TenantCode",
table: "sys_tenants",
column: "TenantCode",
unique: true);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "gw_service_instances");
migrationBuilder.DropTable(
name: "gw_tenant_routes");
migrationBuilder.DropTable(
name: "gw_tenants");
migrationBuilder.DropTable(
name: "idn_role_claims");
migrationBuilder.DropTable(
name: "idn_user_claims");
migrationBuilder.DropTable(
name: "idn_user_logins");
migrationBuilder.DropTable(
name: "idn_user_roles");
migrationBuilder.DropTable(
name: "idn_user_tokens");
migrationBuilder.DropTable(
name: "sys_access_logs");
migrationBuilder.DropTable(
name: "sys_audit_logs");
migrationBuilder.DropTable(
name: "sys_tenants");
migrationBuilder.DropTable(
name: "idn_roles");
migrationBuilder.DropTable(
name: "idn_users");
}
}
}

View File

@ -0,0 +1,731 @@
// <auto-generated />
using System;
using System.Collections.Generic;
using Fengling.Console.Data;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
#nullable disable
namespace Fengling.Console.Migrations
{
[DbContext(typeof(ConsoleDbContext))]
partial class ConsoleDbContextModelSnapshot : ModelSnapshot
{
protected override void BuildModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "10.0.3")
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("Fengling.Platform.Domain.AggregatesModel.GatewayAggregate.GwServiceInstance", b =>
{
b.Property<string>("Id")
.HasColumnType("text");
b.Property<string>("Address")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("character varying(200)");
b.Property<string>("ClusterId")
.IsRequired()
.HasMaxLength(100)
.HasColumnType("character varying(100)");
b.Property<long?>("CreatedBy")
.HasColumnType("bigint");
b.Property<DateTime>("CreatedTime")
.HasColumnType("timestamp with time zone");
b.Property<string>("DestinationId")
.IsRequired()
.HasMaxLength(100)
.HasColumnType("character varying(100)");
b.Property<int>("Health")
.HasColumnType("integer");
b.Property<bool>("IsDeleted")
.HasColumnType("boolean");
b.Property<int>("Status")
.HasColumnType("integer");
b.Property<long?>("UpdatedBy")
.HasColumnType("bigint");
b.Property<DateTime?>("UpdatedTime")
.HasColumnType("timestamp with time zone");
b.Property<int>("Version")
.HasColumnType("integer");
b.Property<int>("Weight")
.HasColumnType("integer");
b.HasKey("Id");
b.HasIndex("Health");
b.HasIndex("ClusterId", "DestinationId")
.IsUnique();
b.ToTable("gw_service_instances", (string)null);
});
modelBuilder.Entity("Fengling.Platform.Domain.AggregatesModel.GatewayAggregate.GwTenant", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("bigint");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
b.Property<long?>("CreatedBy")
.HasColumnType("bigint");
b.Property<DateTime>("CreatedTime")
.HasColumnType("timestamp with time zone");
b.Property<bool>("IsDeleted")
.HasColumnType("boolean");
b.Property<int>("Status")
.HasColumnType("integer");
b.Property<string>("TenantCode")
.IsRequired()
.HasMaxLength(50)
.HasColumnType("character varying(50)");
b.Property<string>("TenantName")
.IsRequired()
.HasMaxLength(100)
.HasColumnType("character varying(100)");
b.Property<long?>("UpdatedBy")
.HasColumnType("bigint");
b.Property<DateTime?>("UpdatedTime")
.HasColumnType("timestamp with time zone");
b.Property<int>("Version")
.HasColumnType("integer");
b.HasKey("Id");
b.HasIndex("TenantCode")
.IsUnique();
b.ToTable("gw_tenants", (string)null);
});
modelBuilder.Entity("Fengling.Platform.Domain.AggregatesModel.GatewayAggregate.GwTenantRoute", b =>
{
b.Property<string>("Id")
.HasColumnType("text");
b.Property<string>("ClusterId")
.IsRequired()
.HasMaxLength(100)
.HasColumnType("character varying(100)");
b.Property<long?>("CreatedBy")
.HasColumnType("bigint");
b.Property<DateTime>("CreatedTime")
.HasColumnType("timestamp with time zone");
b.Property<bool>("IsDeleted")
.HasColumnType("boolean");
b.Property<bool>("IsGlobal")
.HasColumnType("boolean");
b.Property<string>("PathPattern")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("character varying(200)");
b.Property<int>("Priority")
.HasColumnType("integer");
b.Property<string>("ServiceName")
.IsRequired()
.HasMaxLength(100)
.HasColumnType("character varying(100)");
b.Property<int>("Status")
.HasColumnType("integer");
b.Property<string>("TenantCode")
.IsRequired()
.HasMaxLength(50)
.HasColumnType("character varying(50)");
b.Property<long?>("UpdatedBy")
.HasColumnType("bigint");
b.Property<DateTime?>("UpdatedTime")
.HasColumnType("timestamp with time zone");
b.Property<int>("Version")
.HasColumnType("integer");
b.HasKey("Id");
b.HasIndex("ClusterId");
b.HasIndex("ServiceName");
b.HasIndex("TenantCode");
b.HasIndex("ServiceName", "IsGlobal", "Status");
b.ToTable("gw_tenant_routes", (string)null);
});
modelBuilder.Entity("Fengling.Platform.Domain.AggregatesModel.RoleAggregate.ApplicationRole", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("bigint");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasColumnType("text");
b.Property<DateTimeOffset>("CreatedTime")
.HasColumnType("timestamp with time zone");
b.Property<string>("Description")
.HasMaxLength(200)
.HasColumnType("character varying(200)");
b.Property<string>("DisplayName")
.HasColumnType("text");
b.Property<bool>("IsSystem")
.HasColumnType("boolean");
b.Property<string>("Name")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.Property<string>("NormalizedName")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.PrimitiveCollection<List<string>>("Permissions")
.HasColumnType("text[]");
b.Property<long?>("TenantId")
.HasColumnType("bigint");
b.HasKey("Id");
b.HasIndex("NormalizedName")
.IsUnique()
.HasDatabaseName("RoleNameIndex");
b.ToTable("idn_roles", (string)null);
});
modelBuilder.Entity("Fengling.Platform.Domain.AggregatesModel.TenantAggregate.Tenant", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("bigint");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
b.Property<string>("ContactEmail")
.IsRequired()
.HasMaxLength(100)
.HasColumnType("character varying(100)");
b.Property<string>("ContactName")
.IsRequired()
.HasMaxLength(50)
.HasColumnType("character varying(50)");
b.Property<string>("ContactPhone")
.HasMaxLength(20)
.HasColumnType("character varying(20)");
b.Property<DateTime>("CreatedAt")
.HasColumnType("timestamp with time zone");
b.Property<string>("Description")
.HasMaxLength(500)
.HasColumnType("character varying(500)");
b.Property<DateTime?>("ExpiresAt")
.HasColumnType("timestamp with time zone");
b.Property<bool>("IsDeleted")
.HasColumnType("boolean");
b.Property<int?>("MaxUsers")
.HasColumnType("integer");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(100)
.HasColumnType("character varying(100)");
b.Property<long>("RowVersion")
.HasColumnType("bigint");
b.Property<int>("Status")
.HasColumnType("integer");
b.Property<string>("TenantCode")
.IsRequired()
.HasMaxLength(50)
.HasColumnType("character varying(50)");
b.Property<DateTime?>("UpdatedAt")
.HasColumnType("timestamp with time zone");
b.HasKey("Id");
b.HasIndex("Status");
b.HasIndex("TenantCode")
.IsUnique();
b.ToTable("sys_tenants", (string)null);
});
modelBuilder.Entity("Fengling.Platform.Domain.AggregatesModel.UserAggregate.AccessLog", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("bigint");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
b.Property<string>("Action")
.IsRequired()
.HasMaxLength(20)
.HasColumnType("character varying(20)");
b.Property<DateTime>("CreatedAt")
.HasColumnType("timestamp with time zone");
b.Property<int>("Duration")
.HasColumnType("integer");
b.Property<string>("ErrorMessage")
.HasColumnType("text");
b.Property<string>("IpAddress")
.HasMaxLength(50)
.HasColumnType("character varying(50)");
b.Property<string>("Method")
.HasMaxLength(10)
.HasColumnType("character varying(10)");
b.Property<string>("RequestData")
.HasColumnType("text");
b.Property<string>("Resource")
.HasMaxLength(200)
.HasColumnType("character varying(200)");
b.Property<string>("ResponseData")
.HasColumnType("text");
b.Property<string>("Status")
.IsRequired()
.HasMaxLength(20)
.HasColumnType("character varying(20)");
b.Property<string>("TenantId")
.HasMaxLength(50)
.HasColumnType("character varying(50)");
b.Property<string>("UserAgent")
.HasMaxLength(500)
.HasColumnType("character varying(500)");
b.Property<string>("UserName")
.HasMaxLength(50)
.HasColumnType("character varying(50)");
b.HasKey("Id");
b.HasIndex("Action");
b.HasIndex("CreatedAt");
b.HasIndex("Status");
b.HasIndex("TenantId");
b.HasIndex("UserName");
b.ToTable("sys_access_logs", (string)null);
});
modelBuilder.Entity("Fengling.Platform.Domain.AggregatesModel.UserAggregate.ApplicationUser", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("bigint");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
b.Property<int>("AccessFailedCount")
.HasColumnType("integer");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasColumnType("text");
b.Property<DateTimeOffset>("CreatedTime")
.HasColumnType("timestamp with time zone");
b.Property<string>("Email")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.Property<bool>("EmailConfirmed")
.HasColumnType("boolean");
b.Property<bool>("IsDeleted")
.HasColumnType("boolean");
b.Property<bool>("LockoutEnabled")
.HasColumnType("boolean");
b.Property<DateTimeOffset?>("LockoutEnd")
.HasColumnType("timestamp with time zone");
b.Property<string>("NormalizedEmail")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.Property<string>("NormalizedUserName")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.Property<string>("PasswordHash")
.HasColumnType("text");
b.Property<string>("PhoneNumber")
.HasMaxLength(20)
.HasColumnType("character varying(20)");
b.Property<bool>("PhoneNumberConfirmed")
.HasColumnType("boolean");
b.Property<string>("RealName")
.IsRequired()
.HasColumnType("text");
b.Property<string>("SecurityStamp")
.HasColumnType("text");
b.Property<bool>("TwoFactorEnabled")
.HasColumnType("boolean");
b.Property<DateTimeOffset?>("UpdatedTime")
.HasColumnType("timestamp with time zone");
b.Property<string>("UserName")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.HasKey("Id");
b.HasIndex("NormalizedEmail")
.HasDatabaseName("EmailIndex");
b.HasIndex("NormalizedUserName")
.IsUnique()
.HasDatabaseName("UserNameIndex");
b.HasIndex("PhoneNumber")
.IsUnique();
b.ToTable("idn_users", (string)null);
});
modelBuilder.Entity("Fengling.Platform.Domain.AggregatesModel.UserAggregate.AuditLog", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("bigint");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
b.Property<string>("Action")
.IsRequired()
.HasMaxLength(20)
.HasColumnType("character varying(20)");
b.Property<DateTime>("CreatedAt")
.HasColumnType("timestamp with time zone");
b.Property<string>("Description")
.HasMaxLength(500)
.HasColumnType("character varying(500)");
b.Property<string>("ErrorMessage")
.HasColumnType("text");
b.Property<string>("IpAddress")
.IsRequired()
.HasMaxLength(50)
.HasColumnType("character varying(50)");
b.Property<string>("NewValue")
.HasColumnType("text");
b.Property<string>("OldValue")
.HasColumnType("text");
b.Property<string>("Operation")
.IsRequired()
.HasMaxLength(20)
.HasColumnType("character varying(20)");
b.Property<string>("Operator")
.IsRequired()
.HasMaxLength(50)
.HasColumnType("character varying(50)");
b.Property<string>("Status")
.IsRequired()
.HasMaxLength(20)
.HasColumnType("character varying(20)");
b.Property<long?>("TargetId")
.HasColumnType("bigint");
b.Property<string>("TargetName")
.HasMaxLength(100)
.HasColumnType("character varying(100)");
b.Property<string>("TargetType")
.HasMaxLength(50)
.HasColumnType("character varying(50)");
b.Property<string>("TenantId")
.HasMaxLength(50)
.HasColumnType("character varying(50)");
b.HasKey("Id");
b.HasIndex("Action");
b.HasIndex("CreatedAt");
b.HasIndex("Operation");
b.HasIndex("Operator");
b.HasIndex("TenantId");
b.ToTable("sys_audit_logs", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<long>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<string>("ClaimType")
.HasColumnType("text");
b.Property<string>("ClaimValue")
.HasColumnType("text");
b.Property<long>("RoleId")
.HasColumnType("bigint");
b.HasKey("Id");
b.HasIndex("RoleId");
b.ToTable("idn_role_claims", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<long>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<string>("ClaimType")
.HasColumnType("text");
b.Property<string>("ClaimValue")
.HasColumnType("text");
b.Property<long>("UserId")
.HasColumnType("bigint");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("idn_user_claims", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<long>", b =>
{
b.Property<string>("LoginProvider")
.HasColumnType("text");
b.Property<string>("ProviderKey")
.HasColumnType("text");
b.Property<string>("ProviderDisplayName")
.HasColumnType("text");
b.Property<long>("UserId")
.HasColumnType("bigint");
b.HasKey("LoginProvider", "ProviderKey");
b.HasIndex("UserId");
b.ToTable("idn_user_logins", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<long>", b =>
{
b.Property<long>("UserId")
.HasColumnType("bigint");
b.Property<long>("RoleId")
.HasColumnType("bigint");
b.HasKey("UserId", "RoleId");
b.HasIndex("RoleId");
b.ToTable("idn_user_roles", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<long>", b =>
{
b.Property<long>("UserId")
.HasColumnType("bigint");
b.Property<string>("LoginProvider")
.HasColumnType("text");
b.Property<string>("Name")
.HasColumnType("text");
b.Property<string>("Value")
.HasColumnType("text");
b.HasKey("UserId", "LoginProvider", "Name");
b.ToTable("idn_user_tokens", (string)null);
});
modelBuilder.Entity("Fengling.Platform.Domain.AggregatesModel.UserAggregate.ApplicationUser", b =>
{
b.OwnsOne("Fengling.Platform.Domain.AggregatesModel.TenantAggregate.TenantInfo", "TenantInfo", b1 =>
{
b1.Property<long>("ApplicationUserId")
.HasColumnType("bigint");
b1.Property<string>("TenantCode")
.HasColumnType("text")
.HasColumnName("TenantCode");
b1.Property<long?>("TenantId")
.HasColumnType("bigint")
.HasColumnName("TenantId");
b1.Property<string>("TenantName")
.HasColumnType("text")
.HasColumnName("TenantName");
b1.HasKey("ApplicationUserId");
b1.ToTable("idn_users");
b1.WithOwner()
.HasForeignKey("ApplicationUserId");
});
b.Navigation("TenantInfo");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<long>", b =>
{
b.HasOne("Fengling.Platform.Domain.AggregatesModel.RoleAggregate.ApplicationRole", null)
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<long>", b =>
{
b.HasOne("Fengling.Platform.Domain.AggregatesModel.UserAggregate.ApplicationUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<long>", b =>
{
b.HasOne("Fengling.Platform.Domain.AggregatesModel.UserAggregate.ApplicationUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<long>", b =>
{
b.HasOne("Fengling.Platform.Domain.AggregatesModel.RoleAggregate.ApplicationRole", null)
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("Fengling.Platform.Domain.AggregatesModel.UserAggregate.ApplicationUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<long>", b =>
{
b.HasOne("Fengling.Platform.Domain.AggregatesModel.UserAggregate.ApplicationUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
#pragma warning restore 612, 618
}
}
}

254
src/Migrations/initial.sql Normal file
View File

@ -0,0 +1,254 @@
CREATE TABLE IF NOT EXISTS "__EFMigrationsHistory" (
"MigrationId" character varying(150) NOT NULL,
"ProductVersion" character varying(32) NOT NULL,
CONSTRAINT "PK___EFMigrationsHistory" PRIMARY KEY ("MigrationId")
);
START TRANSACTION;
CREATE TABLE gw_service_instances (
"Id" text NOT NULL,
"ClusterId" character varying(100) NOT NULL,
"DestinationId" character varying(100) NOT NULL,
"Address" character varying(200) NOT NULL,
"Health" integer NOT NULL,
"Weight" integer NOT NULL,
"Status" integer NOT NULL,
"CreatedBy" bigint,
"CreatedTime" timestamp with time zone NOT NULL,
"UpdatedBy" bigint,
"UpdatedTime" timestamp with time zone,
"IsDeleted" boolean NOT NULL,
"Version" integer NOT NULL,
CONSTRAINT "PK_gw_service_instances" PRIMARY KEY ("Id")
);
CREATE TABLE gw_tenant_routes (
"Id" text NOT NULL,
"TenantCode" character varying(50) NOT NULL,
"ServiceName" character varying(100) NOT NULL,
"ClusterId" character varying(100) NOT NULL,
"PathPattern" character varying(200) NOT NULL,
"Priority" integer NOT NULL,
"Status" integer NOT NULL,
"IsGlobal" boolean NOT NULL,
"CreatedBy" bigint,
"CreatedTime" timestamp with time zone NOT NULL,
"UpdatedBy" bigint,
"UpdatedTime" timestamp with time zone,
"IsDeleted" boolean NOT NULL,
"Version" integer NOT NULL,
CONSTRAINT "PK_gw_tenant_routes" PRIMARY KEY ("Id")
);
CREATE TABLE gw_tenants (
"Id" bigint GENERATED BY DEFAULT AS IDENTITY,
"TenantCode" character varying(50) NOT NULL,
"TenantName" character varying(100) NOT NULL,
"Status" integer NOT NULL,
"CreatedBy" bigint,
"CreatedTime" timestamp with time zone NOT NULL,
"UpdatedBy" bigint,
"UpdatedTime" timestamp with time zone,
"IsDeleted" boolean NOT NULL,
"Version" integer NOT NULL,
CONSTRAINT "PK_gw_tenants" PRIMARY KEY ("Id")
);
CREATE TABLE idn_roles (
"Id" bigint GENERATED BY DEFAULT AS IDENTITY,
"Description" character varying(200),
"CreatedTime" timestamp with time zone NOT NULL,
"TenantId" bigint,
"IsSystem" boolean NOT NULL,
"DisplayName" text,
"Permissions" text[],
"Name" character varying(256),
"NormalizedName" character varying(256),
"ConcurrencyStamp" text,
CONSTRAINT "PK_idn_roles" PRIMARY KEY ("Id")
);
CREATE TABLE idn_users (
"Id" bigint GENERATED BY DEFAULT AS IDENTITY,
"RealName" text NOT NULL,
"TenantId" bigint,
"TenantCode" text,
"TenantName" text,
"CreatedTime" timestamp with time zone NOT NULL,
"UpdatedTime" timestamp with time zone,
"IsDeleted" boolean NOT NULL,
"UserName" character varying(256),
"NormalizedUserName" character varying(256),
"Email" character varying(256),
"NormalizedEmail" character varying(256),
"EmailConfirmed" boolean NOT NULL,
"PasswordHash" text,
"SecurityStamp" text,
"ConcurrencyStamp" text,
"PhoneNumber" character varying(20),
"PhoneNumberConfirmed" boolean NOT NULL,
"TwoFactorEnabled" boolean NOT NULL,
"LockoutEnd" timestamp with time zone,
"LockoutEnabled" boolean NOT NULL,
"AccessFailedCount" integer NOT NULL,
CONSTRAINT "PK_idn_users" PRIMARY KEY ("Id")
);
CREATE TABLE sys_access_logs (
"Id" bigint GENERATED BY DEFAULT AS IDENTITY,
"UserName" character varying(50),
"TenantId" character varying(50),
"Action" character varying(20) NOT NULL,
"Resource" character varying(200),
"Method" character varying(10),
"IpAddress" character varying(50),
"UserAgent" character varying(500),
"Status" character varying(20) NOT NULL,
"Duration" integer NOT NULL,
"RequestData" text,
"ResponseData" text,
"ErrorMessage" text,
"CreatedAt" timestamp with time zone NOT NULL,
CONSTRAINT "PK_sys_access_logs" PRIMARY KEY ("Id")
);
CREATE TABLE sys_audit_logs (
"Id" bigint GENERATED BY DEFAULT AS IDENTITY,
"Operator" character varying(50) NOT NULL,
"TenantId" character varying(50),
"Operation" character varying(20) NOT NULL,
"Action" character varying(20) NOT NULL,
"TargetType" character varying(50),
"TargetId" bigint,
"TargetName" character varying(100),
"IpAddress" character varying(50) NOT NULL,
"Description" character varying(500),
"OldValue" text,
"NewValue" text,
"ErrorMessage" text,
"Status" character varying(20) NOT NULL,
"CreatedAt" timestamp with time zone NOT NULL,
CONSTRAINT "PK_sys_audit_logs" PRIMARY KEY ("Id")
);
CREATE TABLE sys_tenants (
"Id" bigint GENERATED BY DEFAULT AS IDENTITY,
"TenantCode" character varying(50) NOT NULL,
"Name" character varying(100) NOT NULL,
"ContactName" character varying(50) NOT NULL,
"ContactEmail" character varying(100) NOT NULL,
"ContactPhone" character varying(20),
"MaxUsers" integer,
"CreatedAt" timestamp with time zone NOT NULL,
"UpdatedAt" timestamp with time zone,
"ExpiresAt" timestamp with time zone,
"Description" character varying(500),
"Status" integer NOT NULL,
"IsDeleted" boolean NOT NULL,
"RowVersion" bigint NOT NULL,
CONSTRAINT "PK_sys_tenants" PRIMARY KEY ("Id")
);
CREATE TABLE idn_role_claims (
"Id" integer GENERATED BY DEFAULT AS IDENTITY,
"RoleId" bigint NOT NULL,
"ClaimType" text,
"ClaimValue" text,
CONSTRAINT "PK_idn_role_claims" PRIMARY KEY ("Id"),
CONSTRAINT "FK_idn_role_claims_idn_roles_RoleId" FOREIGN KEY ("RoleId") REFERENCES idn_roles ("Id") ON DELETE CASCADE
);
CREATE TABLE idn_user_claims (
"Id" integer GENERATED BY DEFAULT AS IDENTITY,
"UserId" bigint NOT NULL,
"ClaimType" text,
"ClaimValue" text,
CONSTRAINT "PK_idn_user_claims" PRIMARY KEY ("Id"),
CONSTRAINT "FK_idn_user_claims_idn_users_UserId" FOREIGN KEY ("UserId") REFERENCES idn_users ("Id") ON DELETE CASCADE
);
CREATE TABLE idn_user_logins (
"LoginProvider" text NOT NULL,
"ProviderKey" text NOT NULL,
"ProviderDisplayName" text,
"UserId" bigint NOT NULL,
CONSTRAINT "PK_idn_user_logins" PRIMARY KEY ("LoginProvider", "ProviderKey"),
CONSTRAINT "FK_idn_user_logins_idn_users_UserId" FOREIGN KEY ("UserId") REFERENCES idn_users ("Id") ON DELETE CASCADE
);
CREATE TABLE idn_user_roles (
"UserId" bigint NOT NULL,
"RoleId" bigint NOT NULL,
CONSTRAINT "PK_idn_user_roles" PRIMARY KEY ("UserId", "RoleId"),
CONSTRAINT "FK_idn_user_roles_idn_roles_RoleId" FOREIGN KEY ("RoleId") REFERENCES idn_roles ("Id") ON DELETE CASCADE,
CONSTRAINT "FK_idn_user_roles_idn_users_UserId" FOREIGN KEY ("UserId") REFERENCES idn_users ("Id") ON DELETE CASCADE
);
CREATE TABLE idn_user_tokens (
"UserId" bigint NOT NULL,
"LoginProvider" text NOT NULL,
"Name" text NOT NULL,
"Value" text,
CONSTRAINT "PK_idn_user_tokens" PRIMARY KEY ("UserId", "LoginProvider", "Name"),
CONSTRAINT "FK_idn_user_tokens_idn_users_UserId" FOREIGN KEY ("UserId") REFERENCES idn_users ("Id") ON DELETE CASCADE
);
CREATE UNIQUE INDEX "IX_gw_service_instances_ClusterId_DestinationId" ON gw_service_instances ("ClusterId", "DestinationId");
CREATE INDEX "IX_gw_service_instances_Health" ON gw_service_instances ("Health");
CREATE INDEX "IX_gw_tenant_routes_ClusterId" ON gw_tenant_routes ("ClusterId");
CREATE INDEX "IX_gw_tenant_routes_ServiceName" ON gw_tenant_routes ("ServiceName");
CREATE INDEX "IX_gw_tenant_routes_ServiceName_IsGlobal_Status" ON gw_tenant_routes ("ServiceName", "IsGlobal", "Status");
CREATE INDEX "IX_gw_tenant_routes_TenantCode" ON gw_tenant_routes ("TenantCode");
CREATE UNIQUE INDEX "IX_gw_tenants_TenantCode" ON gw_tenants ("TenantCode");
CREATE INDEX "IX_idn_role_claims_RoleId" ON idn_role_claims ("RoleId");
CREATE UNIQUE INDEX "RoleNameIndex" ON idn_roles ("NormalizedName");
CREATE INDEX "IX_idn_user_claims_UserId" ON idn_user_claims ("UserId");
CREATE INDEX "IX_idn_user_logins_UserId" ON idn_user_logins ("UserId");
CREATE INDEX "IX_idn_user_roles_RoleId" ON idn_user_roles ("RoleId");
CREATE INDEX "EmailIndex" ON idn_users ("NormalizedEmail");
CREATE UNIQUE INDEX "IX_idn_users_PhoneNumber" ON idn_users ("PhoneNumber");
CREATE UNIQUE INDEX "UserNameIndex" ON idn_users ("NormalizedUserName");
CREATE INDEX "IX_sys_access_logs_Action" ON sys_access_logs ("Action");
CREATE INDEX "IX_sys_access_logs_CreatedAt" ON sys_access_logs ("CreatedAt");
CREATE INDEX "IX_sys_access_logs_Status" ON sys_access_logs ("Status");
CREATE INDEX "IX_sys_access_logs_TenantId" ON sys_access_logs ("TenantId");
CREATE INDEX "IX_sys_access_logs_UserName" ON sys_access_logs ("UserName");
CREATE INDEX "IX_sys_audit_logs_Action" ON sys_audit_logs ("Action");
CREATE INDEX "IX_sys_audit_logs_CreatedAt" ON sys_audit_logs ("CreatedAt");
CREATE INDEX "IX_sys_audit_logs_Operation" ON sys_audit_logs ("Operation");
CREATE INDEX "IX_sys_audit_logs_Operator" ON sys_audit_logs ("Operator");
CREATE INDEX "IX_sys_audit_logs_TenantId" ON sys_audit_logs ("TenantId");
CREATE INDEX "IX_sys_tenants_Status" ON sys_tenants ("Status");
CREATE UNIQUE INDEX "IX_sys_tenants_TenantCode" ON sys_tenants ("TenantCode");
INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion")
VALUES ('20260301040647_Initial', '10.0.3');
COMMIT;

View File

@ -2,7 +2,7 @@ namespace Fengling.Console.Models.Dtos;
public class GatewayServiceDto public class GatewayServiceDto
{ {
public long Id { get; set; } public string Id { get; set; } = "";
public string ServicePrefix { get; set; } = ""; public string ServicePrefix { get; set; } = "";
public string ServiceName { get; set; } = ""; public string ServiceName { get; set; } = "";
public string Version { get; set; } = "v1"; public string Version { get; set; } = "v1";
@ -32,7 +32,7 @@ public class CreateGatewayServiceDto
public class GatewayRouteDto public class GatewayRouteDto
{ {
public long Id { get; set; } public string Id { get; set; } = "";
public string ServiceName { get; set; } = ""; public string ServiceName { get; set; } = "";
public string ClusterId { get; set; } = ""; public string ClusterId { get; set; } = "";
public string PathPattern { get; set; } = ""; public string PathPattern { get; set; } = "";
@ -55,7 +55,7 @@ public class CreateGatewayRouteDto
public class GatewayInstanceDto public class GatewayInstanceDto
{ {
public long Id { get; set; } public string Id { get; set; } = "";
public string ClusterId { get; set; } = ""; public string ClusterId { get; set; } = "";
public string DestinationId { get; set; } = ""; public string DestinationId { get; set; } = "";
public string Address { get; set; } = ""; public string Address { get; set; } = "";

View File

@ -1,4 +1,6 @@
using System.Reflection; using System.Reflection;
using Fengling.Console.Data;
using Fengling.Console.Services;
using Fengling.Console.Services; using Fengling.Console.Services;
using Fengling.Platform.Domain.AggregatesModel.UserAggregate; using Fengling.Platform.Domain.AggregatesModel.UserAggregate;
using Fengling.Platform.Domain.AggregatesModel.RoleAggregate; using Fengling.Platform.Domain.AggregatesModel.RoleAggregate;
@ -17,7 +19,16 @@ var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers(); builder.Services.AddControllers();
// Use PlatformDbContext for all identity // Use ConsoleDbContext for all identity
builder.Services.AddDbContext<ConsoleDbContext>(options =>
{
options.UseNpgsql(builder.Configuration.GetConnectionString("DefaultConnection"));
if (builder.Environment.IsDevelopment())
{
options.EnableSensitiveDataLogging();
}
options.EnableDetailedErrors();
});
builder.Services.AddDbContext<PlatformDbContext>(options => builder.Services.AddDbContext<PlatformDbContext>(options =>
{ {
options.UseNpgsql(builder.Configuration.GetConnectionString("DefaultConnection")); options.UseNpgsql(builder.Configuration.GetConnectionString("DefaultConnection"));
@ -31,6 +42,7 @@ builder.Services.AddDbContext<PlatformDbContext>(options =>
// Use Platform's identity // Use Platform's identity
builder.Services.AddIdentity<ApplicationUser, ApplicationRole>() builder.Services.AddIdentity<ApplicationUser, ApplicationRole>()
.AddEntityFrameworkStores<ConsoleDbContext>()
.AddEntityFrameworkStores<PlatformDbContext>() .AddEntityFrameworkStores<PlatformDbContext>()
.AddDefaultTokenProviders(); .AddDefaultTokenProviders();
@ -40,14 +52,15 @@ builder.Services.AddHttpClient();
builder.Services.AddScoped<IOAuthClientService, OAuthClientService>(); builder.Services.AddScoped<IOAuthClientService, OAuthClientService>();
// Register Platform managers // Register Platform managers
builder.Services.AddScoped<ITenantStore, TenantStore<PlatformDbContext>>(); builder.Services.AddScoped<ITenantStore, TenantStore<ConsoleDbContext>>();
builder.Services.AddScoped<ITenantManager, TenantManager>(); builder.Services.AddScoped<ITenantManager, TenantManager>();
// Register Gateway managers // Register Gateway managers
builder.Services.AddScoped<IRouteStore, RouteStore<PlatformDbContext>>(); builder.Services.AddScoped<IRouteStore, RouteStore<ConsoleDbContext>>();
builder.Services.AddScoped<IInstanceStore, InstanceStore<ConsoleDbContext>>();
builder.Services.AddScoped<IInstanceStore, InstanceStore<PlatformDbContext>>(); builder.Services.AddScoped<IInstanceStore, InstanceStore<PlatformDbContext>>();
builder.Services.AddScoped<IRouteManager, RouteManager>(); builder.Services.AddScoped<IRouteManager, RouteManager>();
builder.Services.AddScoped<ITenantStore, TenantStore<PlatformDbContext>>(); builder.Services.AddScoped<ITenantStore, TenantStore<ConsoleDbContext>>();
builder.Services.AddScoped<ITenantManager, TenantManager>(); builder.Services.AddScoped<ITenantManager, TenantManager>();
builder.Services.AddScoped<IUserService, UserService>(); builder.Services.AddScoped<IUserService, UserService>();
@ -57,6 +70,7 @@ builder.Services.AddScoped<IGatewayService, GatewayService>();
builder.Services.AddScoped<IH5LinkService, H5LinkService>(); builder.Services.AddScoped<IH5LinkService, H5LinkService>();
builder.Services.AddOpenIddict() builder.Services.AddOpenIddict()
.AddCore(options => { options.UseEntityFrameworkCore().UseDbContext<ConsoleDbContext>(); })
.AddCore(options => { options.UseEntityFrameworkCore().UseDbContext<PlatformDbContext>(); }) .AddCore(options => { options.UseEntityFrameworkCore().UseDbContext<PlatformDbContext>(); })
.AddValidation(options => .AddValidation(options =>
{ {
@ -95,7 +109,7 @@ builder.Services.AddSwaggerGen(c =>
c.CustomSchemaIds(type => type.FullName); c.CustomSchemaIds(type => type.FullName);
}); });
builder.Services.AddRepositories(typeof(PlatformDbContext).Assembly); builder.Services.AddRepositories(typeof(ConsoleDbContext).Assembly);
var app = builder.Build(); var app = builder.Build();

View File

@ -1,7 +1,5 @@
using Fengling.Platform.Infrastructure;
using Fengling.Platform.Domain.AggregatesModel.GatewayAggregate; using Fengling.Platform.Domain.AggregatesModel.GatewayAggregate;
using Fengling.Platform.Infrastructure;
using Microsoft.EntityFrameworkCore;
using Fengling.Console.Models.Dtos; using Fengling.Console.Models.Dtos;
namespace Fengling.Console.Services; namespace Fengling.Console.Services;
@ -17,35 +15,43 @@ public interface IGatewayService
Task<GatewayRouteDto> CreateRouteAsync(CreateGatewayRouteDto dto); Task<GatewayRouteDto> CreateRouteAsync(CreateGatewayRouteDto dto);
Task<List<GatewayInstanceDto>> GetInstancesAsync(string clusterId); Task<List<GatewayInstanceDto>> GetInstancesAsync(string clusterId);
Task<GatewayInstanceDto> AddInstanceAsync(CreateGatewayInstanceDto dto); Task<GatewayInstanceDto> AddInstanceAsync(CreateGatewayInstanceDto dto);
Task<bool> RemoveInstanceAsync(long instanceId); Task<bool> RemoveInstanceAsync(string instanceId);
Task<bool> UpdateInstanceWeightAsync(long instanceId, int weight); Task<bool> UpdateInstanceWeightAsync(string instanceId, int weight);
Task ReloadGatewayAsync(); Task ReloadGatewayAsync();
} }
public class GatewayService : IGatewayService public class GatewayService : IGatewayService
{ {
private readonly PlatformDbContext _dbContext; private readonly IRouteStore _routeStore;
private readonly IInstanceStore _instanceStore;
private readonly ILogger<GatewayService> _logger; private readonly ILogger<GatewayService> _logger;
public GatewayService(PlatformDbContext dbContext, ILogger<GatewayService> logger) public GatewayService(
IRouteStore routeStore,
IInstanceStore instanceStore,
ILogger<GatewayService> logger)
{ {
_dbContext = dbContext; _routeStore = routeStore;
_instanceStore = instanceStore;
_logger = logger; _logger = logger;
} }
public async Task<GatewayStatisticsDto> GetStatisticsAsync() public async Task<GatewayStatisticsDto> GetStatisticsAsync()
{ {
var routes = await _dbContext.GwTenantRoutes.Where(r => !r.IsDeleted).ToListAsync(); var routes = await _routeStore.GetAllAsync();
var instances = await _dbContext.GwServiceInstances.Where(i => !i.IsDeleted).ToListAsync(); var instances = await _instanceStore.GetAllAsync();
var activeRoutes = routes.Where(r => !r.IsDeleted).ToList();
var activeInstances = instances.Where(i => !i.IsDeleted).ToList();
return new GatewayStatisticsDto return new GatewayStatisticsDto
{ {
TotalServices = routes.Select(r => r.ServiceName).Distinct().Count(), TotalServices = activeRoutes.Select(r => r.ServiceName).Distinct().Count(),
GlobalRoutes = routes.Count(r => r.IsGlobal), GlobalRoutes = activeRoutes.Count(r => r.IsGlobal),
TenantRoutes = routes.Count(r => !r.IsGlobal), TenantRoutes = activeRoutes.Count(r => !r.IsGlobal),
TotalInstances = instances.Count, TotalInstances = activeInstances.Count,
HealthyInstances = instances.Count(i => i.Health == 1), HealthyInstances = activeInstances.Count(i => i.Health == (int)InstanceHealth.Healthy),
RecentServices = routes RecentServices = activeRoutes
.OrderByDescending(r => r.CreatedTime) .OrderByDescending(r => r.CreatedTime)
.Take(5) .Take(5)
.Select(MapToServiceDto) .Select(MapToServiceDto)
@ -55,38 +61,41 @@ public class GatewayService : IGatewayService
public async Task<List<GatewayServiceDto>> GetServicesAsync(bool globalOnly = false, string? tenantCode = null) public async Task<List<GatewayServiceDto>> GetServicesAsync(bool globalOnly = false, string? tenantCode = null)
{ {
var query = _dbContext.GwTenantRoutes.Where(r => !r.IsDeleted); var routes = await _routeStore.GetAllAsync();
var instances = await _instanceStore.GetAllAsync();
var query = routes.Where(r => !r.IsDeleted);
if (globalOnly) if (globalOnly)
query = query.Where(r => r.IsGlobal); query = query.Where(r => r.IsGlobal);
else if (!string.IsNullOrEmpty(tenantCode)) else if (!string.IsNullOrEmpty(tenantCode))
query = query.Where(r => r.TenantCode == tenantCode); query = query.Where(r => r.TenantCode == tenantCode);
var routes = await query.OrderByDescending(r => r.CreatedTime).ToListAsync(); var routeList = query.OrderByDescending(r => r.CreatedTime).ToList();
var clusters = routes.Select(r => r.ClusterId).Distinct().ToList(); var clusters = routeList.Select(r => r.ClusterId).Distinct().ToList();
var instances = await _dbContext.GwServiceInstances var instancesDict = instances
.Where(i => clusters.Contains(i.ClusterId) && !i.IsDeleted) .Where(i => clusters.Contains(i.ClusterId) && !i.IsDeleted)
.GroupBy(i => i.ClusterId) .GroupBy(i => i.ClusterId)
.ToDictionaryAsync(g => g.Key, g => g.Count()); .ToDictionary(g => g.Key, g => g.Count());
return routes.Select(r => MapToServiceDto(r, instances.GetValueOrDefault(r.ClusterId, 0))).ToList(); return routeList.Select(r => MapToServiceDto(r, instancesDict.GetValueOrDefault(r.ClusterId, 0))).ToList();
} }
public async Task<GatewayServiceDto?> GetServiceAsync(string serviceName, string? tenantCode = null) public async Task<GatewayServiceDto?> GetServiceAsync(string serviceName, string? tenantCode = null)
{ {
var route = await _dbContext.GwTenantRoutes var routes = await _routeStore.GetAllAsync();
.FirstOrDefaultAsync(r => var route = routes.FirstOrDefault(r =>
r.ServiceName == serviceName && r.ServiceName == serviceName &&
r.IsDeleted == false && !r.IsDeleted &&
(r.IsGlobal || r.TenantCode == tenantCode)); (r.IsGlobal || r.TenantCode == tenantCode));
if (route == null) return null; if (route == null) return null;
var instances = await _dbContext.GwServiceInstances var instances = await _instanceStore.GetAllAsync();
.CountAsync(i => i.ClusterId == route.ClusterId && !i.IsDeleted); var instanceCount = instances.Count(i => i.ClusterId == route.ClusterId && !i.IsDeleted);
return MapToServiceDto(route, instances); return MapToServiceDto(route, instanceCount);
} }
public async Task<GatewayServiceDto> RegisterServiceAsync(CreateGatewayServiceDto dto) public async Task<GatewayServiceDto> RegisterServiceAsync(CreateGatewayServiceDto dto)
@ -98,11 +107,11 @@ public class GatewayService : IGatewayService
: dto.DestinationId; : dto.DestinationId;
// Check if route already exists // Check if route already exists
var existingRoute = await _dbContext.GwTenantRoutes var routes = await _routeStore.GetAllAsync();
.FirstOrDefaultAsync(r => var existingRoute = routes.FirstOrDefault(r =>
r.ServiceName == dto.ServicePrefix && r.ServiceName == dto.ServicePrefix &&
r.IsGlobal == dto.IsGlobal && r.IsGlobal == dto.IsGlobal &&
(dto.IsGlobal || r.TenantCode == dto.TenantCode)); (dto.IsGlobal || r.TenantCode == dto.TenantCode));
if (existingRoute != null) if (existingRoute != null)
{ {
@ -110,7 +119,7 @@ public class GatewayService : IGatewayService
} }
// Add instance // Add instance
var instanceId = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); var instanceId = Guid.CreateVersion7().ToString("N");
var instance = new GwServiceInstance var instance = new GwServiceInstance
{ {
Id = instanceId, Id = instanceId,
@ -118,14 +127,14 @@ public class GatewayService : IGatewayService
DestinationId = destinationId, DestinationId = destinationId,
Address = dto.ServiceAddress, Address = dto.ServiceAddress,
Weight = dto.Weight, Weight = dto.Weight,
Health = 1, Health = (int)InstanceHealth.Healthy,
Status = 1, Status = (int)InstanceStatus.Active,
CreatedTime = DateTime.UtcNow CreatedTime = DateTime.UtcNow
}; };
await _dbContext.GwServiceInstances.AddAsync(instance); await _instanceStore.CreateAsync(instance);
// Add route // Add route
var routeId = instanceId + 1; var routeId = Guid.CreateVersion7().ToString("N");
var route = new GwTenantRoute var route = new GwTenantRoute
{ {
Id = routeId, Id = routeId,
@ -134,13 +143,11 @@ public class GatewayService : IGatewayService
ClusterId = clusterId, ClusterId = clusterId,
PathPattern = pathPattern, PathPattern = pathPattern,
Priority = dto.IsGlobal ? 0 : 10, Priority = dto.IsGlobal ? 0 : 10,
Status = 1, Status = (int)RouteStatus.Active,
IsGlobal = dto.IsGlobal, IsGlobal = dto.IsGlobal,
CreatedTime = DateTime.UtcNow CreatedTime = DateTime.UtcNow
}; };
await _dbContext.GwTenantRoutes.AddAsync(route); await _routeStore.CreateAsync(route);
await _dbContext.SaveChangesAsync();
_logger.LogInformation("Registered service {Service} at {Address}", dto.ServicePrefix, dto.ServiceAddress); _logger.LogInformation("Registered service {Service} at {Address}", dto.ServicePrefix, dto.ServiceAddress);
@ -149,31 +156,30 @@ public class GatewayService : IGatewayService
public async Task<bool> UnregisterServiceAsync(string serviceName, string? tenantCode = null) public async Task<bool> UnregisterServiceAsync(string serviceName, string? tenantCode = null)
{ {
var route = await _dbContext.GwTenantRoutes var routes = await _routeStore.GetAllAsync();
.FirstOrDefaultAsync(r => var route = routes.FirstOrDefault(r =>
r.ServiceName == serviceName && r.ServiceName == serviceName &&
r.IsDeleted == false && !r.IsDeleted &&
(r.IsGlobal || r.TenantCode == tenantCode)); (r.IsGlobal || r.TenantCode == tenantCode));
if (route == null) return false; if (route == null) return false;
// Soft delete route // Soft delete route
route.IsDeleted = true; route.IsDeleted = true;
route.UpdatedTime = DateTime.UtcNow; route.UpdatedTime = DateTime.UtcNow;
await _routeStore.UpdateAsync(route);
// Soft delete instances // Soft delete instances
var instances = await _dbContext.GwServiceInstances var instances = await _instanceStore.GetAllAsync();
.Where(i => i.ClusterId == route.ClusterId && !i.IsDeleted) var routeInstances = instances.Where(i => i.ClusterId == route.ClusterId && !i.IsDeleted).ToList();
.ToListAsync();
foreach (var instance in instances) foreach (var instance in routeInstances)
{ {
instance.IsDeleted = true; instance.IsDeleted = true;
instance.UpdatedTime = DateTime.UtcNow; instance.UpdatedTime = DateTime.UtcNow;
await _instanceStore.UpdateAsync(instance);
} }
await _dbContext.SaveChangesAsync();
_logger.LogInformation("Unregistered service {Service}", serviceName); _logger.LogInformation("Unregistered service {Service}", serviceName);
return true; return true;
@ -181,20 +187,23 @@ public class GatewayService : IGatewayService
public async Task<List<GatewayRouteDto>> GetRoutesAsync(bool globalOnly = false) public async Task<List<GatewayRouteDto>> GetRoutesAsync(bool globalOnly = false)
{ {
var query = _dbContext.GwTenantRoutes.Where(r => !r.IsDeleted); var routes = await _routeStore.GetAllAsync();
var instances = await _instanceStore.GetAllAsync();
var query = routes.Where(r => !r.IsDeleted);
if (globalOnly) if (globalOnly)
query = query.Where(r => r.IsGlobal); query = query.Where(r => r.IsGlobal);
var routes = await query.OrderByDescending(r => r.Priority).ToListAsync(); var routeList = query.OrderByDescending(r => r.Priority).ToList();
var clusters = routes.Select(r => r.ClusterId).Distinct().ToList(); var clusters = routeList.Select(r => r.ClusterId).Distinct().ToList();
var instances = await _dbContext.GwServiceInstances var instancesDict = instances
.Where(i => clusters.Contains(i.ClusterId) && !i.IsDeleted) .Where(i => clusters.Contains(i.ClusterId) && !i.IsDeleted)
.GroupBy(i => i.ClusterId) .GroupBy(i => i.ClusterId)
.ToDictionaryAsync(g => g.Key, g => g.Count()); .ToDictionary(g => g.Key, g => g.Count());
return routes.Select(r => new GatewayRouteDto return routeList.Select(r => new GatewayRouteDto
{ {
Id = r.Id, Id = r.Id,
ServiceName = r.ServiceName, ServiceName = r.ServiceName,
@ -203,18 +212,18 @@ public class GatewayService : IGatewayService
Priority = r.Priority, Priority = r.Priority,
IsGlobal = r.IsGlobal, IsGlobal = r.IsGlobal,
TenantCode = r.TenantCode, TenantCode = r.TenantCode,
Status = r.Status, Status = (int)r.Status,
InstanceCount = instances.GetValueOrDefault(r.ClusterId, 0) InstanceCount = instancesDict.GetValueOrDefault(r.ClusterId, 0)
}).ToList(); }).ToList();
} }
public async Task<GatewayRouteDto> CreateRouteAsync(CreateGatewayRouteDto dto) public async Task<GatewayRouteDto> CreateRouteAsync(CreateGatewayRouteDto dto)
{ {
var existing = await _dbContext.GwTenantRoutes var routes = await _routeStore.GetAllAsync();
.FirstOrDefaultAsync(r => var existing = routes.FirstOrDefault(r =>
r.ServiceName == dto.ServiceName && r.ServiceName == dto.ServiceName &&
r.IsGlobal == dto.IsGlobal && r.IsGlobal == dto.IsGlobal &&
(dto.IsGlobal || r.TenantCode == dto.TenantCode)); (dto.IsGlobal || r.TenantCode == dto.TenantCode));
if (existing != null) if (existing != null)
{ {
@ -223,19 +232,18 @@ public class GatewayService : IGatewayService
var route = new GwTenantRoute var route = new GwTenantRoute
{ {
Id = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(), Id = Guid.CreateVersion7().ToString("N"),
TenantCode = dto.IsGlobal ? "" : dto.TenantCode ?? "", TenantCode = dto.IsGlobal ? "" : dto.TenantCode ?? "",
ServiceName = dto.ServiceName, ServiceName = dto.ServiceName,
ClusterId = dto.ClusterId, ClusterId = dto.ClusterId,
PathPattern = dto.PathPattern, PathPattern = dto.PathPattern,
Priority = dto.Priority, Priority = dto.Priority,
Status = 1, Status = (int)RouteStatus.Active,
IsGlobal = dto.IsGlobal, IsGlobal = dto.IsGlobal,
CreatedTime = DateTime.UtcNow CreatedTime = DateTime.UtcNow
}; };
await _dbContext.GwTenantRoutes.AddAsync(route); await _routeStore.CreateAsync(route);
await _dbContext.SaveChangesAsync();
return new GatewayRouteDto return new GatewayRouteDto
{ {
@ -246,58 +254,53 @@ public class GatewayService : IGatewayService
Priority = route.Priority, Priority = route.Priority,
IsGlobal = route.IsGlobal, IsGlobal = route.IsGlobal,
TenantCode = route.TenantCode, TenantCode = route.TenantCode,
Status = route.Status, Status = (int)route.Status,
InstanceCount = 0 InstanceCount = 0
}; };
} }
public async Task<List<GatewayInstanceDto>> GetInstancesAsync(string clusterId) public async Task<List<GatewayInstanceDto>> GetInstancesAsync(string clusterId)
{ {
var instances = await _dbContext.GwServiceInstances var instances = await _instanceStore.GetAllAsync();
var clusterInstances = instances
.Where(i => i.ClusterId == clusterId && !i.IsDeleted) .Where(i => i.ClusterId == clusterId && !i.IsDeleted)
.OrderByDescending(i => i.Weight) .OrderByDescending(i => i.Weight)
.ToListAsync(); .ToList();
return instances.Select(i => new GatewayInstanceDto return clusterInstances.Select(i => new GatewayInstanceDto
{ {
Id = i.Id, Id = i.Id,
ClusterId = i.ClusterId, ClusterId = i.ClusterId,
DestinationId = i.DestinationId, DestinationId = i.DestinationId,
Address = i.Address, Address = i.Address,
Weight = i.Weight, Weight = i.Weight,
Health = i.Health, Health = (int)i.Health,
Status = i.Status, Status = (int)i.Status,
CreatedAt = i.CreatedTime CreatedAt = i.CreatedTime
}).ToList(); }).ToList();
} }
public async Task<GatewayInstanceDto> AddInstanceAsync(CreateGatewayInstanceDto dto) public async Task<GatewayInstanceDto> AddInstanceAsync(CreateGatewayInstanceDto dto)
{ {
var existing = await _dbContext.GwServiceInstances var existing = await _instanceStore.FindByDestinationAsync(dto.ClusterId, dto.DestinationId);
.FirstOrDefaultAsync(i => if (existing != null && !existing.IsDeleted)
i.ClusterId == dto.ClusterId &&
i.DestinationId == dto.DestinationId &&
!i.IsDeleted);
if (existing != null)
{ {
throw new InvalidOperationException($"Instance {dto.DestinationId} already exists in cluster {dto.ClusterId}"); throw new InvalidOperationException($"Instance {dto.DestinationId} already exists in cluster {dto.ClusterId}");
} }
var instance = new GwServiceInstance var instance = new GwServiceInstance
{ {
Id = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(), Id = Guid.CreateVersion7().ToString("N"),
ClusterId = dto.ClusterId, ClusterId = dto.ClusterId,
DestinationId = dto.DestinationId, DestinationId = dto.DestinationId,
Address = dto.Address, Address = dto.Address,
Weight = dto.Weight, Weight = dto.Weight,
Health = 1, Health = (int)InstanceHealth.Healthy,
Status = 1, Status = (int)InstanceStatus.Active,
CreatedTime = DateTime.UtcNow CreatedTime = DateTime.UtcNow
}; };
await _dbContext.GwServiceInstances.AddAsync(instance); await _instanceStore.CreateAsync(instance);
await _dbContext.SaveChangesAsync();
return new GatewayInstanceDto return new GatewayInstanceDto
{ {
@ -306,33 +309,31 @@ public class GatewayService : IGatewayService
DestinationId = instance.DestinationId, DestinationId = instance.DestinationId,
Address = instance.Address, Address = instance.Address,
Weight = instance.Weight, Weight = instance.Weight,
Health = instance.Health, Health = (int)instance.Health,
Status = instance.Status, Status = (int)instance.Status,
CreatedAt = instance.CreatedTime CreatedAt = instance.CreatedTime
}; };
} }
public async Task<bool> RemoveInstanceAsync(long instanceId) public async Task<bool> RemoveInstanceAsync(string instanceId)
{ {
var instance = await _dbContext.GwServiceInstances.FindAsync(instanceId); var instance = await _instanceStore.FindByIdAsync(instanceId);
if (instance == null) return false; if (instance == null) return false;
instance.IsDeleted = true; instance.IsDeleted = true;
instance.UpdatedTime = DateTime.UtcNow; instance.UpdatedTime = DateTime.UtcNow;
await _instanceStore.UpdateAsync(instance);
await _dbContext.SaveChangesAsync();
return true; return true;
} }
public async Task<bool> UpdateInstanceWeightAsync(long instanceId, int weight) public async Task<bool> UpdateInstanceWeightAsync(string instanceId, int weight)
{ {
var instance = await _dbContext.GwServiceInstances.FindAsync(instanceId); var instance = await _instanceStore.FindByIdAsync(instanceId);
if (instance == null) return false; if (instance == null) return false;
instance.Weight = weight; instance.Weight = weight;
instance.UpdatedTime = DateTime.UtcNow; instance.UpdatedTime = DateTime.UtcNow;
await _instanceStore.UpdateAsync(instance);
await _dbContext.SaveChangesAsync();
return true; return true;
} }
@ -357,7 +358,7 @@ public class GatewayService : IGatewayService
InstanceCount = instanceCount, InstanceCount = instanceCount,
IsGlobal = route.IsGlobal, IsGlobal = route.IsGlobal,
TenantCode = route.TenantCode, TenantCode = route.TenantCode,
Status = route.Status, Status = (int)route.Status,
CreatedAt = route.CreatedTime CreatedAt = route.CreatedTime
}; };
} }

View File

@ -7,7 +7,6 @@
}, },
"AllowedHosts": "*", "AllowedHosts": "*",
"ConnectionStrings": { "ConnectionStrings": {
"DefaultConnection": "Host=81.68.223.70;Port=15432;Database=fengling_auth;Username=movingsam;Password=sl52788542", "DefaultConnection": "Host=81.68.223.70;Port=15432;Database=fengling_auth;Username=movingsam;Password=sl52788542"
"GatewayConnection" : "Host=81.68.223.70;Port=15432;Database=fengling_gateway;Username=movingsam;Password=sl52788542"
} }
} }