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>
<ItemGroup>
<!-- 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.Identity.EntityFrameworkCore" Version="10.0.3" />
<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.DistributedLocks.Redis" Version="3.2.1" />
<!-- Database -->
<PackageVersion Include="Microsoft.EntityFrameworkCore.Design" Version="10.0.0" />
<PackageVersion Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="10.0.0" />
<!-- OpenIddict (version must match Fengling.Platform) -->
<PackageVersion Include="OpenIddict.Abstractions" Version="7.2.0" />

View File

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

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="Microsoft.AspNetCore.Authentication.JwtBearer" />
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" />
<PackageReference Include="Microsoft.OpenApi" />
<PackageReference Include="NetCorePal.Extensions.AspNetCore" />
<PackageReference Include="NetCorePal.Extensions.DistributedLocks.Redis" />
@ -33,5 +34,4 @@
<PackageReference Include="Swashbuckle.AspNetCore" />
</ItemGroup>
</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 long Id { get; set; }
public string Id { get; set; } = "";
public string ServicePrefix { get; set; } = "";
public string ServiceName { get; set; } = "";
public string Version { get; set; } = "v1";
@ -32,7 +32,7 @@ public class CreateGatewayServiceDto
public class GatewayRouteDto
{
public long Id { get; set; }
public string Id { get; set; } = "";
public string ServiceName { get; set; } = "";
public string ClusterId { get; set; } = "";
public string PathPattern { get; set; } = "";
@ -55,7 +55,7 @@ public class CreateGatewayRouteDto
public class GatewayInstanceDto
{
public long Id { get; set; }
public string Id { get; set; } = "";
public string ClusterId { get; set; } = "";
public string DestinationId { get; set; } = "";
public string Address { get; set; } = "";

View File

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

View File

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

View File

@ -7,7 +7,6 @@
},
"AllowedHosts": "*",
"ConnectionStrings": {
"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"
"DefaultConnection": "Host=81.68.223.70;Port=15432;Database=fengling_auth;Username=movingsam;Password=sl52788542"
}
}