forked from xiongyuxing/tiku-backend.net
feat(security): add distributed authorization foundation
This commit is contained in:
@@ -27,6 +27,56 @@ internal sealed class PlatformSaasPlanConfiguration : IEntityTypeConfiguration<P
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class ProductModuleConfiguration : IEntityTypeConfiguration<ProductModule>
|
||||
{
|
||||
public void Configure(EntityTypeBuilder<ProductModule> builder)
|
||||
{
|
||||
builder.ConfigureEntity("product_modules");
|
||||
builder.ConfigureTimestamps();
|
||||
builder.Property(entity => entity.Code).HasMaxLength(100);
|
||||
builder.Property(entity => entity.Name).HasMaxLength(200);
|
||||
builder.Property(entity => entity.Description).HasMaxLength(1000);
|
||||
builder.Property(entity => entity.Status).HasSnakeCaseEnum();
|
||||
builder.HasIndex(entity => entity.Code).IsUnique();
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class PlanModuleEntitlementConfiguration : IEntityTypeConfiguration<PlanModuleEntitlement>
|
||||
{
|
||||
public void Configure(EntityTypeBuilder<PlanModuleEntitlement> builder)
|
||||
{
|
||||
builder.ConfigureEntity("plan_module_entitlements");
|
||||
builder.Property(entity => entity.PlanCode).HasMaxLength(100);
|
||||
builder.Property(entity => entity.ModuleCode).HasMaxLength(100);
|
||||
builder.HasIndex(entity => new { entity.PlanCode, entity.ModuleCode }).IsUnique();
|
||||
builder.HasOne<PlatformSaasPlan>().WithMany()
|
||||
.HasPrincipalKey(entity => entity.Code)
|
||||
.HasForeignKey(entity => entity.PlanCode)
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
builder.HasOne<ProductModule>().WithMany()
|
||||
.HasPrincipalKey(entity => entity.Code)
|
||||
.HasForeignKey(entity => entity.ModuleCode)
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class TenantModuleOverrideConfiguration : IEntityTypeConfiguration<TenantModuleOverride>
|
||||
{
|
||||
public void Configure(EntityTypeBuilder<TenantModuleOverride> builder)
|
||||
{
|
||||
builder.ConfigureTenantEntity("tenant_module_overrides");
|
||||
builder.ConfigureTimestamps();
|
||||
builder.Property(entity => entity.ModuleCode).HasMaxLength(100);
|
||||
builder.Property(entity => entity.Mode).HasSnakeCaseEnum();
|
||||
builder.Property(entity => entity.Reason).HasMaxLength(1000);
|
||||
builder.HasIndex(entity => new { entity.TenantId, entity.ModuleCode }).IsUnique();
|
||||
builder.HasOne<ProductModule>().WithMany()
|
||||
.HasPrincipalKey(entity => entity.Code)
|
||||
.HasForeignKey(entity => entity.ModuleCode)
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class TenantBillingProfileConfiguration : IEntityTypeConfiguration<TenantBillingProfile>
|
||||
{
|
||||
public void Configure(EntityTypeBuilder<TenantBillingProfile> builder)
|
||||
|
||||
@@ -115,6 +115,20 @@ internal sealed class TenantSettingsConfiguration : IEntityTypeConfiguration<Ten
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class TenantAuthPolicyConfiguration : IEntityTypeConfiguration<TenantAuthPolicy>
|
||||
{
|
||||
public void Configure(EntityTypeBuilder<TenantAuthPolicy> builder)
|
||||
{
|
||||
builder.ToTable("tenant_auth_policies");
|
||||
builder.HasKey(entity => entity.TenantId);
|
||||
builder.ConfigureTimestamps();
|
||||
builder.Property(entity => entity.AllowExternalStudentSelfRegistration).HasDefaultValue(false);
|
||||
builder.HasOne<Tenant>().WithOne()
|
||||
.HasForeignKey<TenantAuthPolicy>(entity => entity.TenantId)
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class TenantFrontendConfigConfiguration : IEntityTypeConfiguration<TenantFrontendConfig>
|
||||
{
|
||||
public void Configure(EntityTypeBuilder<TenantFrontendConfig> builder)
|
||||
|
||||
18569
Tiku.Infrastructure/Persistence/Migrations/20260729012205_AddDistributedSecurityFoundation.Designer.cs
generated
Normal file
18569
Tiku.Infrastructure/Persistence/Migrations/20260729012205_AddDistributedSecurityFoundation.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,297 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Tiku.Infrastructure.Persistence.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class AddDistributedSecurityFoundation : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AddUniqueConstraint(
|
||||
name: "ak_platform_saas_plans_code",
|
||||
table: "platform_saas_plans",
|
||||
column: "code");
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "inbox_state",
|
||||
columns: table => new
|
||||
{
|
||||
id = table.Column<long>(type: "bigint", nullable: false)
|
||||
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||
message_id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||
consumer_id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||
lock_id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||
row_version = table.Column<byte[]>(type: "bytea", rowVersion: true, nullable: true),
|
||||
received = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
|
||||
receive_count = table.Column<int>(type: "integer", nullable: false),
|
||||
expiration_time = table.Column<DateTime>(type: "timestamp with time zone", nullable: true),
|
||||
consumed = table.Column<DateTime>(type: "timestamp with time zone", nullable: true),
|
||||
delivered = table.Column<DateTime>(type: "timestamp with time zone", nullable: true),
|
||||
last_sequence_number = table.Column<long>(type: "bigint", nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("pk_inbox_state", x => x.id);
|
||||
table.UniqueConstraint("ak_inbox_state_message_id_consumer_id", x => new { x.message_id, x.consumer_id });
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "outbox_state",
|
||||
columns: table => new
|
||||
{
|
||||
outbox_id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||
lock_id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||
row_version = table.Column<byte[]>(type: "bytea", rowVersion: true, nullable: true),
|
||||
created = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
|
||||
delivered = table.Column<DateTime>(type: "timestamp with time zone", nullable: true),
|
||||
last_sequence_number = table.Column<long>(type: "bigint", nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("pk_outbox_state", x => x.outbox_id);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "product_modules",
|
||||
columns: table => new
|
||||
{
|
||||
id = table.Column<Guid>(type: "uuid", nullable: false, defaultValueSql: "gen_random_uuid()"),
|
||||
code = table.Column<string>(type: "character varying(100)", maxLength: 100, nullable: false),
|
||||
name = table.Column<string>(type: "character varying(200)", maxLength: 200, nullable: false),
|
||||
description = table.Column<string>(type: "character varying(1000)", maxLength: 1000, nullable: true),
|
||||
status = table.Column<string>(type: "character varying(32)", maxLength: 32, nullable: false),
|
||||
sort_order = table.Column<int>(type: "integer", nullable: false),
|
||||
created_at = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false, defaultValueSql: "now()"),
|
||||
updated_at = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false, defaultValueSql: "now()")
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("pk_product_modules", x => x.id);
|
||||
table.UniqueConstraint("ak_product_modules_code", x => x.code);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "tenant_auth_policies",
|
||||
columns: table => new
|
||||
{
|
||||
tenant_id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||
allow_external_student_self_registration = table.Column<bool>(type: "boolean", nullable: false, defaultValue: false),
|
||||
created_at = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false, defaultValueSql: "now()"),
|
||||
updated_at = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false, defaultValueSql: "now()")
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("pk_tenant_auth_policies", x => x.tenant_id);
|
||||
table.ForeignKey(
|
||||
name: "fk_tenant_auth_policies_tenants_tenant_id",
|
||||
column: x => x.tenant_id,
|
||||
principalTable: "tenants",
|
||||
principalColumn: "id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
// Existing tenants retain the historical external-login behavior. New tenants
|
||||
// receive an explicit fail-closed policy when created by PlatformAdminService.
|
||||
migrationBuilder.Sql("""
|
||||
INSERT INTO tenant_auth_policies
|
||||
(tenant_id, allow_external_student_self_registration, created_at, updated_at)
|
||||
SELECT id, TRUE, now(), now()
|
||||
FROM tenants
|
||||
ON CONFLICT (tenant_id) DO NOTHING;
|
||||
""");
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "outbox_message",
|
||||
columns: table => new
|
||||
{
|
||||
sequence_number = table.Column<long>(type: "bigint", nullable: false)
|
||||
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||
enqueue_time = table.Column<DateTime>(type: "timestamp with time zone", nullable: true),
|
||||
sent_time = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
|
||||
headers = table.Column<string>(type: "text", nullable: true),
|
||||
properties = table.Column<string>(type: "text", nullable: true),
|
||||
inbox_message_id = table.Column<Guid>(type: "uuid", nullable: true),
|
||||
inbox_consumer_id = table.Column<Guid>(type: "uuid", nullable: true),
|
||||
outbox_id = table.Column<Guid>(type: "uuid", nullable: true),
|
||||
message_id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||
content_type = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: false),
|
||||
message_type = table.Column<string>(type: "text", nullable: false),
|
||||
body = table.Column<string>(type: "text", nullable: false),
|
||||
conversation_id = table.Column<Guid>(type: "uuid", nullable: true),
|
||||
correlation_id = table.Column<Guid>(type: "uuid", nullable: true),
|
||||
initiator_id = table.Column<Guid>(type: "uuid", nullable: true),
|
||||
request_id = table.Column<Guid>(type: "uuid", nullable: true),
|
||||
source_address = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true),
|
||||
destination_address = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true),
|
||||
response_address = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true),
|
||||
fault_address = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true),
|
||||
expiration_time = table.Column<DateTime>(type: "timestamp with time zone", nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("pk_outbox_message", x => x.sequence_number);
|
||||
table.ForeignKey(
|
||||
name: "fk_outbox_message_inbox_state_inbox_message_id_inbox_consumer_~",
|
||||
columns: x => new { x.inbox_message_id, x.inbox_consumer_id },
|
||||
principalTable: "inbox_state",
|
||||
principalColumns: new[] { "message_id", "consumer_id" });
|
||||
table.ForeignKey(
|
||||
name: "fk_outbox_message_outbox_state_outbox_id",
|
||||
column: x => x.outbox_id,
|
||||
principalTable: "outbox_state",
|
||||
principalColumn: "outbox_id");
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "plan_module_entitlements",
|
||||
columns: table => new
|
||||
{
|
||||
id = table.Column<Guid>(type: "uuid", nullable: false, defaultValueSql: "gen_random_uuid()"),
|
||||
plan_code = table.Column<string>(type: "character varying(100)", maxLength: 100, nullable: false),
|
||||
module_code = table.Column<string>(type: "character varying(100)", maxLength: 100, nullable: false),
|
||||
enabled = table.Column<bool>(type: "boolean", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("pk_plan_module_entitlements", x => x.id);
|
||||
table.ForeignKey(
|
||||
name: "fk_plan_module_entitlements_platform_saas_plans_plan_code",
|
||||
column: x => x.plan_code,
|
||||
principalTable: "platform_saas_plans",
|
||||
principalColumn: "code",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
table.ForeignKey(
|
||||
name: "fk_plan_module_entitlements_product_modules_module_code",
|
||||
column: x => x.module_code,
|
||||
principalTable: "product_modules",
|
||||
principalColumn: "code",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "tenant_module_overrides",
|
||||
columns: table => new
|
||||
{
|
||||
id = table.Column<Guid>(type: "uuid", nullable: false, defaultValueSql: "gen_random_uuid()"),
|
||||
module_code = table.Column<string>(type: "character varying(100)", maxLength: 100, nullable: false),
|
||||
mode = table.Column<string>(type: "character varying(32)", maxLength: 32, nullable: false),
|
||||
expires_at = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: true),
|
||||
reason = table.Column<string>(type: "character varying(1000)", maxLength: 1000, nullable: true),
|
||||
tenant_id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||
created_at = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false, defaultValueSql: "now()"),
|
||||
updated_at = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false, defaultValueSql: "now()")
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("pk_tenant_module_overrides", x => x.id);
|
||||
table.UniqueConstraint("ak_tenant_module_overrides_tenant_id_id", x => new { x.tenant_id, x.id });
|
||||
table.ForeignKey(
|
||||
name: "fk_tenant_module_overrides_product_modules_module_code",
|
||||
column: x => x.module_code,
|
||||
principalTable: "product_modules",
|
||||
principalColumn: "code",
|
||||
onDelete: ReferentialAction.Restrict);
|
||||
table.ForeignKey(
|
||||
name: "fk_tenant_module_overrides_tenants_tenant_id",
|
||||
column: x => x.tenant_id,
|
||||
principalTable: "tenants",
|
||||
principalColumn: "id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "ix_inbox_state_delivered",
|
||||
table: "inbox_state",
|
||||
column: "delivered");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "ix_outbox_message_enqueue_time",
|
||||
table: "outbox_message",
|
||||
column: "enqueue_time");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "ix_outbox_message_expiration_time",
|
||||
table: "outbox_message",
|
||||
column: "expiration_time");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "ix_outbox_message_inbox_message_id_inbox_consumer_id_sequence_~",
|
||||
table: "outbox_message",
|
||||
columns: new[] { "inbox_message_id", "inbox_consumer_id", "sequence_number" },
|
||||
unique: true);
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "ix_outbox_message_outbox_id_sequence_number",
|
||||
table: "outbox_message",
|
||||
columns: new[] { "outbox_id", "sequence_number" },
|
||||
unique: true);
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "ix_outbox_state_created",
|
||||
table: "outbox_state",
|
||||
column: "created");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "ix_plan_module_entitlements_module_code",
|
||||
table: "plan_module_entitlements",
|
||||
column: "module_code");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "ix_plan_module_entitlements_plan_code_module_code",
|
||||
table: "plan_module_entitlements",
|
||||
columns: new[] { "plan_code", "module_code" },
|
||||
unique: true);
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "ix_product_modules_code",
|
||||
table: "product_modules",
|
||||
column: "code",
|
||||
unique: true);
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "ix_tenant_module_overrides_module_code",
|
||||
table: "tenant_module_overrides",
|
||||
column: "module_code");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "ix_tenant_module_overrides_tenant_id_module_code",
|
||||
table: "tenant_module_overrides",
|
||||
columns: new[] { "tenant_id", "module_code" },
|
||||
unique: true);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "outbox_message");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "plan_module_entitlements");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "tenant_auth_policies");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "tenant_module_overrides");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "inbox_state");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "outbox_state");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "product_modules");
|
||||
|
||||
migrationBuilder.DropUniqueConstraint(
|
||||
name: "ak_platform_saas_plans_code",
|
||||
table: "platform_saas_plans");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -25,6 +25,224 @@ namespace Tiku.Infrastructure.Persistence.Migrations
|
||||
NpgsqlModelBuilderExtensions.HasPostgresExtension(modelBuilder, "ltree");
|
||||
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
||||
|
||||
modelBuilder.Entity("MassTransit.EntityFrameworkCoreIntegration.InboxState", b =>
|
||||
{
|
||||
b.Property<long>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("bigint")
|
||||
.HasColumnName("id");
|
||||
|
||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
|
||||
|
||||
b.Property<DateTime?>("Consumed")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("consumed");
|
||||
|
||||
b.Property<Guid>("ConsumerId")
|
||||
.HasColumnType("uuid")
|
||||
.HasColumnName("consumer_id");
|
||||
|
||||
b.Property<DateTime?>("Delivered")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("delivered");
|
||||
|
||||
b.Property<DateTime?>("ExpirationTime")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("expiration_time");
|
||||
|
||||
b.Property<long?>("LastSequenceNumber")
|
||||
.HasColumnType("bigint")
|
||||
.HasColumnName("last_sequence_number");
|
||||
|
||||
b.Property<Guid>("LockId")
|
||||
.HasColumnType("uuid")
|
||||
.HasColumnName("lock_id");
|
||||
|
||||
b.Property<Guid>("MessageId")
|
||||
.HasColumnType("uuid")
|
||||
.HasColumnName("message_id");
|
||||
|
||||
b.Property<int>("ReceiveCount")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("receive_count");
|
||||
|
||||
b.Property<DateTime>("Received")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("received");
|
||||
|
||||
b.Property<byte[]>("RowVersion")
|
||||
.IsConcurrencyToken()
|
||||
.ValueGeneratedOnAddOrUpdate()
|
||||
.HasColumnType("bytea")
|
||||
.HasColumnName("row_version");
|
||||
|
||||
b.HasKey("Id")
|
||||
.HasName("pk_inbox_state");
|
||||
|
||||
b.HasAlternateKey("MessageId", "ConsumerId")
|
||||
.HasName("ak_inbox_state_message_id_consumer_id");
|
||||
|
||||
b.HasIndex("Delivered")
|
||||
.HasDatabaseName("ix_inbox_state_delivered");
|
||||
|
||||
b.ToTable("inbox_state", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("MassTransit.EntityFrameworkCoreIntegration.OutboxMessage", b =>
|
||||
{
|
||||
b.Property<long>("SequenceNumber")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("bigint")
|
||||
.HasColumnName("sequence_number");
|
||||
|
||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("SequenceNumber"));
|
||||
|
||||
b.Property<string>("Body")
|
||||
.IsRequired()
|
||||
.HasColumnType("text")
|
||||
.HasColumnName("body");
|
||||
|
||||
b.Property<string>("ContentType")
|
||||
.IsRequired()
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("character varying(256)")
|
||||
.HasColumnName("content_type");
|
||||
|
||||
b.Property<Guid?>("ConversationId")
|
||||
.HasColumnType("uuid")
|
||||
.HasColumnName("conversation_id");
|
||||
|
||||
b.Property<Guid?>("CorrelationId")
|
||||
.HasColumnType("uuid")
|
||||
.HasColumnName("correlation_id");
|
||||
|
||||
b.Property<string>("DestinationAddress")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("character varying(256)")
|
||||
.HasColumnName("destination_address");
|
||||
|
||||
b.Property<DateTime?>("EnqueueTime")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("enqueue_time");
|
||||
|
||||
b.Property<DateTime?>("ExpirationTime")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("expiration_time");
|
||||
|
||||
b.Property<string>("FaultAddress")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("character varying(256)")
|
||||
.HasColumnName("fault_address");
|
||||
|
||||
b.Property<string>("Headers")
|
||||
.HasColumnType("text")
|
||||
.HasColumnName("headers");
|
||||
|
||||
b.Property<Guid?>("InboxConsumerId")
|
||||
.HasColumnType("uuid")
|
||||
.HasColumnName("inbox_consumer_id");
|
||||
|
||||
b.Property<Guid?>("InboxMessageId")
|
||||
.HasColumnType("uuid")
|
||||
.HasColumnName("inbox_message_id");
|
||||
|
||||
b.Property<Guid?>("InitiatorId")
|
||||
.HasColumnType("uuid")
|
||||
.HasColumnName("initiator_id");
|
||||
|
||||
b.Property<Guid>("MessageId")
|
||||
.HasColumnType("uuid")
|
||||
.HasColumnName("message_id");
|
||||
|
||||
b.Property<string>("MessageType")
|
||||
.IsRequired()
|
||||
.HasColumnType("text")
|
||||
.HasColumnName("message_type");
|
||||
|
||||
b.Property<Guid?>("OutboxId")
|
||||
.HasColumnType("uuid")
|
||||
.HasColumnName("outbox_id");
|
||||
|
||||
b.Property<string>("Properties")
|
||||
.HasColumnType("text")
|
||||
.HasColumnName("properties");
|
||||
|
||||
b.Property<Guid?>("RequestId")
|
||||
.HasColumnType("uuid")
|
||||
.HasColumnName("request_id");
|
||||
|
||||
b.Property<string>("ResponseAddress")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("character varying(256)")
|
||||
.HasColumnName("response_address");
|
||||
|
||||
b.Property<DateTime>("SentTime")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("sent_time");
|
||||
|
||||
b.Property<string>("SourceAddress")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("character varying(256)")
|
||||
.HasColumnName("source_address");
|
||||
|
||||
b.HasKey("SequenceNumber")
|
||||
.HasName("pk_outbox_message");
|
||||
|
||||
b.HasIndex("EnqueueTime")
|
||||
.HasDatabaseName("ix_outbox_message_enqueue_time");
|
||||
|
||||
b.HasIndex("ExpirationTime")
|
||||
.HasDatabaseName("ix_outbox_message_expiration_time");
|
||||
|
||||
b.HasIndex("OutboxId", "SequenceNumber")
|
||||
.IsUnique()
|
||||
.HasDatabaseName("ix_outbox_message_outbox_id_sequence_number");
|
||||
|
||||
b.HasIndex("InboxMessageId", "InboxConsumerId", "SequenceNumber")
|
||||
.IsUnique()
|
||||
.HasDatabaseName("ix_outbox_message_inbox_message_id_inbox_consumer_id_sequence_~");
|
||||
|
||||
b.ToTable("outbox_message", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("MassTransit.EntityFrameworkCoreIntegration.OutboxState", b =>
|
||||
{
|
||||
b.Property<Guid>("OutboxId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uuid")
|
||||
.HasColumnName("outbox_id");
|
||||
|
||||
b.Property<DateTime>("Created")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("created");
|
||||
|
||||
b.Property<DateTime?>("Delivered")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("delivered");
|
||||
|
||||
b.Property<long?>("LastSequenceNumber")
|
||||
.HasColumnType("bigint")
|
||||
.HasColumnName("last_sequence_number");
|
||||
|
||||
b.Property<Guid>("LockId")
|
||||
.HasColumnType("uuid")
|
||||
.HasColumnName("lock_id");
|
||||
|
||||
b.Property<byte[]>("RowVersion")
|
||||
.IsConcurrencyToken()
|
||||
.ValueGeneratedOnAddOrUpdate()
|
||||
.HasColumnType("bytea")
|
||||
.HasColumnName("row_version");
|
||||
|
||||
b.HasKey("OutboxId")
|
||||
.HasName("pk_outbox_state");
|
||||
|
||||
b.HasIndex("Created")
|
||||
.HasDatabaseName("ix_outbox_state_created");
|
||||
|
||||
b.ToTable("outbox_state", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.DataProtection.EntityFrameworkCore.DataProtectionKey", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
@@ -11755,6 +11973,43 @@ namespace Tiku.Infrastructure.Persistence.Migrations
|
||||
b.ToTable("user_notifications", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Tiku.Domain.Platform.PlanModuleEntitlement", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uuid")
|
||||
.HasColumnName("id")
|
||||
.HasDefaultValueSql("gen_random_uuid()");
|
||||
|
||||
b.Property<bool>("Enabled")
|
||||
.HasColumnType("boolean")
|
||||
.HasColumnName("enabled");
|
||||
|
||||
b.Property<string>("ModuleCode")
|
||||
.IsRequired()
|
||||
.HasMaxLength(100)
|
||||
.HasColumnType("character varying(100)")
|
||||
.HasColumnName("module_code");
|
||||
|
||||
b.Property<string>("PlanCode")
|
||||
.IsRequired()
|
||||
.HasMaxLength(100)
|
||||
.HasColumnType("character varying(100)")
|
||||
.HasColumnName("plan_code");
|
||||
|
||||
b.HasKey("Id")
|
||||
.HasName("pk_plan_module_entitlements");
|
||||
|
||||
b.HasIndex("ModuleCode")
|
||||
.HasDatabaseName("ix_plan_module_entitlements_module_code");
|
||||
|
||||
b.HasIndex("PlanCode", "ModuleCode")
|
||||
.IsUnique()
|
||||
.HasDatabaseName("ix_plan_module_entitlements_plan_code_module_code");
|
||||
|
||||
b.ToTable("plan_module_entitlements", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Tiku.Domain.Platform.PlatformAuditAlert", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
@@ -12304,6 +12559,9 @@ namespace Tiku.Infrastructure.Persistence.Migrations
|
||||
b.HasKey("Id")
|
||||
.HasName("pk_platform_saas_plans");
|
||||
|
||||
b.HasAlternateKey("Code")
|
||||
.HasName("ak_platform_saas_plans_code");
|
||||
|
||||
b.HasIndex("Code")
|
||||
.IsUnique()
|
||||
.HasDatabaseName("ix_platform_saas_plans_code");
|
||||
@@ -12317,6 +12575,66 @@ namespace Tiku.Infrastructure.Persistence.Migrations
|
||||
});
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Tiku.Domain.Platform.ProductModule", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uuid")
|
||||
.HasColumnName("id")
|
||||
.HasDefaultValueSql("gen_random_uuid()");
|
||||
|
||||
b.Property<string>("Code")
|
||||
.IsRequired()
|
||||
.HasMaxLength(100)
|
||||
.HasColumnType("character varying(100)")
|
||||
.HasColumnName("code");
|
||||
|
||||
b.Property<DateTimeOffset>("CreatedAt")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("created_at")
|
||||
.HasDefaultValueSql("now()");
|
||||
|
||||
b.Property<string>("Description")
|
||||
.HasMaxLength(1000)
|
||||
.HasColumnType("character varying(1000)")
|
||||
.HasColumnName("description");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasMaxLength(200)
|
||||
.HasColumnType("character varying(200)")
|
||||
.HasColumnName("name");
|
||||
|
||||
b.Property<int>("SortOrder")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("sort_order");
|
||||
|
||||
b.Property<string>("Status")
|
||||
.IsRequired()
|
||||
.HasMaxLength(32)
|
||||
.HasColumnType("character varying(32)")
|
||||
.HasColumnName("status");
|
||||
|
||||
b.Property<DateTimeOffset>("UpdatedAt")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("updated_at")
|
||||
.HasDefaultValueSql("now()");
|
||||
|
||||
b.HasKey("Id")
|
||||
.HasName("pk_product_modules");
|
||||
|
||||
b.HasAlternateKey("Code")
|
||||
.HasName("ak_product_modules_code");
|
||||
|
||||
b.HasIndex("Code")
|
||||
.IsUnique()
|
||||
.HasDatabaseName("ix_product_modules_code");
|
||||
|
||||
b.ToTable("product_modules", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Tiku.Domain.Platform.TenantBillingProfile", b =>
|
||||
{
|
||||
b.Property<Guid>("TenantId")
|
||||
@@ -12818,6 +13136,67 @@ namespace Tiku.Infrastructure.Persistence.Migrations
|
||||
});
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Tiku.Domain.Platform.TenantModuleOverride", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uuid")
|
||||
.HasColumnName("id")
|
||||
.HasDefaultValueSql("gen_random_uuid()");
|
||||
|
||||
b.Property<DateTimeOffset>("CreatedAt")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("created_at")
|
||||
.HasDefaultValueSql("now()");
|
||||
|
||||
b.Property<DateTimeOffset?>("ExpiresAt")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("expires_at");
|
||||
|
||||
b.Property<string>("Mode")
|
||||
.IsRequired()
|
||||
.HasMaxLength(32)
|
||||
.HasColumnType("character varying(32)")
|
||||
.HasColumnName("mode");
|
||||
|
||||
b.Property<string>("ModuleCode")
|
||||
.IsRequired()
|
||||
.HasMaxLength(100)
|
||||
.HasColumnType("character varying(100)")
|
||||
.HasColumnName("module_code");
|
||||
|
||||
b.Property<string>("Reason")
|
||||
.HasMaxLength(1000)
|
||||
.HasColumnType("character varying(1000)")
|
||||
.HasColumnName("reason");
|
||||
|
||||
b.Property<Guid>("TenantId")
|
||||
.HasColumnType("uuid")
|
||||
.HasColumnName("tenant_id");
|
||||
|
||||
b.Property<DateTimeOffset>("UpdatedAt")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("updated_at")
|
||||
.HasDefaultValueSql("now()");
|
||||
|
||||
b.HasKey("Id")
|
||||
.HasName("pk_tenant_module_overrides");
|
||||
|
||||
b.HasAlternateKey("TenantId", "Id")
|
||||
.HasName("ak_tenant_module_overrides_tenant_id_id");
|
||||
|
||||
b.HasIndex("ModuleCode")
|
||||
.HasDatabaseName("ix_tenant_module_overrides_module_code");
|
||||
|
||||
b.HasIndex("TenantId", "ModuleCode")
|
||||
.IsUnique()
|
||||
.HasDatabaseName("ix_tenant_module_overrides_tenant_id_module_code");
|
||||
|
||||
b.ToTable("tenant_module_overrides", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Tiku.Domain.QuestionBanks.Question", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
@@ -13642,6 +14021,36 @@ namespace Tiku.Infrastructure.Persistence.Migrations
|
||||
b.ToTable("tenants", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Tiku.Domain.Tenancy.TenantAuthPolicy", b =>
|
||||
{
|
||||
b.Property<Guid>("TenantId")
|
||||
.HasColumnType("uuid")
|
||||
.HasColumnName("tenant_id");
|
||||
|
||||
b.Property<bool>("AllowExternalStudentSelfRegistration")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("boolean")
|
||||
.HasDefaultValue(false)
|
||||
.HasColumnName("allow_external_student_self_registration");
|
||||
|
||||
b.Property<DateTimeOffset>("CreatedAt")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("created_at")
|
||||
.HasDefaultValueSql("now()");
|
||||
|
||||
b.Property<DateTimeOffset>("UpdatedAt")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("updated_at")
|
||||
.HasDefaultValueSql("now()");
|
||||
|
||||
b.HasKey("TenantId")
|
||||
.HasName("pk_tenant_auth_policies");
|
||||
|
||||
b.ToTable("tenant_auth_policies", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Tiku.Domain.Tenancy.TenantBranding", b =>
|
||||
{
|
||||
b.Property<Guid>("TenantId")
|
||||
@@ -14618,6 +15027,20 @@ namespace Tiku.Infrastructure.Persistence.Migrations
|
||||
b.ToTable("tenant_student_notes", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("MassTransit.EntityFrameworkCoreIntegration.OutboxMessage", b =>
|
||||
{
|
||||
b.HasOne("MassTransit.EntityFrameworkCoreIntegration.OutboxState", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("OutboxId")
|
||||
.HasConstraintName("fk_outbox_message_outbox_state_outbox_id");
|
||||
|
||||
b.HasOne("MassTransit.EntityFrameworkCoreIntegration.InboxState", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("InboxMessageId", "InboxConsumerId")
|
||||
.HasPrincipalKey("MessageId", "ConsumerId")
|
||||
.HasConstraintName("fk_outbox_message_inbox_state_inbox_message_id_inbox_consumer_~");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<System.Guid>", b =>
|
||||
{
|
||||
b.HasOne("Tiku.Domain.Identity.User", null)
|
||||
@@ -17550,6 +17973,25 @@ namespace Tiku.Infrastructure.Persistence.Migrations
|
||||
.HasConstraintName("fk_user_notifications_users_user_id");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Tiku.Domain.Platform.PlanModuleEntitlement", b =>
|
||||
{
|
||||
b.HasOne("Tiku.Domain.Platform.ProductModule", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("ModuleCode")
|
||||
.HasPrincipalKey("Code")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired()
|
||||
.HasConstraintName("fk_plan_module_entitlements_product_modules_module_code");
|
||||
|
||||
b.HasOne("Tiku.Domain.Platform.PlatformSaasPlan", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("PlanCode")
|
||||
.HasPrincipalKey("Code")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired()
|
||||
.HasConstraintName("fk_plan_module_entitlements_platform_saas_plans_plan_code");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Tiku.Domain.Platform.PlatformAuditAlert", b =>
|
||||
{
|
||||
b.HasOne("Tiku.Domain.Identity.User", null)
|
||||
@@ -17719,6 +18161,24 @@ namespace Tiku.Infrastructure.Persistence.Migrations
|
||||
.HasConstraintName("fk_tenant_invoice_reminders_tenant_invoices_tenant_id_invoice_~");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Tiku.Domain.Platform.TenantModuleOverride", b =>
|
||||
{
|
||||
b.HasOne("Tiku.Domain.Platform.ProductModule", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("ModuleCode")
|
||||
.HasPrincipalKey("Code")
|
||||
.OnDelete(DeleteBehavior.Restrict)
|
||||
.IsRequired()
|
||||
.HasConstraintName("fk_tenant_module_overrides_product_modules_module_code");
|
||||
|
||||
b.HasOne("Tiku.Domain.Tenancy.Tenant", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("TenantId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired()
|
||||
.HasConstraintName("fk_tenant_module_overrides_tenants_tenant_id");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Tiku.Domain.QuestionBanks.Question", b =>
|
||||
{
|
||||
b.HasOne("Tiku.Domain.Tenancy.Tenant", null)
|
||||
@@ -17895,6 +18355,16 @@ namespace Tiku.Infrastructure.Persistence.Migrations
|
||||
.HasConstraintName("fk_tenants_users_owner_user_id");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Tiku.Domain.Tenancy.TenantAuthPolicy", b =>
|
||||
{
|
||||
b.HasOne("Tiku.Domain.Tenancy.Tenant", null)
|
||||
.WithOne()
|
||||
.HasForeignKey("Tiku.Domain.Tenancy.TenantAuthPolicy", "TenantId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired()
|
||||
.HasConstraintName("fk_tenant_auth_policies_tenants_tenant_id");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Tiku.Domain.Tenancy.TenantBranding", b =>
|
||||
{
|
||||
b.HasOne("Tiku.Domain.Tenancy.Tenant", null)
|
||||
|
||||
@@ -16,6 +16,8 @@ using Tiku.Domain.Operations;
|
||||
using Tiku.Domain.Platform;
|
||||
using Tiku.Domain.QuestionBanks;
|
||||
using Tiku.Domain.Tenancy;
|
||||
using MassTransit;
|
||||
using MassTransit.EntityFrameworkCoreIntegration;
|
||||
|
||||
namespace Tiku.Infrastructure.Persistence;
|
||||
|
||||
@@ -47,6 +49,7 @@ public sealed class TikuDbContext(
|
||||
public DbSet<TenantDomain> TenantDomains => Set<TenantDomain>();
|
||||
public DbSet<TenantBranding> TenantBrandings => Set<TenantBranding>();
|
||||
public DbSet<TenantSettings> TenantSettings => Set<TenantSettings>();
|
||||
public DbSet<TenantAuthPolicy> TenantAuthPolicies => Set<TenantAuthPolicy>();
|
||||
public DbSet<TenantFrontendConfig> TenantFrontendConfigs => Set<TenantFrontendConfig>();
|
||||
public DbSet<TenantExternalProvider> TenantExternalProviders => Set<TenantExternalProvider>();
|
||||
public DbSet<TenantSecret> TenantSecrets => Set<TenantSecret>();
|
||||
@@ -178,6 +181,9 @@ public sealed class TikuDbContext(
|
||||
public DbSet<TenantThemeTemplate> TenantThemeTemplates => Set<TenantThemeTemplate>();
|
||||
public DbSet<TenantThemeConfig> TenantThemeConfigs => Set<TenantThemeConfig>();
|
||||
public DbSet<PlatformSaasPlan> PlatformSaasPlans => Set<PlatformSaasPlan>();
|
||||
public DbSet<ProductModule> ProductModules => Set<ProductModule>();
|
||||
public DbSet<PlanModuleEntitlement> PlanModuleEntitlements => Set<PlanModuleEntitlement>();
|
||||
public DbSet<TenantModuleOverride> TenantModuleOverrides => Set<TenantModuleOverride>();
|
||||
public DbSet<TenantBillingProfile> TenantBillingProfiles => Set<TenantBillingProfile>();
|
||||
public DbSet<TenantInvoice> TenantInvoices => Set<TenantInvoice>();
|
||||
public DbSet<TenantInvoiceItem> TenantInvoiceItems => Set<TenantInvoiceItem>();
|
||||
@@ -201,6 +207,12 @@ public sealed class TikuDbContext(
|
||||
modelBuilder.HasPostgresExtension("ltree");
|
||||
modelBuilder.ApplyConfigurationsFromAssembly(typeof(TikuDbContext).Assembly);
|
||||
modelBuilder.Entity<DataProtectionKey>().ToTable("data_protection_keys");
|
||||
modelBuilder.AddInboxStateEntity();
|
||||
modelBuilder.AddOutboxMessageEntity();
|
||||
modelBuilder.AddOutboxStateEntity();
|
||||
modelBuilder.Entity<InboxState>().ToTable("inbox_state");
|
||||
modelBuilder.Entity<OutboxMessage>().ToTable("outbox_message");
|
||||
modelBuilder.Entity<OutboxState>().ToTable("outbox_state");
|
||||
ApplyTenantQueryFilters(modelBuilder);
|
||||
ValidateTenantModel(modelBuilder);
|
||||
modelBuilder.UseSnakeCaseIdentifiers();
|
||||
|
||||
Reference in New Issue
Block a user