From ca632a7c097b30cb010c6675a3d06b76248aef0e Mon Sep 17 00:00:00 2001
From: MSuMshk <2039814060@qq.com>
Date: Fri, 26 Dec 2025 17:24:10 +0800
Subject: [PATCH] =?UTF-8?q?refactor:=20=E6=97=A5=E5=BF=97=E5=BA=93?=
=?UTF-8?q?=E6=8B=86=E5=88=86=E4=B8=8E=E6=B8=85=E7=90=86=E7=94=A8=E6=88=B7?=
=?UTF-8?q?=E5=AE=A1=E8=AE=A1?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
deploy/postgres/create_databases.sql | 19 +
deploy/postgres/migrate_logs_to_logs_db.sql | 89 +++++
.../appsettings.Development.json | 9 +
.../appsettings.Production.json | 9 +
.../appsettings.Development.json | 11 +-
.../appsettings.Production.json | 11 +-
.../appsettings.Development.json | 11 +-
.../appsettings.Production.json | 11 +-
.../Constants/DatabaseConstants.cs | 5 +
.../AppServiceCollectionExtensions.cs | 2 +
.../App/Persistence/TakeoutAppDbContext.cs | 66 ----
.../App/Repositories/EfMerchantRepository.cs | 15 +-
.../Repositories/EfSubscriptionRepository.cs | 9 +-
.../App/Repositories/EfTenantRepository.cs | 26 +-
.../Logs/Persistence/TakeoutLogsDbContext.cs | 102 ++++++
.../TakeoutLogsDesignTimeDbContextFactory.cs | 35 ++
...rantAnnouncementPermissionsToSuperAdmin.cs | 11 +-
.../20251226091835_InitLogsDb.Designer.cs | 335 ++++++++++++++++++
.../LogsDb/20251226091835_InitLogsDb.cs | 21 ++
.../TakeoutLogsDbContextModelSnapshot.cs | 332 +++++++++++++++++
.../TakeoutAppDbContextModelSnapshot.cs | 305 ----------------
21 files changed, 1042 insertions(+), 392 deletions(-)
create mode 100644 deploy/postgres/migrate_logs_to_logs_db.sql
create mode 100644 src/Infrastructure/TakeoutSaaS.Infrastructure/Logs/Persistence/TakeoutLogsDbContext.cs
create mode 100644 src/Infrastructure/TakeoutSaaS.Infrastructure/Logs/Persistence/TakeoutLogsDesignTimeDbContextFactory.cs
create mode 100644 src/Infrastructure/TakeoutSaaS.Infrastructure/Migrations/LogsDb/20251226091835_InitLogsDb.Designer.cs
create mode 100644 src/Infrastructure/TakeoutSaaS.Infrastructure/Migrations/LogsDb/20251226091835_InitLogsDb.cs
create mode 100644 src/Infrastructure/TakeoutSaaS.Infrastructure/Migrations/LogsDb/TakeoutLogsDbContextModelSnapshot.cs
diff --git a/deploy/postgres/create_databases.sql b/deploy/postgres/create_databases.sql
index c8732f6..afc0817 100644
--- a/deploy/postgres/create_databases.sql
+++ b/deploy/postgres/create_databases.sql
@@ -15,6 +15,9 @@ BEGIN
IF NOT EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'hangfire_user') THEN
CREATE ROLE hangfire_user LOGIN PASSWORD 'HangFire112233';
END IF;
+ IF NOT EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'logs_user') THEN
+ CREATE ROLE logs_user LOGIN PASSWORD 'Logs112233';
+ END IF;
END $$;
DO $$
@@ -49,6 +52,14 @@ BEGIN
END $$;
COMMENT ON DATABASE takeout_hangfire_db IS 'Takeout SaaS 调度/Hangfire 数据库';
+DO $$
+BEGIN
+ IF NOT EXISTS (SELECT 1 FROM pg_database WHERE datname = 'takeout_logs_db') THEN
+ CREATE DATABASE takeout_logs_db OWNER logs_user ENCODING 'UTF8';
+ END IF;
+END $$;
+COMMENT ON DATABASE takeout_logs_db IS 'Takeout SaaS 审计/日志数据库';
+
-- Ensure privileges and default schema permissions
\connect takeout_app_db
GRANT CONNECT, TEMP ON DATABASE takeout_app_db TO app_user;
@@ -81,3 +92,11 @@ GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO hangfire_
GRANT USAGE, SELECT, UPDATE ON ALL SEQUENCES IN SCHEMA public TO hangfire_user;
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO hangfire_user;
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT USAGE, SELECT, UPDATE ON SEQUENCES TO hangfire_user;
+
+\connect takeout_logs_db
+GRANT CONNECT, TEMP ON DATABASE takeout_logs_db TO logs_user;
+GRANT USAGE ON SCHEMA public TO logs_user;
+GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO logs_user;
+GRANT USAGE, SELECT, UPDATE ON ALL SEQUENCES IN SCHEMA public TO logs_user;
+ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO logs_user;
+ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT USAGE, SELECT, UPDATE ON SEQUENCES TO logs_user;
diff --git a/deploy/postgres/migrate_logs_to_logs_db.sql b/deploy/postgres/migrate_logs_to_logs_db.sql
new file mode 100644
index 0000000..95892c8
--- /dev/null
+++ b/deploy/postgres/migrate_logs_to_logs_db.sql
@@ -0,0 +1,89 @@
+-- 日志库迁移脚本(请在 psql 中按步骤执行)
+
+-- 1. 在日志库创建表结构(takeout_logs_db)
+\connect takeout_logs_db
+
+CREATE TABLE IF NOT EXISTS tenant_audit_logs (
+ "Id" bigint GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
+ "TenantId" bigint NOT NULL,
+ "Action" integer NOT NULL,
+ "Title" character varying(128) NOT NULL,
+ "Description" character varying(1024),
+ "OperatorId" bigint,
+ "OperatorName" character varying(64),
+ "PreviousStatus" integer,
+ "CurrentStatus" integer,
+ "CreatedAt" timestamp with time zone NOT NULL,
+ "UpdatedAt" timestamp with time zone,
+ "DeletedAt" timestamp with time zone,
+ "CreatedBy" bigint,
+ "UpdatedBy" bigint,
+ "DeletedBy" bigint
+);
+CREATE INDEX IF NOT EXISTS "IX_tenant_audit_logs_TenantId" ON tenant_audit_logs ("TenantId");
+
+CREATE TABLE IF NOT EXISTS merchant_audit_logs (
+ "Id" bigint GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
+ "MerchantId" bigint NOT NULL,
+ "Action" integer NOT NULL,
+ "Title" character varying(128) NOT NULL,
+ "Description" character varying(1024),
+ "OperatorId" bigint,
+ "OperatorName" character varying(64),
+ "CreatedAt" timestamp with time zone NOT NULL,
+ "UpdatedAt" timestamp with time zone,
+ "DeletedAt" timestamp with time zone,
+ "CreatedBy" bigint,
+ "UpdatedBy" bigint,
+ "DeletedBy" bigint,
+ "TenantId" bigint NOT NULL
+);
+CREATE INDEX IF NOT EXISTS "IX_merchant_audit_logs_TenantId_MerchantId" ON merchant_audit_logs ("TenantId", "MerchantId");
+
+CREATE TABLE IF NOT EXISTS operation_logs (
+ "Id" bigint GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
+ "OperationType" character varying(64) NOT NULL,
+ "TargetType" character varying(64) NOT NULL,
+ "TargetIds" text,
+ "OperatorId" character varying(64),
+ "OperatorName" character varying(128),
+ "Parameters" text,
+ "Result" text,
+ "Success" boolean NOT NULL,
+ "CreatedAt" timestamp with time zone NOT NULL,
+ "UpdatedAt" timestamp with time zone,
+ "DeletedAt" timestamp with time zone,
+ "CreatedBy" bigint,
+ "UpdatedBy" bigint,
+ "DeletedBy" bigint
+);
+CREATE INDEX IF NOT EXISTS "IX_operation_logs_CreatedAt" ON operation_logs ("CreatedAt");
+CREATE INDEX IF NOT EXISTS "IX_operation_logs_OperationType_CreatedAt" ON operation_logs ("OperationType", "CreatedAt");
+
+CREATE TABLE IF NOT EXISTS member_growth_logs (
+ "Id" bigint GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
+ "MemberId" bigint NOT NULL,
+ "ChangeValue" integer NOT NULL,
+ "CurrentValue" integer NOT NULL,
+ "Notes" character varying(256),
+ "OccurredAt" timestamp with time zone NOT NULL,
+ "CreatedAt" timestamp with time zone NOT NULL,
+ "UpdatedAt" timestamp with time zone,
+ "DeletedAt" timestamp with time zone,
+ "CreatedBy" bigint,
+ "UpdatedBy" bigint,
+ "DeletedBy" bigint,
+ "TenantId" bigint NOT NULL
+);
+CREATE INDEX IF NOT EXISTS "IX_member_growth_logs_TenantId_MemberId_OccurredAt" ON member_growth_logs ("TenantId", "MemberId", "OccurredAt");
+
+-- 2. 迁移数据(建议使用 pg_dump/pg_restore 或应用侧批量拷贝)
+-- 示例:pg_dump -t tenant_audit_logs -t merchant_audit_logs -t operation_logs -t member_growth_logs takeout_app_db > logs_dump.sql
+-- psql -d takeout_logs_db -f logs_dump.sql
+
+-- 3. 在业务库删除旧日志表(takeout_app_db)
+\connect takeout_app_db
+DROP TABLE IF EXISTS tenant_audit_logs;
+DROP TABLE IF EXISTS merchant_audit_logs;
+DROP TABLE IF EXISTS operation_logs;
+DROP TABLE IF EXISTS member_growth_logs;
diff --git a/src/Api/TakeoutSaaS.AdminApi/appsettings.Development.json b/src/Api/TakeoutSaaS.AdminApi/appsettings.Development.json
index 55b3266..882ab41 100644
--- a/src/Api/TakeoutSaaS.AdminApi/appsettings.Development.json
+++ b/src/Api/TakeoutSaaS.AdminApi/appsettings.Development.json
@@ -30,6 +30,15 @@
"CommandTimeoutSeconds": 30,
"MaxRetryCount": 3,
"MaxRetryDelaySeconds": 5
+ },
+ "LogsDatabase": {
+ "Write": "Host=120.53.222.17;Port=5432;Database=takeout_logs_db;Username=logs_user;Password=Logs112233;Pooling=true;Minimum Pool Size=5;Maximum Pool Size=50",
+ "Reads": [
+ "Host=120.53.222.17;Port=5432;Database=takeout_logs_db;Username=logs_user;Password=Logs112233;Pooling=true;Minimum Pool Size=5;Maximum Pool Size=50"
+ ],
+ "CommandTimeoutSeconds": 30,
+ "MaxRetryCount": 3,
+ "MaxRetryDelaySeconds": 5
}
}
},
diff --git a/src/Api/TakeoutSaaS.AdminApi/appsettings.Production.json b/src/Api/TakeoutSaaS.AdminApi/appsettings.Production.json
index 3955d16..725c21f 100644
--- a/src/Api/TakeoutSaaS.AdminApi/appsettings.Production.json
+++ b/src/Api/TakeoutSaaS.AdminApi/appsettings.Production.json
@@ -30,6 +30,15 @@
"CommandTimeoutSeconds": 30,
"MaxRetryCount": 3,
"MaxRetryDelaySeconds": 5
+ },
+ "LogsDatabase": {
+ "Write": "Host=120.53.222.17;Port=5432;Database=takeout_logs_db;Username=logs_user;Password=Logs112233;Pooling=true;Minimum Pool Size=5;Maximum Pool Size=50",
+ "Reads": [
+ "Host=120.53.222.17;Port=5432;Database=takeout_logs_db;Username=logs_user;Password=Logs112233;Pooling=true;Minimum Pool Size=5;Maximum Pool Size=50"
+ ],
+ "CommandTimeoutSeconds": 30,
+ "MaxRetryCount": 3,
+ "MaxRetryDelaySeconds": 5
}
}
},
diff --git a/src/Api/TakeoutSaaS.MiniApi/appsettings.Development.json b/src/Api/TakeoutSaaS.MiniApi/appsettings.Development.json
index 8eb84b7..9f6e1ca 100644
--- a/src/Api/TakeoutSaaS.MiniApi/appsettings.Development.json
+++ b/src/Api/TakeoutSaaS.MiniApi/appsettings.Development.json
@@ -27,6 +27,15 @@
"CommandTimeoutSeconds": 30,
"MaxRetryCount": 3,
"MaxRetryDelaySeconds": 5
+ },
+ "LogsDatabase": {
+ "Write": "Host=120.53.222.17;Port=5432;Database=takeout_logs_db;Username=logs_user;Password=Logs112233;Pooling=true;Minimum Pool Size=5;Maximum Pool Size=50",
+ "Reads": [
+ "Host=120.53.222.17;Port=5432;Database=takeout_logs_db;Username=logs_user;Password=Logs112233;Pooling=true;Minimum Pool Size=5;Maximum Pool Size=50"
+ ],
+ "CommandTimeoutSeconds": 30,
+ "MaxRetryCount": 3,
+ "MaxRetryDelaySeconds": 5
}
}
},
@@ -162,4 +171,4 @@
"Sampling": "ParentBasedAlwaysOn",
"UseConsoleExporter": true
}
-}
\ No newline at end of file
+}
diff --git a/src/Api/TakeoutSaaS.MiniApi/appsettings.Production.json b/src/Api/TakeoutSaaS.MiniApi/appsettings.Production.json
index 8eb84b7..9f6e1ca 100644
--- a/src/Api/TakeoutSaaS.MiniApi/appsettings.Production.json
+++ b/src/Api/TakeoutSaaS.MiniApi/appsettings.Production.json
@@ -27,6 +27,15 @@
"CommandTimeoutSeconds": 30,
"MaxRetryCount": 3,
"MaxRetryDelaySeconds": 5
+ },
+ "LogsDatabase": {
+ "Write": "Host=120.53.222.17;Port=5432;Database=takeout_logs_db;Username=logs_user;Password=Logs112233;Pooling=true;Minimum Pool Size=5;Maximum Pool Size=50",
+ "Reads": [
+ "Host=120.53.222.17;Port=5432;Database=takeout_logs_db;Username=logs_user;Password=Logs112233;Pooling=true;Minimum Pool Size=5;Maximum Pool Size=50"
+ ],
+ "CommandTimeoutSeconds": 30,
+ "MaxRetryCount": 3,
+ "MaxRetryDelaySeconds": 5
}
}
},
@@ -162,4 +171,4 @@
"Sampling": "ParentBasedAlwaysOn",
"UseConsoleExporter": true
}
-}
\ No newline at end of file
+}
diff --git a/src/Api/TakeoutSaaS.UserApi/appsettings.Development.json b/src/Api/TakeoutSaaS.UserApi/appsettings.Development.json
index 585bef6..17378b5 100644
--- a/src/Api/TakeoutSaaS.UserApi/appsettings.Development.json
+++ b/src/Api/TakeoutSaaS.UserApi/appsettings.Development.json
@@ -27,6 +27,15 @@
"CommandTimeoutSeconds": 30,
"MaxRetryCount": 3,
"MaxRetryDelaySeconds": 5
+ },
+ "LogsDatabase": {
+ "Write": "Host=120.53.222.17;Port=5432;Database=takeout_logs_db;Username=logs_user;Password=Logs112233;Pooling=true;Minimum Pool Size=5;Maximum Pool Size=50",
+ "Reads": [
+ "Host=120.53.222.17;Port=5432;Database=takeout_logs_db;Username=logs_user;Password=Logs112233;Pooling=true;Minimum Pool Size=5;Maximum Pool Size=50"
+ ],
+ "CommandTimeoutSeconds": 30,
+ "MaxRetryCount": 3,
+ "MaxRetryDelaySeconds": 5
}
}
},
@@ -65,4 +74,4 @@
"Sampling": "ParentBasedAlwaysOn",
"UseConsoleExporter": true
}
-}
\ No newline at end of file
+}
diff --git a/src/Api/TakeoutSaaS.UserApi/appsettings.Production.json b/src/Api/TakeoutSaaS.UserApi/appsettings.Production.json
index 585bef6..17378b5 100644
--- a/src/Api/TakeoutSaaS.UserApi/appsettings.Production.json
+++ b/src/Api/TakeoutSaaS.UserApi/appsettings.Production.json
@@ -27,6 +27,15 @@
"CommandTimeoutSeconds": 30,
"MaxRetryCount": 3,
"MaxRetryDelaySeconds": 5
+ },
+ "LogsDatabase": {
+ "Write": "Host=120.53.222.17;Port=5432;Database=takeout_logs_db;Username=logs_user;Password=Logs112233;Pooling=true;Minimum Pool Size=5;Maximum Pool Size=50",
+ "Reads": [
+ "Host=120.53.222.17;Port=5432;Database=takeout_logs_db;Username=logs_user;Password=Logs112233;Pooling=true;Minimum Pool Size=5;Maximum Pool Size=50"
+ ],
+ "CommandTimeoutSeconds": 30,
+ "MaxRetryCount": 3,
+ "MaxRetryDelaySeconds": 5
}
}
},
@@ -65,4 +74,4 @@
"Sampling": "ParentBasedAlwaysOn",
"UseConsoleExporter": true
}
-}
\ No newline at end of file
+}
diff --git a/src/Core/TakeoutSaaS.Shared.Abstractions/Constants/DatabaseConstants.cs b/src/Core/TakeoutSaaS.Shared.Abstractions/Constants/DatabaseConstants.cs
index 2f4022e..4e9e458 100644
--- a/src/Core/TakeoutSaaS.Shared.Abstractions/Constants/DatabaseConstants.cs
+++ b/src/Core/TakeoutSaaS.Shared.Abstractions/Constants/DatabaseConstants.cs
@@ -19,4 +19,9 @@ public static class DatabaseConstants
/// 字典库(DictionaryDatabase)。
///
public const string DictionaryDataSource = "DictionaryDatabase";
+
+ ///
+ /// 日志库(LogsDatabase)。
+ ///
+ public const string LogsDataSource = "LogsDatabase";
}
diff --git a/src/Infrastructure/TakeoutSaaS.Infrastructure/App/Extensions/AppServiceCollectionExtensions.cs b/src/Infrastructure/TakeoutSaaS.Infrastructure/App/Extensions/AppServiceCollectionExtensions.cs
index fae5267..86d6d8c 100644
--- a/src/Infrastructure/TakeoutSaaS.Infrastructure/App/Extensions/AppServiceCollectionExtensions.cs
+++ b/src/Infrastructure/TakeoutSaaS.Infrastructure/App/Extensions/AppServiceCollectionExtensions.cs
@@ -11,6 +11,7 @@ using TakeoutSaaS.Domain.Tenants.Repositories;
using TakeoutSaaS.Domain.Tenants.Services;
using TakeoutSaaS.Infrastructure.App.Options;
using TakeoutSaaS.Infrastructure.App.Persistence;
+using TakeoutSaaS.Infrastructure.Logs.Persistence;
using TakeoutSaaS.Infrastructure.App.Persistence.Repositories;
using TakeoutSaaS.Infrastructure.App.Repositories;
using TakeoutSaaS.Infrastructure.App.Services;
@@ -34,6 +35,7 @@ public static class AppServiceCollectionExtensions
{
services.AddDatabaseInfrastructure(configuration);
services.AddPostgresDbContext(DatabaseConstants.AppDataSource);
+ services.AddPostgresDbContext(DatabaseConstants.LogsDataSource);
services.AddScoped();
services.AddScoped();
diff --git a/src/Infrastructure/TakeoutSaaS.Infrastructure/App/Persistence/TakeoutAppDbContext.cs b/src/Infrastructure/TakeoutSaaS.Infrastructure/App/Persistence/TakeoutAppDbContext.cs
index 39b8931..9d21e02 100644
--- a/src/Infrastructure/TakeoutSaaS.Infrastructure/App/Persistence/TakeoutAppDbContext.cs
+++ b/src/Infrastructure/TakeoutSaaS.Infrastructure/App/Persistence/TakeoutAppDbContext.cs
@@ -87,18 +87,10 @@ public sealed class TakeoutAppDbContext(
///
public DbSet TenantVerificationProfiles => Set();
///
- /// 租户审计日志。
- ///
- public DbSet TenantAuditLogs => Set();
- ///
/// 租户审核领取记录。
///
public DbSet TenantReviewClaims => Set();
///
- /// 运营操作日志。
- ///
- public DbSet OperationLogs => Set();
- ///
/// 配额包定义。
///
public DbSet QuotaPackages => Set();
@@ -123,10 +115,6 @@ public sealed class TakeoutAppDbContext(
///
public DbSet MerchantStaff => Set();
///
- /// 商户审计日志。
- ///
- public DbSet MerchantAuditLogs => Set();
- ///
/// 商户分类。
///
public DbSet MerchantCategories => Set();
@@ -307,10 +295,6 @@ public sealed class TakeoutAppDbContext(
///
public DbSet MemberPointLedgers => Set();
///
- /// 成长值日志。
- ///
- public DbSet MemberGrowthLogs => Set();
- ///
/// 会话记录。
///
public DbSet ChatSessions => Set();
@@ -401,15 +385,12 @@ public sealed class TakeoutAppDbContext(
ConfigureTenantAnnouncement(modelBuilder.Entity());
ConfigureTenantAnnouncementRead(modelBuilder.Entity());
ConfigureTenantVerificationProfile(modelBuilder.Entity());
- ConfigureTenantAuditLog(modelBuilder.Entity());
ConfigureTenantReviewClaim(modelBuilder.Entity());
- ConfigureOperationLog(modelBuilder.Entity());
ConfigureQuotaPackage(modelBuilder.Entity());
ConfigureTenantQuotaPackagePurchase(modelBuilder.Entity());
ConfigureMerchantDocument(modelBuilder.Entity());
ConfigureMerchantContract(modelBuilder.Entity());
ConfigureMerchantStaff(modelBuilder.Entity());
- ConfigureMerchantAuditLog(modelBuilder.Entity());
ConfigureMerchantCategory(modelBuilder.Entity());
ConfigureStoreBusinessHour(modelBuilder.Entity());
ConfigureStoreHoliday(modelBuilder.Entity());
@@ -454,7 +435,6 @@ public sealed class TakeoutAppDbContext(
ConfigureMemberProfile(modelBuilder.Entity());
ConfigureMemberTier(modelBuilder.Entity());
ConfigureMemberPointLedger(modelBuilder.Entity());
- ConfigureMemberGrowthLog(modelBuilder.Entity());
ConfigureChatSession(modelBuilder.Entity());
ConfigureChatMessage(modelBuilder.Entity());
ConfigureSupportTicket(modelBuilder.Entity());
@@ -512,17 +492,6 @@ public sealed class TakeoutAppDbContext(
builder.HasIndex(x => x.TenantId).IsUnique();
}
- private static void ConfigureTenantAuditLog(EntityTypeBuilder builder)
- {
- builder.ToTable("tenant_audit_logs");
- builder.HasKey(x => x.Id);
- builder.Property(x => x.TenantId).IsRequired();
- builder.Property(x => x.Title).HasMaxLength(128).IsRequired();
- builder.Property(x => x.Description).HasMaxLength(1024);
- builder.Property(x => x.OperatorName).HasMaxLength(64);
- builder.HasIndex(x => x.TenantId);
- }
-
private static void ConfigureTenantReviewClaim(EntityTypeBuilder builder)
{
builder.ToTable("tenant_review_claims");
@@ -537,21 +506,6 @@ public sealed class TakeoutAppDbContext(
builder.HasIndex(x => x.TenantId).IsUnique().HasFilter("\"ReleasedAt\" IS NULL AND \"DeletedAt\" IS NULL");
}
- private static void ConfigureOperationLog(EntityTypeBuilder builder)
- {
- builder.ToTable("operation_logs");
- builder.HasKey(x => x.Id);
- builder.Property(x => x.OperationType).HasMaxLength(64).IsRequired();
- builder.Property(x => x.TargetType).HasMaxLength(64).IsRequired();
- builder.Property(x => x.TargetIds).HasColumnType("text");
- builder.Property(x => x.OperatorId).HasMaxLength(64);
- builder.Property(x => x.OperatorName).HasMaxLength(128);
- builder.Property(x => x.Parameters).HasColumnType("text");
- builder.Property(x => x.Result).HasColumnType("text");
- builder.Property(x => x.Success).IsRequired();
- builder.HasIndex(x => new { x.OperationType, x.CreatedAt });
- builder.HasIndex(x => x.CreatedAt);
- }
private static void ConfigureTenantSubscriptionHistory(EntityTypeBuilder builder)
{
@@ -885,17 +839,6 @@ public sealed class TakeoutAppDbContext(
builder.HasIndex(x => new { x.TenantId, x.MerchantId, x.Phone });
}
- private static void ConfigureMerchantAuditLog(EntityTypeBuilder builder)
- {
- builder.ToTable("merchant_audit_logs");
- builder.HasKey(x => x.Id);
- builder.Property(x => x.MerchantId).IsRequired();
- builder.Property(x => x.Title).HasMaxLength(128).IsRequired();
- builder.Property(x => x.Description).HasMaxLength(1024);
- builder.Property(x => x.OperatorName).HasMaxLength(64);
- builder.HasIndex(x => new { x.TenantId, x.MerchantId });
- }
-
private static void ConfigureMerchantCategory(EntityTypeBuilder builder)
{
builder.ToTable("merchant_categories");
@@ -1297,15 +1240,6 @@ public sealed class TakeoutAppDbContext(
builder.HasIndex(x => new { x.TenantId, x.MemberId, x.OccurredAt });
}
- private static void ConfigureMemberGrowthLog(EntityTypeBuilder builder)
- {
- builder.ToTable("member_growth_logs");
- builder.HasKey(x => x.Id);
- builder.Property(x => x.MemberId).IsRequired();
- builder.Property(x => x.Notes).HasMaxLength(256);
- builder.HasIndex(x => new { x.TenantId, x.MemberId, x.OccurredAt });
- }
-
private static void ConfigureChatSession(EntityTypeBuilder builder)
{
builder.ToTable("chat_sessions");
diff --git a/src/Infrastructure/TakeoutSaaS.Infrastructure/App/Repositories/EfMerchantRepository.cs b/src/Infrastructure/TakeoutSaaS.Infrastructure/App/Repositories/EfMerchantRepository.cs
index 34eeb92..db41cdd 100644
--- a/src/Infrastructure/TakeoutSaaS.Infrastructure/App/Repositories/EfMerchantRepository.cs
+++ b/src/Infrastructure/TakeoutSaaS.Infrastructure/App/Repositories/EfMerchantRepository.cs
@@ -3,6 +3,7 @@ using TakeoutSaaS.Domain.Merchants.Entities;
using TakeoutSaaS.Domain.Merchants.Enums;
using TakeoutSaaS.Domain.Merchants.Repositories;
using TakeoutSaaS.Infrastructure.App.Persistence;
+using TakeoutSaaS.Infrastructure.Logs.Persistence;
namespace TakeoutSaaS.Infrastructure.App.Repositories;
@@ -12,7 +13,7 @@ namespace TakeoutSaaS.Infrastructure.App.Repositories;
///
/// 初始化仓储。
///
-public sealed class EfMerchantRepository(TakeoutAppDbContext context) : IMerchantRepository
+public sealed class EfMerchantRepository(TakeoutAppDbContext context, TakeoutLogsDbContext logsContext) : IMerchantRepository
{
///
public Task FindByIdAsync(long merchantId, long tenantId, CancellationToken cancellationToken = default)
@@ -151,9 +152,13 @@ public sealed class EfMerchantRepository(TakeoutAppDbContext context) : IMerchan
}
///
- public Task SaveChangesAsync(CancellationToken cancellationToken = default)
+ public async Task SaveChangesAsync(CancellationToken cancellationToken = default)
{
- return context.SaveChangesAsync(cancellationToken);
+ // 1. 保存业务库变更
+ await context.SaveChangesAsync(cancellationToken);
+
+ // 2. (空行后) 保存日志库变更
+ await logsContext.SaveChangesAsync(cancellationToken);
}
///
@@ -196,13 +201,13 @@ public sealed class EfMerchantRepository(TakeoutAppDbContext context) : IMerchan
///
public Task AddAuditLogAsync(MerchantAuditLog log, CancellationToken cancellationToken = default)
{
- return context.MerchantAuditLogs.AddAsync(log, cancellationToken).AsTask();
+ return logsContext.MerchantAuditLogs.AddAsync(log, cancellationToken).AsTask();
}
///
public async Task> GetAuditLogsAsync(long merchantId, long tenantId, CancellationToken cancellationToken = default)
{
- return await context.MerchantAuditLogs
+ return await logsContext.MerchantAuditLogs
.AsNoTracking()
.Where(x => x.TenantId == tenantId && x.MerchantId == merchantId)
.OrderByDescending(x => x.CreatedAt)
diff --git a/src/Infrastructure/TakeoutSaaS.Infrastructure/App/Repositories/EfSubscriptionRepository.cs b/src/Infrastructure/TakeoutSaaS.Infrastructure/App/Repositories/EfSubscriptionRepository.cs
index 0b59a3b..9a1802b 100644
--- a/src/Infrastructure/TakeoutSaaS.Infrastructure/App/Repositories/EfSubscriptionRepository.cs
+++ b/src/Infrastructure/TakeoutSaaS.Infrastructure/App/Repositories/EfSubscriptionRepository.cs
@@ -3,13 +3,14 @@ using TakeoutSaaS.Domain.Tenants.Entities;
using TakeoutSaaS.Domain.Tenants.Enums;
using TakeoutSaaS.Domain.Tenants.Repositories;
using TakeoutSaaS.Infrastructure.App.Persistence;
+using TakeoutSaaS.Infrastructure.Logs.Persistence;
namespace TakeoutSaaS.Infrastructure.App.Repositories;
///
/// 订阅管理仓储实现。
///
-public sealed class EfSubscriptionRepository(TakeoutAppDbContext dbContext) : ISubscriptionRepository
+public sealed class EfSubscriptionRepository(TakeoutAppDbContext dbContext, TakeoutLogsDbContext logsContext) : ISubscriptionRepository
{
#region 订阅查询
@@ -393,7 +394,7 @@ public sealed class EfSubscriptionRepository(TakeoutAppDbContext dbContext) : IS
///
public Task AddOperationLogAsync(OperationLog log, CancellationToken cancellationToken = default)
{
- dbContext.Set().Add(log);
+ logsContext.OperationLogs.Add(log);
return Task.CompletedTask;
}
@@ -402,6 +403,10 @@ public sealed class EfSubscriptionRepository(TakeoutAppDbContext dbContext) : IS
///
public async Task SaveChangesAsync(CancellationToken cancellationToken = default)
{
+ // 1. 保存业务库变更
await dbContext.SaveChangesAsync(cancellationToken);
+
+ // 2. (空行后) 保存日志库变更
+ await logsContext.SaveChangesAsync(cancellationToken);
}
}
diff --git a/src/Infrastructure/TakeoutSaaS.Infrastructure/App/Repositories/EfTenantRepository.cs b/src/Infrastructure/TakeoutSaaS.Infrastructure/App/Repositories/EfTenantRepository.cs
index ce1f485..ecfa185 100644
--- a/src/Infrastructure/TakeoutSaaS.Infrastructure/App/Repositories/EfTenantRepository.cs
+++ b/src/Infrastructure/TakeoutSaaS.Infrastructure/App/Repositories/EfTenantRepository.cs
@@ -4,13 +4,14 @@ using TakeoutSaaS.Domain.Tenants.Entities;
using TakeoutSaaS.Domain.Tenants.Enums;
using TakeoutSaaS.Domain.Tenants.Repositories;
using TakeoutSaaS.Infrastructure.App.Persistence;
+using TakeoutSaaS.Infrastructure.Logs.Persistence;
namespace TakeoutSaaS.Infrastructure.App.Repositories;
///
/// 租户聚合的 EF Core 仓储实现。
///
-public sealed class EfTenantRepository(TakeoutAppDbContext context) : ITenantRepository
+public sealed class EfTenantRepository(TakeoutAppDbContext context, TakeoutLogsDbContext logsContext) : ITenantRepository
{
///
public Task FindByIdAsync(long tenantId, CancellationToken cancellationToken = default)
@@ -277,16 +278,21 @@ public sealed class EfTenantRepository(TakeoutAppDbContext context) : ITenantRep
{
try
{
+ // 1. 写入领取记录
await context.TenantReviewClaims.AddAsync(claim, cancellationToken);
- await context.TenantAuditLogs.AddAsync(auditLog, cancellationToken);
-
await context.SaveChangesAsync(cancellationToken);
+
+ // 2. (空行后) 写入审计日志
+ await logsContext.TenantAuditLogs.AddAsync(auditLog, cancellationToken);
+ await logsContext.SaveChangesAsync(cancellationToken);
return true;
}
catch (DbUpdateException ex) when (ex.InnerException is PostgresException pg && pg.SqlState == PostgresErrorCodes.UniqueViolation)
{
+ // 1. 释放实体跟踪避免重复写入
context.Entry(claim).State = EntityState.Detached;
- context.Entry(auditLog).State = EntityState.Detached;
+
+ // 2. (空行后) 返回抢占失败
return false;
}
}
@@ -372,13 +378,13 @@ public sealed class EfTenantRepository(TakeoutAppDbContext context) : ITenantRep
///
public Task AddAuditLogAsync(TenantAuditLog log, CancellationToken cancellationToken = default)
{
- return context.TenantAuditLogs.AddAsync(log, cancellationToken).AsTask();
+ return logsContext.TenantAuditLogs.AddAsync(log, cancellationToken).AsTask();
}
///
public async Task> GetAuditLogsAsync(long tenantId, CancellationToken cancellationToken = default)
{
- return await context.TenantAuditLogs
+ return await logsContext.TenantAuditLogs
.IgnoreQueryFilters()
.AsNoTracking()
.Where(x => x.DeletedAt == null && x.TenantId == tenantId)
@@ -387,8 +393,12 @@ public sealed class EfTenantRepository(TakeoutAppDbContext context) : ITenantRep
}
///
- public Task SaveChangesAsync(CancellationToken cancellationToken = default)
+ public async Task SaveChangesAsync(CancellationToken cancellationToken = default)
{
- return context.SaveChangesAsync(cancellationToken);
+ // 1. 保存业务库变更
+ await context.SaveChangesAsync(cancellationToken);
+
+ // 2. (空行后) 保存日志库变更
+ await logsContext.SaveChangesAsync(cancellationToken);
}
}
diff --git a/src/Infrastructure/TakeoutSaaS.Infrastructure/Logs/Persistence/TakeoutLogsDbContext.cs b/src/Infrastructure/TakeoutSaaS.Infrastructure/Logs/Persistence/TakeoutLogsDbContext.cs
new file mode 100644
index 0000000..1743a1e
--- /dev/null
+++ b/src/Infrastructure/TakeoutSaaS.Infrastructure/Logs/Persistence/TakeoutLogsDbContext.cs
@@ -0,0 +1,102 @@
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Metadata.Builders;
+using TakeoutSaaS.Domain.Membership.Entities;
+using TakeoutSaaS.Domain.Merchants.Entities;
+using TakeoutSaaS.Domain.Tenants.Entities;
+using TakeoutSaaS.Infrastructure.Common.Persistence;
+using TakeoutSaaS.Shared.Abstractions.Ids;
+using TakeoutSaaS.Shared.Abstractions.Security;
+using TakeoutSaaS.Shared.Abstractions.Tenancy;
+
+namespace TakeoutSaaS.Infrastructure.Logs.Persistence;
+
+///
+/// 日志库 DbContext。
+///
+public sealed class TakeoutLogsDbContext(
+ DbContextOptions options,
+ ITenantProvider tenantProvider,
+ ICurrentUserAccessor? currentUserAccessor = null,
+ IIdGenerator? idGenerator = null)
+ : TenantAwareDbContext(options, tenantProvider, currentUserAccessor, idGenerator)
+{
+ ///
+ /// 租户审计日志集合。
+ ///
+ public DbSet TenantAuditLogs => Set();
+
+ ///
+ /// 商户审计日志集合。
+ ///
+ public DbSet MerchantAuditLogs => Set();
+
+ ///
+ /// 运营操作日志集合。
+ ///
+ public DbSet OperationLogs => Set();
+
+ ///
+ /// 成长值日志集合。
+ ///
+ public DbSet MemberGrowthLogs => Set();
+
+ ///
+ /// 配置实体模型。
+ ///
+ /// 模型构建器。
+ protected override void OnModelCreating(ModelBuilder modelBuilder)
+ {
+ base.OnModelCreating(modelBuilder);
+ ConfigureTenantAuditLog(modelBuilder.Entity());
+ ConfigureMerchantAuditLog(modelBuilder.Entity());
+ ConfigureOperationLog(modelBuilder.Entity());
+ ConfigureMemberGrowthLog(modelBuilder.Entity());
+ }
+
+ private static void ConfigureTenantAuditLog(EntityTypeBuilder builder)
+ {
+ builder.ToTable("tenant_audit_logs");
+ builder.HasKey(x => x.Id);
+ builder.Property(x => x.TenantId).IsRequired();
+ builder.Property(x => x.Title).HasMaxLength(128).IsRequired();
+ builder.Property(x => x.Description).HasMaxLength(1024);
+ builder.Property(x => x.OperatorName).HasMaxLength(64);
+ builder.HasIndex(x => x.TenantId);
+ }
+
+ private static void ConfigureMerchantAuditLog(EntityTypeBuilder builder)
+ {
+ builder.ToTable("merchant_audit_logs");
+ builder.HasKey(x => x.Id);
+ builder.Property(x => x.MerchantId).IsRequired();
+ builder.Property(x => x.Title).HasMaxLength(128).IsRequired();
+ builder.Property(x => x.Description).HasMaxLength(1024);
+ builder.Property(x => x.OperatorName).HasMaxLength(64);
+ builder.HasIndex(x => new { x.TenantId, x.MerchantId });
+ }
+
+ private static void ConfigureOperationLog(EntityTypeBuilder builder)
+ {
+ builder.ToTable("operation_logs");
+ builder.HasKey(x => x.Id);
+ builder.Property(x => x.OperationType).HasMaxLength(64).IsRequired();
+ builder.Property(x => x.TargetType).HasMaxLength(64).IsRequired();
+ builder.Property(x => x.TargetIds).HasColumnType("text");
+ builder.Property(x => x.OperatorId).HasMaxLength(64);
+ builder.Property(x => x.OperatorName).HasMaxLength(128);
+ builder.Property(x => x.Parameters).HasColumnType("text");
+ builder.Property(x => x.Result).HasColumnType("text");
+ builder.Property(x => x.Success).IsRequired();
+ builder.HasIndex(x => new { x.OperationType, x.CreatedAt });
+ builder.HasIndex(x => x.CreatedAt);
+ }
+
+ private static void ConfigureMemberGrowthLog(EntityTypeBuilder builder)
+ {
+ builder.ToTable("member_growth_logs");
+ builder.HasKey(x => x.Id);
+ builder.Property(x => x.MemberId).IsRequired();
+ builder.Property(x => x.Notes).HasMaxLength(256);
+ builder.HasIndex(x => new { x.TenantId, x.MemberId, x.OccurredAt });
+ }
+}
diff --git a/src/Infrastructure/TakeoutSaaS.Infrastructure/Logs/Persistence/TakeoutLogsDesignTimeDbContextFactory.cs b/src/Infrastructure/TakeoutSaaS.Infrastructure/Logs/Persistence/TakeoutLogsDesignTimeDbContextFactory.cs
new file mode 100644
index 0000000..5184dcf
--- /dev/null
+++ b/src/Infrastructure/TakeoutSaaS.Infrastructure/Logs/Persistence/TakeoutLogsDesignTimeDbContextFactory.cs
@@ -0,0 +1,35 @@
+using Microsoft.EntityFrameworkCore;
+using TakeoutSaaS.Infrastructure.Common.Persistence.DesignTime;
+using TakeoutSaaS.Shared.Abstractions.Constants;
+using TakeoutSaaS.Shared.Abstractions.Security;
+using TakeoutSaaS.Shared.Abstractions.Tenancy;
+
+namespace TakeoutSaaS.Infrastructure.Logs.Persistence;
+
+///
+/// 日志库设计时工厂,供 EF CLI 使用。
+///
+internal sealed class TakeoutLogsDesignTimeDbContextFactory
+ : DesignTimeDbContextFactoryBase
+{
+ ///
+ /// 初始化日志库设计时上下文工厂。
+ ///
+ public TakeoutLogsDesignTimeDbContextFactory()
+ : base(DatabaseConstants.LogsDataSource, "TAKEOUTSAAS_LOGS_CONNECTION")
+ {
+ }
+
+ ///
+ /// 创建日志库 DbContext。
+ ///
+ /// 上下文选项。
+ /// 租户提供器。
+ /// 当前用户访问器。
+ /// 日志库上下文实例。
+ protected override TakeoutLogsDbContext CreateContext(
+ DbContextOptions options,
+ ITenantProvider tenantProvider,
+ ICurrentUserAccessor currentUserAccessor)
+ => new(options, tenantProvider, currentUserAccessor);
+}
diff --git a/src/Infrastructure/TakeoutSaaS.Infrastructure/Migrations/IdentityDb/20251220183000_GrantAnnouncementPermissionsToSuperAdmin.cs b/src/Infrastructure/TakeoutSaaS.Infrastructure/Migrations/IdentityDb/20251220183000_GrantAnnouncementPermissionsToSuperAdmin.cs
index a056adf..b01cb6e 100644
--- a/src/Infrastructure/TakeoutSaaS.Infrastructure/Migrations/IdentityDb/20251220183000_GrantAnnouncementPermissionsToSuperAdmin.cs
+++ b/src/Infrastructure/TakeoutSaaS.Infrastructure/Migrations/IdentityDb/20251220183000_GrantAnnouncementPermissionsToSuperAdmin.cs
@@ -52,8 +52,15 @@ SELECT
NULL,
NULL
FROM target_permissions tp
-ON CONFLICT (""TenantId"", ""Code"") DO NOTHING;
-
+ON CONFLICT (""TenantId"", ""Code"") DO NOTHING;"
+ );
+ migrationBuilder.Sql(
+ @"WITH target_roles AS (
+ SELECT ""Id"" AS role_id, ""TenantId"" AS tenant_id
+ FROM ""roles""
+ WHERE ""Code"" IN ('super-admin', 'SUPER_ADMIN', 'PlatformAdmin', 'platform-admin')
+ AND ""DeletedAt"" IS NULL
+)
INSERT INTO ""role_permissions"" (
""TenantId"",
""RoleId"",
diff --git a/src/Infrastructure/TakeoutSaaS.Infrastructure/Migrations/LogsDb/20251226091835_InitLogsDb.Designer.cs b/src/Infrastructure/TakeoutSaaS.Infrastructure/Migrations/LogsDb/20251226091835_InitLogsDb.Designer.cs
new file mode 100644
index 0000000..3adc7b7
--- /dev/null
+++ b/src/Infrastructure/TakeoutSaaS.Infrastructure/Migrations/LogsDb/20251226091835_InitLogsDb.Designer.cs
@@ -0,0 +1,335 @@
+//
+using System;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
+using TakeoutSaaS.Infrastructure.Logs.Persistence;
+
+#nullable disable
+
+namespace TakeoutSaaS.Infrastructure.Migrations.LogsDb
+{
+ [DbContext(typeof(TakeoutLogsDbContext))]
+ [Migration("20251226091835_InitLogsDb")]
+ partial class InitLogsDb
+ {
+ ///
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("ProductVersion", "10.0.0")
+ .HasAnnotation("Relational:MaxIdentifierLength", 63);
+
+ NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
+
+ modelBuilder.Entity("TakeoutSaaS.Domain.Membership.Entities.MemberGrowthLog", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint")
+ .HasComment("实体唯一标识。");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("ChangeValue")
+ .HasColumnType("integer")
+ .HasComment("变动数量。");
+
+ b.Property("CreatedAt")
+ .HasColumnType("timestamp with time zone")
+ .HasComment("创建时间(UTC)。");
+
+ b.Property("CreatedBy")
+ .HasColumnType("bigint")
+ .HasComment("创建人用户标识,匿名或系统操作时为 null。");
+
+ b.Property("CurrentValue")
+ .HasColumnType("integer")
+ .HasComment("当前成长值。");
+
+ b.Property("DeletedAt")
+ .HasColumnType("timestamp with time zone")
+ .HasComment("软删除时间(UTC),未删除时为 null。");
+
+ b.Property("DeletedBy")
+ .HasColumnType("bigint")
+ .HasComment("删除人用户标识(软删除),未删除时为 null。");
+
+ b.Property("MemberId")
+ .HasColumnType("bigint")
+ .HasComment("会员标识。");
+
+ b.Property("Notes")
+ .HasMaxLength(256)
+ .HasColumnType("character varying(256)")
+ .HasComment("备注。");
+
+ b.Property("OccurredAt")
+ .HasColumnType("timestamp with time zone")
+ .HasComment("发生时间。");
+
+ b.Property("TenantId")
+ .HasColumnType("bigint")
+ .HasComment("所属租户 ID。");
+
+ b.Property("UpdatedAt")
+ .HasColumnType("timestamp with time zone")
+ .HasComment("最近一次更新时间(UTC),从未更新时为 null。");
+
+ b.Property("UpdatedBy")
+ .HasColumnType("bigint")
+ .HasComment("最后更新人用户标识,匿名或系统操作时为 null。");
+
+ b.HasKey("Id");
+
+ b.HasIndex("TenantId", "MemberId", "OccurredAt");
+
+ b.ToTable("member_growth_logs", null, t =>
+ {
+ t.HasComment("成长值变动日志。");
+ });
+ });
+
+ modelBuilder.Entity("TakeoutSaaS.Domain.Merchants.Entities.MerchantAuditLog", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint")
+ .HasComment("实体唯一标识。");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("Action")
+ .HasColumnType("integer")
+ .HasComment("动作类型。");
+
+ b.Property("CreatedAt")
+ .HasColumnType("timestamp with time zone")
+ .HasComment("创建时间(UTC)。");
+
+ b.Property("CreatedBy")
+ .HasColumnType("bigint")
+ .HasComment("创建人用户标识,匿名或系统操作时为 null。");
+
+ b.Property("DeletedAt")
+ .HasColumnType("timestamp with time zone")
+ .HasComment("软删除时间(UTC),未删除时为 null。");
+
+ b.Property("DeletedBy")
+ .HasColumnType("bigint")
+ .HasComment("删除人用户标识(软删除),未删除时为 null。");
+
+ b.Property("Description")
+ .HasMaxLength(1024)
+ .HasColumnType("character varying(1024)")
+ .HasComment("详情描述。");
+
+ b.Property("MerchantId")
+ .HasColumnType("bigint")
+ .HasComment("商户标识。");
+
+ b.Property("OperatorId")
+ .HasColumnType("bigint")
+ .HasComment("操作人 ID。");
+
+ b.Property("OperatorName")
+ .HasMaxLength(64)
+ .HasColumnType("character varying(64)")
+ .HasComment("操作人名称。");
+
+ b.Property("TenantId")
+ .HasColumnType("bigint")
+ .HasComment("所属租户 ID。");
+
+ b.Property("Title")
+ .IsRequired()
+ .HasMaxLength(128)
+ .HasColumnType("character varying(128)")
+ .HasComment("标题。");
+
+ b.Property("UpdatedAt")
+ .HasColumnType("timestamp with time zone")
+ .HasComment("最近一次更新时间(UTC),从未更新时为 null。");
+
+ b.Property("UpdatedBy")
+ .HasColumnType("bigint")
+ .HasComment("最后更新人用户标识,匿名或系统操作时为 null。");
+
+ b.HasKey("Id");
+
+ b.HasIndex("TenantId", "MerchantId");
+
+ b.ToTable("merchant_audit_logs", null, t =>
+ {
+ t.HasComment("商户入驻审核日志。");
+ });
+ });
+
+ modelBuilder.Entity("TakeoutSaaS.Domain.Tenants.Entities.OperationLog", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint")
+ .HasComment("实体唯一标识。");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("CreatedAt")
+ .HasColumnType("timestamp with time zone")
+ .HasComment("创建时间(UTC)。");
+
+ b.Property("CreatedBy")
+ .HasColumnType("bigint")
+ .HasComment("创建人用户标识,匿名或系统操作时为 null。");
+
+ b.Property("DeletedAt")
+ .HasColumnType("timestamp with time zone")
+ .HasComment("软删除时间(UTC),未删除时为 null。");
+
+ b.Property("DeletedBy")
+ .HasColumnType("bigint")
+ .HasComment("删除人用户标识(软删除),未删除时为 null。");
+
+ b.Property("OperationType")
+ .IsRequired()
+ .HasMaxLength(64)
+ .HasColumnType("character varying(64)")
+ .HasComment("操作类型:BatchExtend, BatchRemind, StatusChange 等。");
+
+ b.Property("OperatorId")
+ .HasMaxLength(64)
+ .HasColumnType("character varying(64)")
+ .HasComment("操作人ID。");
+
+ b.Property("OperatorName")
+ .HasMaxLength(128)
+ .HasColumnType("character varying(128)")
+ .HasComment("操作人名称。");
+
+ b.Property("Parameters")
+ .HasColumnType("text")
+ .HasComment("操作参数(JSON)。");
+
+ b.Property("Result")
+ .HasColumnType("text")
+ .HasComment("操作结果(JSON)。");
+
+ b.Property("Success")
+ .HasColumnType("boolean")
+ .HasComment("是否成功。");
+
+ b.Property("TargetIds")
+ .HasColumnType("text")
+ .HasComment("目标ID列表(JSON)。");
+
+ b.Property("TargetType")
+ .IsRequired()
+ .HasMaxLength(64)
+ .HasColumnType("character varying(64)")
+ .HasComment("目标类型:Subscription, Bill 等。");
+
+ b.Property("UpdatedAt")
+ .HasColumnType("timestamp with time zone")
+ .HasComment("最近一次更新时间(UTC),从未更新时为 null。");
+
+ b.Property("UpdatedBy")
+ .HasColumnType("bigint")
+ .HasComment("最后更新人用户标识,匿名或系统操作时为 null。");
+
+ b.HasKey("Id");
+
+ b.HasIndex("CreatedAt");
+
+ b.HasIndex("OperationType", "CreatedAt");
+
+ b.ToTable("operation_logs", null, t =>
+ {
+ t.HasComment("运营操作日志。");
+ });
+ });
+
+ modelBuilder.Entity("TakeoutSaaS.Domain.Tenants.Entities.TenantAuditLog", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint")
+ .HasComment("实体唯一标识。");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("Action")
+ .HasColumnType("integer")
+ .HasComment("操作类型。");
+
+ b.Property("CreatedAt")
+ .HasColumnType("timestamp with time zone")
+ .HasComment("创建时间(UTC)。");
+
+ b.Property("CreatedBy")
+ .HasColumnType("bigint")
+ .HasComment("创建人用户标识,匿名或系统操作时为 null。");
+
+ b.Property("CurrentStatus")
+ .HasColumnType("integer")
+ .HasComment("新状态。");
+
+ b.Property("DeletedAt")
+ .HasColumnType("timestamp with time zone")
+ .HasComment("软删除时间(UTC),未删除时为 null。");
+
+ b.Property("DeletedBy")
+ .HasColumnType("bigint")
+ .HasComment("删除人用户标识(软删除),未删除时为 null。");
+
+ b.Property("Description")
+ .HasMaxLength(1024)
+ .HasColumnType("character varying(1024)")
+ .HasComment("详细描述。");
+
+ b.Property("OperatorId")
+ .HasColumnType("bigint")
+ .HasComment("操作人 ID。");
+
+ b.Property("OperatorName")
+ .HasMaxLength(64)
+ .HasColumnType("character varying(64)")
+ .HasComment("操作人名称。");
+
+ b.Property("PreviousStatus")
+ .HasColumnType("integer")
+ .HasComment("原状态。");
+
+ b.Property("TenantId")
+ .HasColumnType("bigint")
+ .HasComment("关联的租户标识。");
+
+ b.Property("Title")
+ .IsRequired()
+ .HasMaxLength(128)
+ .HasColumnType("character varying(128)")
+ .HasComment("日志标题。");
+
+ b.Property("UpdatedAt")
+ .HasColumnType("timestamp with time zone")
+ .HasComment("最近一次更新时间(UTC),从未更新时为 null。");
+
+ b.Property("UpdatedBy")
+ .HasColumnType("bigint")
+ .HasComment("最后更新人用户标识,匿名或系统操作时为 null。");
+
+ b.HasKey("Id");
+
+ b.HasIndex("TenantId");
+
+ b.ToTable("tenant_audit_logs", null, t =>
+ {
+ t.HasComment("租户运营审核日志。");
+ });
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
diff --git a/src/Infrastructure/TakeoutSaaS.Infrastructure/Migrations/LogsDb/20251226091835_InitLogsDb.cs b/src/Infrastructure/TakeoutSaaS.Infrastructure/Migrations/LogsDb/20251226091835_InitLogsDb.cs
new file mode 100644
index 0000000..fd7090a
--- /dev/null
+++ b/src/Infrastructure/TakeoutSaaS.Infrastructure/Migrations/LogsDb/20251226091835_InitLogsDb.cs
@@ -0,0 +1,21 @@
+using Microsoft.EntityFrameworkCore.Migrations;
+
+#nullable disable
+
+namespace TakeoutSaaS.Infrastructure.Migrations.LogsDb
+{
+ ///
+ public partial class InitLogsDb : Migration
+ {
+ ///
+ protected override void Up(MigrationBuilder migrationBuilder)
+ {
+ }
+
+ ///
+ protected override void Down(MigrationBuilder migrationBuilder)
+ {
+ }
+ }
+}
+
diff --git a/src/Infrastructure/TakeoutSaaS.Infrastructure/Migrations/LogsDb/TakeoutLogsDbContextModelSnapshot.cs b/src/Infrastructure/TakeoutSaaS.Infrastructure/Migrations/LogsDb/TakeoutLogsDbContextModelSnapshot.cs
new file mode 100644
index 0000000..d35a5c9
--- /dev/null
+++ b/src/Infrastructure/TakeoutSaaS.Infrastructure/Migrations/LogsDb/TakeoutLogsDbContextModelSnapshot.cs
@@ -0,0 +1,332 @@
+//
+using System;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
+using TakeoutSaaS.Infrastructure.Logs.Persistence;
+
+#nullable disable
+
+namespace TakeoutSaaS.Infrastructure.Migrations.LogsDb
+{
+ [DbContext(typeof(TakeoutLogsDbContext))]
+ partial class TakeoutLogsDbContextModelSnapshot : ModelSnapshot
+ {
+ protected override void BuildModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("ProductVersion", "10.0.0")
+ .HasAnnotation("Relational:MaxIdentifierLength", 63);
+
+ NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
+
+ modelBuilder.Entity("TakeoutSaaS.Domain.Membership.Entities.MemberGrowthLog", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint")
+ .HasComment("实体唯一标识。");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("ChangeValue")
+ .HasColumnType("integer")
+ .HasComment("变动数量。");
+
+ b.Property("CreatedAt")
+ .HasColumnType("timestamp with time zone")
+ .HasComment("创建时间(UTC)。");
+
+ b.Property("CreatedBy")
+ .HasColumnType("bigint")
+ .HasComment("创建人用户标识,匿名或系统操作时为 null。");
+
+ b.Property("CurrentValue")
+ .HasColumnType("integer")
+ .HasComment("当前成长值。");
+
+ b.Property("DeletedAt")
+ .HasColumnType("timestamp with time zone")
+ .HasComment("软删除时间(UTC),未删除时为 null。");
+
+ b.Property("DeletedBy")
+ .HasColumnType("bigint")
+ .HasComment("删除人用户标识(软删除),未删除时为 null。");
+
+ b.Property("MemberId")
+ .HasColumnType("bigint")
+ .HasComment("会员标识。");
+
+ b.Property("Notes")
+ .HasMaxLength(256)
+ .HasColumnType("character varying(256)")
+ .HasComment("备注。");
+
+ b.Property("OccurredAt")
+ .HasColumnType("timestamp with time zone")
+ .HasComment("发生时间。");
+
+ b.Property("TenantId")
+ .HasColumnType("bigint")
+ .HasComment("所属租户 ID。");
+
+ b.Property("UpdatedAt")
+ .HasColumnType("timestamp with time zone")
+ .HasComment("最近一次更新时间(UTC),从未更新时为 null。");
+
+ b.Property("UpdatedBy")
+ .HasColumnType("bigint")
+ .HasComment("最后更新人用户标识,匿名或系统操作时为 null。");
+
+ b.HasKey("Id");
+
+ b.HasIndex("TenantId", "MemberId", "OccurredAt");
+
+ b.ToTable("member_growth_logs", null, t =>
+ {
+ t.HasComment("成长值变动日志。");
+ });
+ });
+
+ modelBuilder.Entity("TakeoutSaaS.Domain.Merchants.Entities.MerchantAuditLog", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint")
+ .HasComment("实体唯一标识。");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("Action")
+ .HasColumnType("integer")
+ .HasComment("动作类型。");
+
+ b.Property("CreatedAt")
+ .HasColumnType("timestamp with time zone")
+ .HasComment("创建时间(UTC)。");
+
+ b.Property("CreatedBy")
+ .HasColumnType("bigint")
+ .HasComment("创建人用户标识,匿名或系统操作时为 null。");
+
+ b.Property("DeletedAt")
+ .HasColumnType("timestamp with time zone")
+ .HasComment("软删除时间(UTC),未删除时为 null。");
+
+ b.Property("DeletedBy")
+ .HasColumnType("bigint")
+ .HasComment("删除人用户标识(软删除),未删除时为 null。");
+
+ b.Property("Description")
+ .HasMaxLength(1024)
+ .HasColumnType("character varying(1024)")
+ .HasComment("详情描述。");
+
+ b.Property("MerchantId")
+ .HasColumnType("bigint")
+ .HasComment("商户标识。");
+
+ b.Property("OperatorId")
+ .HasColumnType("bigint")
+ .HasComment("操作人 ID。");
+
+ b.Property("OperatorName")
+ .HasMaxLength(64)
+ .HasColumnType("character varying(64)")
+ .HasComment("操作人名称。");
+
+ b.Property("TenantId")
+ .HasColumnType("bigint")
+ .HasComment("所属租户 ID。");
+
+ b.Property("Title")
+ .IsRequired()
+ .HasMaxLength(128)
+ .HasColumnType("character varying(128)")
+ .HasComment("标题。");
+
+ b.Property("UpdatedAt")
+ .HasColumnType("timestamp with time zone")
+ .HasComment("最近一次更新时间(UTC),从未更新时为 null。");
+
+ b.Property("UpdatedBy")
+ .HasColumnType("bigint")
+ .HasComment("最后更新人用户标识,匿名或系统操作时为 null。");
+
+ b.HasKey("Id");
+
+ b.HasIndex("TenantId", "MerchantId");
+
+ b.ToTable("merchant_audit_logs", null, t =>
+ {
+ t.HasComment("商户入驻审核日志。");
+ });
+ });
+
+ modelBuilder.Entity("TakeoutSaaS.Domain.Tenants.Entities.OperationLog", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint")
+ .HasComment("实体唯一标识。");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("CreatedAt")
+ .HasColumnType("timestamp with time zone")
+ .HasComment("创建时间(UTC)。");
+
+ b.Property("CreatedBy")
+ .HasColumnType("bigint")
+ .HasComment("创建人用户标识,匿名或系统操作时为 null。");
+
+ b.Property("DeletedAt")
+ .HasColumnType("timestamp with time zone")
+ .HasComment("软删除时间(UTC),未删除时为 null。");
+
+ b.Property("DeletedBy")
+ .HasColumnType("bigint")
+ .HasComment("删除人用户标识(软删除),未删除时为 null。");
+
+ b.Property("OperationType")
+ .IsRequired()
+ .HasMaxLength(64)
+ .HasColumnType("character varying(64)")
+ .HasComment("操作类型:BatchExtend, BatchRemind, StatusChange 等。");
+
+ b.Property("OperatorId")
+ .HasMaxLength(64)
+ .HasColumnType("character varying(64)")
+ .HasComment("操作人ID。");
+
+ b.Property("OperatorName")
+ .HasMaxLength(128)
+ .HasColumnType("character varying(128)")
+ .HasComment("操作人名称。");
+
+ b.Property("Parameters")
+ .HasColumnType("text")
+ .HasComment("操作参数(JSON)。");
+
+ b.Property("Result")
+ .HasColumnType("text")
+ .HasComment("操作结果(JSON)。");
+
+ b.Property("Success")
+ .HasColumnType("boolean")
+ .HasComment("是否成功。");
+
+ b.Property("TargetIds")
+ .HasColumnType("text")
+ .HasComment("目标ID列表(JSON)。");
+
+ b.Property("TargetType")
+ .IsRequired()
+ .HasMaxLength(64)
+ .HasColumnType("character varying(64)")
+ .HasComment("目标类型:Subscription, Bill 等。");
+
+ b.Property("UpdatedAt")
+ .HasColumnType("timestamp with time zone")
+ .HasComment("最近一次更新时间(UTC),从未更新时为 null。");
+
+ b.Property("UpdatedBy")
+ .HasColumnType("bigint")
+ .HasComment("最后更新人用户标识,匿名或系统操作时为 null。");
+
+ b.HasKey("Id");
+
+ b.HasIndex("CreatedAt");
+
+ b.HasIndex("OperationType", "CreatedAt");
+
+ b.ToTable("operation_logs", null, t =>
+ {
+ t.HasComment("运营操作日志。");
+ });
+ });
+
+ modelBuilder.Entity("TakeoutSaaS.Domain.Tenants.Entities.TenantAuditLog", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint")
+ .HasComment("实体唯一标识。");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("Action")
+ .HasColumnType("integer")
+ .HasComment("操作类型。");
+
+ b.Property("CreatedAt")
+ .HasColumnType("timestamp with time zone")
+ .HasComment("创建时间(UTC)。");
+
+ b.Property("CreatedBy")
+ .HasColumnType("bigint")
+ .HasComment("创建人用户标识,匿名或系统操作时为 null。");
+
+ b.Property("CurrentStatus")
+ .HasColumnType("integer")
+ .HasComment("新状态。");
+
+ b.Property("DeletedAt")
+ .HasColumnType("timestamp with time zone")
+ .HasComment("软删除时间(UTC),未删除时为 null。");
+
+ b.Property("DeletedBy")
+ .HasColumnType("bigint")
+ .HasComment("删除人用户标识(软删除),未删除时为 null。");
+
+ b.Property("Description")
+ .HasMaxLength(1024)
+ .HasColumnType("character varying(1024)")
+ .HasComment("详细描述。");
+
+ b.Property("OperatorId")
+ .HasColumnType("bigint")
+ .HasComment("操作人 ID。");
+
+ b.Property("OperatorName")
+ .HasMaxLength(64)
+ .HasColumnType("character varying(64)")
+ .HasComment("操作人名称。");
+
+ b.Property("PreviousStatus")
+ .HasColumnType("integer")
+ .HasComment("原状态。");
+
+ b.Property("TenantId")
+ .HasColumnType("bigint")
+ .HasComment("关联的租户标识。");
+
+ b.Property("Title")
+ .IsRequired()
+ .HasMaxLength(128)
+ .HasColumnType("character varying(128)")
+ .HasComment("日志标题。");
+
+ b.Property("UpdatedAt")
+ .HasColumnType("timestamp with time zone")
+ .HasComment("最近一次更新时间(UTC),从未更新时为 null。");
+
+ b.Property("UpdatedBy")
+ .HasColumnType("bigint")
+ .HasComment("最后更新人用户标识,匿名或系统操作时为 null。");
+
+ b.HasKey("Id");
+
+ b.HasIndex("TenantId");
+
+ b.ToTable("tenant_audit_logs", null, t =>
+ {
+ t.HasComment("租户运营审核日志。");
+ });
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
diff --git a/src/Infrastructure/TakeoutSaaS.Infrastructure/Migrations/TakeoutAppDbContextModelSnapshot.cs b/src/Infrastructure/TakeoutSaaS.Infrastructure/Migrations/TakeoutAppDbContextModelSnapshot.cs
index 4dfee4f..3d77367 100644
--- a/src/Infrastructure/TakeoutSaaS.Infrastructure/Migrations/TakeoutAppDbContextModelSnapshot.cs
+++ b/src/Infrastructure/TakeoutSaaS.Infrastructure/Migrations/TakeoutAppDbContextModelSnapshot.cs
@@ -2125,74 +2125,6 @@ namespace TakeoutSaaS.Infrastructure.Migrations
});
});
- modelBuilder.Entity("TakeoutSaaS.Domain.Membership.Entities.MemberGrowthLog", b =>
- {
- b.Property("Id")
- .ValueGeneratedOnAdd()
- .HasColumnType("bigint")
- .HasComment("实体唯一标识。");
-
- NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
-
- b.Property("ChangeValue")
- .HasColumnType("integer")
- .HasComment("变动数量。");
-
- b.Property("CreatedAt")
- .HasColumnType("timestamp with time zone")
- .HasComment("创建时间(UTC)。");
-
- b.Property("CreatedBy")
- .HasColumnType("bigint")
- .HasComment("创建人用户标识,匿名或系统操作时为 null。");
-
- b.Property("CurrentValue")
- .HasColumnType("integer")
- .HasComment("当前成长值。");
-
- b.Property("DeletedAt")
- .HasColumnType("timestamp with time zone")
- .HasComment("软删除时间(UTC),未删除时为 null。");
-
- b.Property("DeletedBy")
- .HasColumnType("bigint")
- .HasComment("删除人用户标识(软删除),未删除时为 null。");
-
- b.Property("MemberId")
- .HasColumnType("bigint")
- .HasComment("会员标识。");
-
- b.Property("Notes")
- .HasMaxLength(256)
- .HasColumnType("character varying(256)")
- .HasComment("备注。");
-
- b.Property("OccurredAt")
- .HasColumnType("timestamp with time zone")
- .HasComment("发生时间。");
-
- b.Property("TenantId")
- .HasColumnType("bigint")
- .HasComment("所属租户 ID。");
-
- b.Property("UpdatedAt")
- .HasColumnType("timestamp with time zone")
- .HasComment("最近一次更新时间(UTC),从未更新时为 null。");
-
- b.Property("UpdatedBy")
- .HasColumnType("bigint")
- .HasComment("最后更新人用户标识,匿名或系统操作时为 null。");
-
- b.HasKey("Id");
-
- b.HasIndex("TenantId", "MemberId", "OccurredAt");
-
- b.ToTable("member_growth_logs", null, t =>
- {
- t.HasComment("成长值变动日志。");
- });
- });
-
modelBuilder.Entity("TakeoutSaaS.Domain.Membership.Entities.MemberPointLedger", b =>
{
b.Property("Id")
@@ -2575,81 +2507,6 @@ namespace TakeoutSaaS.Infrastructure.Migrations
});
});
- modelBuilder.Entity("TakeoutSaaS.Domain.Merchants.Entities.MerchantAuditLog", b =>
- {
- b.Property("Id")
- .ValueGeneratedOnAdd()
- .HasColumnType("bigint")
- .HasComment("实体唯一标识。");
-
- NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
-
- b.Property("Action")
- .HasColumnType("integer")
- .HasComment("动作类型。");
-
- b.Property("CreatedAt")
- .HasColumnType("timestamp with time zone")
- .HasComment("创建时间(UTC)。");
-
- b.Property("CreatedBy")
- .HasColumnType("bigint")
- .HasComment("创建人用户标识,匿名或系统操作时为 null。");
-
- b.Property("DeletedAt")
- .HasColumnType("timestamp with time zone")
- .HasComment("软删除时间(UTC),未删除时为 null。");
-
- b.Property("DeletedBy")
- .HasColumnType("bigint")
- .HasComment("删除人用户标识(软删除),未删除时为 null。");
-
- b.Property("Description")
- .HasMaxLength(1024)
- .HasColumnType("character varying(1024)")
- .HasComment("详情描述。");
-
- b.Property("MerchantId")
- .HasColumnType("bigint")
- .HasComment("商户标识。");
-
- b.Property("OperatorId")
- .HasColumnType("bigint")
- .HasComment("操作人 ID。");
-
- b.Property("OperatorName")
- .HasMaxLength(64)
- .HasColumnType("character varying(64)")
- .HasComment("操作人名称。");
-
- b.Property("TenantId")
- .HasColumnType("bigint")
- .HasComment("所属租户 ID。");
-
- b.Property("Title")
- .IsRequired()
- .HasMaxLength(128)
- .HasColumnType("character varying(128)")
- .HasComment("标题。");
-
- b.Property("UpdatedAt")
- .HasColumnType("timestamp with time zone")
- .HasComment("最近一次更新时间(UTC),从未更新时为 null。");
-
- b.Property("UpdatedBy")
- .HasColumnType("bigint")
- .HasComment("最后更新人用户标识,匿名或系统操作时为 null。");
-
- b.HasKey("Id");
-
- b.HasIndex("TenantId", "MerchantId");
-
- b.ToTable("merchant_audit_logs", null, t =>
- {
- t.HasComment("商户入驻审核日志。");
- });
- });
-
modelBuilder.Entity("TakeoutSaaS.Domain.Merchants.Entities.MerchantCategory", b =>
{
b.Property("Id")
@@ -5680,89 +5537,6 @@ namespace TakeoutSaaS.Infrastructure.Migrations
});
});
- modelBuilder.Entity("TakeoutSaaS.Domain.Tenants.Entities.OperationLog", b =>
- {
- b.Property("Id")
- .ValueGeneratedOnAdd()
- .HasColumnType("bigint")
- .HasComment("实体唯一标识。");
-
- NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
-
- b.Property("CreatedAt")
- .HasColumnType("timestamp with time zone")
- .HasComment("创建时间(UTC)。");
-
- b.Property("CreatedBy")
- .HasColumnType("bigint")
- .HasComment("创建人用户标识,匿名或系统操作时为 null。");
-
- b.Property("DeletedAt")
- .HasColumnType("timestamp with time zone")
- .HasComment("软删除时间(UTC),未删除时为 null。");
-
- b.Property("DeletedBy")
- .HasColumnType("bigint")
- .HasComment("删除人用户标识(软删除),未删除时为 null。");
-
- b.Property("OperationType")
- .IsRequired()
- .HasMaxLength(64)
- .HasColumnType("character varying(64)")
- .HasComment("操作类型:BatchExtend, BatchRemind, StatusChange 等。");
-
- b.Property("OperatorId")
- .HasMaxLength(64)
- .HasColumnType("character varying(64)")
- .HasComment("操作人ID。");
-
- b.Property("OperatorName")
- .HasMaxLength(128)
- .HasColumnType("character varying(128)")
- .HasComment("操作人名称。");
-
- b.Property("Parameters")
- .HasColumnType("text")
- .HasComment("操作参数(JSON)。");
-
- b.Property("Result")
- .HasColumnType("text")
- .HasComment("操作结果(JSON)。");
-
- b.Property("Success")
- .HasColumnType("boolean")
- .HasComment("是否成功。");
-
- b.Property("TargetIds")
- .HasColumnType("text")
- .HasComment("目标ID列表(JSON)。");
-
- b.Property("TargetType")
- .IsRequired()
- .HasMaxLength(64)
- .HasColumnType("character varying(64)")
- .HasComment("目标类型:Subscription, Bill 等。");
-
- b.Property("UpdatedAt")
- .HasColumnType("timestamp with time zone")
- .HasComment("最近一次更新时间(UTC),从未更新时为 null。");
-
- b.Property("UpdatedBy")
- .HasColumnType("bigint")
- .HasComment("最后更新人用户标识,匿名或系统操作时为 null。");
-
- b.HasKey("Id");
-
- b.HasIndex("CreatedAt");
-
- b.HasIndex("OperationType", "CreatedAt");
-
- b.ToTable("operation_logs", null, t =>
- {
- t.HasComment("运营操作日志。");
- });
- });
-
modelBuilder.Entity("TakeoutSaaS.Domain.Tenants.Entities.QuotaPackage", b =>
{
b.Property("Id")
@@ -6176,85 +5950,6 @@ namespace TakeoutSaaS.Infrastructure.Migrations
});
});
- modelBuilder.Entity("TakeoutSaaS.Domain.Tenants.Entities.TenantAuditLog", b =>
- {
- b.Property("Id")
- .ValueGeneratedOnAdd()
- .HasColumnType("bigint")
- .HasComment("实体唯一标识。");
-
- NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
-
- b.Property("Action")
- .HasColumnType("integer")
- .HasComment("操作类型。");
-
- b.Property("CreatedAt")
- .HasColumnType("timestamp with time zone")
- .HasComment("创建时间(UTC)。");
-
- b.Property