feat(security): add distributed authorization foundation

This commit is contained in:
2026-07-29 10:40:10 +08:00
parent c7f9a4e3c9
commit df88fa19cb
76 changed files with 22020 additions and 88 deletions

View File

@@ -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)