using System; using Microsoft.EntityFrameworkCore.Migrations; using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; #nullable disable namespace Tiku.Infrastructure.Persistence.Migrations { /// public partial class AddDistributedSecurityFoundation : Migration { /// 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(type: "bigint", nullable: false) .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), message_id = table.Column(type: "uuid", nullable: false), consumer_id = table.Column(type: "uuid", nullable: false), lock_id = table.Column(type: "uuid", nullable: false), row_version = table.Column(type: "bytea", rowVersion: true, nullable: true), received = table.Column(type: "timestamp with time zone", nullable: false), receive_count = table.Column(type: "integer", nullable: false), expiration_time = table.Column(type: "timestamp with time zone", nullable: true), consumed = table.Column(type: "timestamp with time zone", nullable: true), delivered = table.Column(type: "timestamp with time zone", nullable: true), last_sequence_number = table.Column(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(type: "uuid", nullable: false), lock_id = table.Column(type: "uuid", nullable: false), row_version = table.Column(type: "bytea", rowVersion: true, nullable: true), created = table.Column(type: "timestamp with time zone", nullable: false), delivered = table.Column(type: "timestamp with time zone", nullable: true), last_sequence_number = table.Column(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(type: "uuid", nullable: false, defaultValueSql: "gen_random_uuid()"), code = table.Column(type: "character varying(100)", maxLength: 100, nullable: false), name = table.Column(type: "character varying(200)", maxLength: 200, nullable: false), description = table.Column(type: "character varying(1000)", maxLength: 1000, nullable: true), status = table.Column(type: "character varying(32)", maxLength: 32, nullable: false), sort_order = table.Column(type: "integer", nullable: false), created_at = table.Column(type: "timestamp with time zone", nullable: false, defaultValueSql: "now()"), updated_at = table.Column(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(type: "uuid", nullable: false), allow_external_student_self_registration = table.Column(type: "boolean", nullable: false, defaultValue: false), created_at = table.Column(type: "timestamp with time zone", nullable: false, defaultValueSql: "now()"), updated_at = table.Column(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(type: "bigint", nullable: false) .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), enqueue_time = table.Column(type: "timestamp with time zone", nullable: true), sent_time = table.Column(type: "timestamp with time zone", nullable: false), headers = table.Column(type: "text", nullable: true), properties = table.Column(type: "text", nullable: true), inbox_message_id = table.Column(type: "uuid", nullable: true), inbox_consumer_id = table.Column(type: "uuid", nullable: true), outbox_id = table.Column(type: "uuid", nullable: true), message_id = table.Column(type: "uuid", nullable: false), content_type = table.Column(type: "character varying(256)", maxLength: 256, nullable: false), message_type = table.Column(type: "text", nullable: false), body = table.Column(type: "text", nullable: false), conversation_id = table.Column(type: "uuid", nullable: true), correlation_id = table.Column(type: "uuid", nullable: true), initiator_id = table.Column(type: "uuid", nullable: true), request_id = table.Column(type: "uuid", nullable: true), source_address = table.Column(type: "character varying(256)", maxLength: 256, nullable: true), destination_address = table.Column(type: "character varying(256)", maxLength: 256, nullable: true), response_address = table.Column(type: "character varying(256)", maxLength: 256, nullable: true), fault_address = table.Column(type: "character varying(256)", maxLength: 256, nullable: true), expiration_time = table.Column(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(type: "uuid", nullable: false, defaultValueSql: "gen_random_uuid()"), plan_code = table.Column(type: "character varying(100)", maxLength: 100, nullable: false), module_code = table.Column(type: "character varying(100)", maxLength: 100, nullable: false), enabled = table.Column(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(type: "uuid", nullable: false, defaultValueSql: "gen_random_uuid()"), module_code = table.Column(type: "character varying(100)", maxLength: 100, nullable: false), mode = table.Column(type: "character varying(32)", maxLength: 32, nullable: false), expires_at = table.Column(type: "timestamp with time zone", nullable: true), reason = table.Column(type: "character varying(1000)", maxLength: 1000, nullable: true), tenant_id = table.Column(type: "uuid", nullable: false), created_at = table.Column(type: "timestamp with time zone", nullable: false, defaultValueSql: "now()"), updated_at = table.Column(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); } /// 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"); } } }