From 4088806b85786a4fe3df365f72f77e69fd0344c9 Mon Sep 17 00:00:00 2001 From: Mohammad Hosseini Date: Mon, 14 Sep 2026 01:36:09 +0330 Subject: [PATCH] feat(lab): make catalog Postgres ephemeral squash Demo Commerce migrations Drop the AppHost postgres_data volume so leftover CatalogInit rows cannot fail storefront migrate, align Compose WaitFor and catalogdb with AppHost, and bump SourceLink to clear NU1902 plus EF1001 test warnings. --- .dockerignore | 14 + Dockerfile | 12 +- README.md | 15 +- docker-compose.yml | 65 +- docs/building-blocks/mcp.md | 2 +- ...ngBlocks.Domain.EntityFrameworkCore.csproj | 2 +- .../Domain/BuildingBlocks.Domain.csproj | 2 +- .../BuildingBlocks.Idempotency.csproj | 2 +- .../Mcp/BuildingBlocks.Mcp.csproj | 2 +- .../Mediator/BuildingBlocks.Mediator.csproj | 2 +- ...ocks.Pagination.EntityFrameworkCore.csproj | 2 +- .../BuildingBlocks.Pagination.csproj | 2 +- .../InfrastructureExtensions.cs | 2 - ...502133232_CatalogInitMigration.Designer.cs | 264 ------ .../20250502133232_CatalogInitMigration.cs | 172 ---- .../20260829151500_ProductsKeysetIndexes.cs | 48 - ...29164800_ProductsKeysetDirectionIndexes.cs | 51 - ...0904180000_ProductsNameThenPriceIndexes.cs | 40 - ...4205214_DemoCommerceFoundation.Designer.cs | 584 ------------ .../20260904205214_DemoCommerceFoundation.cs | 312 ------ .../20260904220000_IntentTickets.cs | 56 -- ...260904222603_CatalogStorefront.Designer.cs | 711 -------------- .../20260904222603_CatalogStorefront.cs | 286 ------ ...908091824_DemoCommerceCheckout.Designer.cs | 891 ------------------ .../20260908091824_DemoCommerceCheckout.cs | 234 ----- ...92920_ProductOriginalVersionConcurrency.cs | 41 - ...913180808_DemoCommerceInitial.Designer.cs} | 4 +- .../20260913180808_DemoCommerceInitial.cs | 614 ++++++++++++ .../FeatureFusion/appsettings.Production.json | 4 +- .../MultiColumnEfTests.cs | 2 + 30 files changed, 688 insertions(+), 3750 deletions(-) create mode 100644 .dockerignore delete mode 100644 src/Lab/FeatureFusion/Infrastructure/Migrations/20250502133232_CatalogInitMigration.Designer.cs delete mode 100644 src/Lab/FeatureFusion/Infrastructure/Migrations/20250502133232_CatalogInitMigration.cs delete mode 100644 src/Lab/FeatureFusion/Infrastructure/Migrations/20260829151500_ProductsKeysetIndexes.cs delete mode 100644 src/Lab/FeatureFusion/Infrastructure/Migrations/20260829164800_ProductsKeysetDirectionIndexes.cs delete mode 100644 src/Lab/FeatureFusion/Infrastructure/Migrations/20260904180000_ProductsNameThenPriceIndexes.cs delete mode 100644 src/Lab/FeatureFusion/Infrastructure/Migrations/20260904205214_DemoCommerceFoundation.Designer.cs delete mode 100644 src/Lab/FeatureFusion/Infrastructure/Migrations/20260904205214_DemoCommerceFoundation.cs delete mode 100644 src/Lab/FeatureFusion/Infrastructure/Migrations/20260904220000_IntentTickets.cs delete mode 100644 src/Lab/FeatureFusion/Infrastructure/Migrations/20260904222603_CatalogStorefront.Designer.cs delete mode 100644 src/Lab/FeatureFusion/Infrastructure/Migrations/20260904222603_CatalogStorefront.cs delete mode 100644 src/Lab/FeatureFusion/Infrastructure/Migrations/20260908091824_DemoCommerceCheckout.Designer.cs delete mode 100644 src/Lab/FeatureFusion/Infrastructure/Migrations/20260908091824_DemoCommerceCheckout.cs delete mode 100644 src/Lab/FeatureFusion/Infrastructure/Migrations/20260908092920_ProductOriginalVersionConcurrency.cs rename src/Lab/FeatureFusion/Infrastructure/Migrations/{20260908092920_ProductOriginalVersionConcurrency.Designer.cs => 20260913180808_DemoCommerceInitial.Designer.cs} (99%) create mode 100644 src/Lab/FeatureFusion/Infrastructure/Migrations/20260913180808_DemoCommerceInitial.cs diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..492b1a0 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,14 @@ +.git +.vs +**/.vs +**/bin +**/obj +**/*.user +**/*.suo +tests +benchmarks +docs +web +node_modules +artifacts +*.binlog diff --git a/Dockerfile b/Dockerfile index b33935c..168ad5b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,6 +4,14 @@ WORKDIR /build COPY src/BuildingBlocks/Mediator/*.csproj ./src/BuildingBlocks/Mediator/ COPY src/BuildingBlocks/Mediator.Analyzers/*.csproj ./src/BuildingBlocks/Mediator.Analyzers/ COPY src/BuildingBlocks/Telemetry/*.csproj ./src/BuildingBlocks/Telemetry/ +COPY src/BuildingBlocks/Domain/*.csproj ./src/BuildingBlocks/Domain/ +COPY src/BuildingBlocks/Domain.EntityFrameworkCore/*.csproj ./src/BuildingBlocks/Domain.EntityFrameworkCore/ +COPY src/BuildingBlocks/Idempotency/*.csproj ./src/BuildingBlocks/Idempotency/ +COPY src/BuildingBlocks/Mcp/*.csproj ./src/BuildingBlocks/Mcp/ +COPY src/BuildingBlocks/Mcp.Analyzers/*.csproj ./src/BuildingBlocks/Mcp.Analyzers/ +COPY src/BuildingBlocks/Pagination/*.csproj ./src/BuildingBlocks/Pagination/ +COPY src/BuildingBlocks/Pagination.EntityFrameworkCore/*.csproj ./src/BuildingBlocks/Pagination.EntityFrameworkCore/ +COPY src/BuildingBlocks/Pagination.Dapper/*.csproj ./src/BuildingBlocks/Pagination.Dapper/ COPY src/Lab/EventBus/*.csproj ./src/Lab/EventBus/ COPY src/Lab/FeatureFusion.ServiceDefaults/*.csproj ./src/Lab/FeatureFusion.ServiceDefaults/ COPY src/Lab/FeatureFusion/*.csproj ./src/Lab/FeatureFusion/ @@ -16,13 +24,11 @@ COPY src/Lab/FeatureFusion.ServiceDefaults/ ./src/Lab/FeatureFusion.ServiceDefau COPY src/Lab/FeatureFusion/ ./src/Lab/FeatureFusion/ WORKDIR /build/src/Lab/FeatureFusion -RUN dotnet publish FeatureFusion.csproj -c Release -o /out --no-restore +RUN dotnet publish FeatureFusion.csproj -c Release -f net10.0 -o /out --no-restore /p:EnableSourceControlManagerQueries=false FROM mcr.microsoft.com/dotnet/aspnet:10.0 AS final WORKDIR /app COPY --from=build /out ./ EXPOSE 5004 ENV ASPNETCORE_URLS=http://+:5004 -HEALTHCHECK --interval=30s --timeout=3s --start-period=20s --retries=3 \ - CMD curl -f http://localhost:5004/health || exit 1 ENTRYPOINT ["dotnet", "FeatureFusion.dll"] diff --git a/README.md b/README.md index 49aa1be..a85ac26 100644 --- a/README.md +++ b/README.md @@ -895,22 +895,29 @@ The SigNoz UI always shows a **login** page. Root-user env vars skip the first-r Those custom credentials are **not** shown on the Aspire resource panel (only package-default `WithUi()` creds are). Package defaults, if you call `WithUi()` with no overrides, are `admin@localhost.local` / `Admin@Signoz1`. If login fails after changing email, delete the persistent SigNoz sqlite volume and restart AppHost. -### Option B — Docker Compose +### Option B — Docker Compose (full stack) + +From the repository root: ```bash docker compose up -d --build ``` -Uses SDK / ASP.NET **10.0** images plus supporting services. +Starts Postgres (`catalogdb`, ephemeral), Redis, RabbitMQ, Memcached, and FeatureFusion. Compose waits until those four services are **healthy** before starting the API (same idea as AppHost `WaitFor`). The API is on `http://localhost:5141`. Postgres data is not persisted; a new compose project gets an empty DB, then migrate + seed. + +The FeatureFusion image still needs those four services. Do not `docker run` it alone. + +### Option C — API only (infra already running) -### Option C — API only +Start backing services, then the API: ```bash +docker compose up -d postgres redis eventbus memcached dotnet restore FeatureFusion.sln dotnet run --project src/Lab/FeatureFusion --launch-profile https ``` -Point connection strings in `appsettings.*.json` (or user secrets) at your local infra. +`appsettings.Development.json` expects Postgres/Redis/Rabbit/Memcached on localhost (database name `catalogdb`). FeatureFusion does not create Postgres itself. AppHost is an alternative to Compose for the same infra.
Feature-flag greeting smoke diff --git a/docker-compose.yml b/docker-compose.yml index f6b2cd0..f541420 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -4,44 +4,43 @@ services: ports: - "11211:11211" healthcheck: - test: ["CMD", "nc", "-z", "memcached", "11211"] + test: ["CMD", "nc", "-z", "127.0.0.1", "11211"] interval: 5s timeout: 3s retries: 5 redis: - image: redis:latest + image: redis:8.6 ports: - "6379:6379" command: "redis-server" volumes: - redis_data:/data healthcheck: - test: ["CMD", "redis-cli", "-h", "redis", "ping"] + test: ["CMD", "redis-cli", "ping"] interval: 5s timeout: 3s retries: 5 eventbus: - image: rabbitmq:management - hostname: eventbus - container_name: eventbus + image: rabbitmq:4.3 + hostname: eventbus + container_name: eventbus networks: default: aliases: - - rabbitmq - - eventbus + - rabbitmq + - eventbus ports: - "5672:5672" - "15672:15672" environment: - RABBITMQ_DEFAULT_USER: guest - RABBITMQ_DEFAULT_PASS: guest + RABBITMQ_DEFAULT_USER: guest + RABBITMQ_DEFAULT_PASS: guest RABBITMQ_DEFAULT_VHOST: / - RABBITMQ_NODENAME: rabbit@eventbus + RABBITMQ_NODENAME: rabbit@eventbus RABBITMQ_SERVER_ADDITIONAL_ERL_ARGS: "-proto_dist inet_tcp" RABBITMQ_DEFAULT_PERMISSIONS: "guest . \".*\" \".*\"" - healthcheck: test: ["CMD", "rabbitmq-diagnostics", "-q", "ping"] interval: 10s @@ -50,26 +49,17 @@ services: volumes: - rabbitmq-data:/var/lib/rabbitmq - postgres: - image: postgres:15-alpine + image: postgres:16-alpine hostname: postgres ports: - "5432:5432" environment: POSTGRES_USER: username - POSTGRES_PASSWORD: password - POSTGRES_DB: eventstore - POSTGRES_HOST_AUTH_METHOD: scram-sha-256 - POSTGRES_INITDB_ARGS: >- - --username=username - --pwfile=<(echo "password") - --auth-host=scram-sha-256 - --auth-local=scram-sha-256 - volumes: - - postgres_data:/var/lib/postgresql/data - healthcheck: - test: ["CMD-SHELL", "pg_isready -h localhost -U username -d eventstore"] + POSTGRES_PASSWORD: password + POSTGRES_DB: catalogdb + healthcheck: + test: ["CMD-SHELL", "pg_isready -h localhost -U username -d catalogdb"] interval: 5s timeout: 5s retries: 10 @@ -87,7 +77,10 @@ services: condition: service_healthy featurefusion-app: + image: featurefusion-app build: . + ports: + - "5141:5004" depends_on: postgres: condition: service_healthy @@ -98,19 +91,13 @@ services: memcached: condition: service_healthy environment: - - ASPNETCORE_ENVIRONMENT=Production - - MEMCACHED__SERVER=memcached:11211 - command: > - sh -c " - while ! nc -z postgres 5432; do sleep 1; done && - while ! nc -z redis 6379; do sleep 1; done && - while ! nc -z eventbus 5672;do sleep 1; done && - while ! nc -z memcached 11211; do sleep 1; done && - echo 'All dependencies ready' && - dotnet FeatureFusion.dll - " + ASPNETCORE_ENVIRONMENT: Development + ConnectionStrings__catalogdb: Host=postgres;Port=5432;Username=username;Password=password;Database=catalogdb + ConnectionStrings__eventbus: amqp://guest:guest@eventbus:5672/ + Redis__ConnectionString: redis:6379 + Memcached__Servers__0__Address: memcached + Memcached__Servers__0__Port: "11211" volumes: redis_data: - postgres_data: - rabbitmq-data: \ No newline at end of file + rabbitmq-data: diff --git a/docs/building-blocks/mcp.md b/docs/building-blocks/mcp.md index b72d1a3..da9ac64 100644 --- a/docs/building-blocks/mcp.md +++ b/docs/building-blocks/mcp.md @@ -208,7 +208,7 @@ Development only (`http://localhost:5141/mcp`): | `products.list` | Scan + `ISender` (query) | products query | | `lab.ping` | `[McpTool]` + `.WithMcp(app)` on `LabPing` | `GET /api/v1/lab-ping` | -Production (`docker-compose` sets `ASPNETCORE_ENVIRONMENT=Production`) does not register or map MCP. +Lab Compose sets `ASPNETCORE_ENVIRONMENT=Development` so MCP is registered (map at `/mcp`). A Production-environment host does not register or map MCP. Workspace root for this Cursor window is `src/`. Put this in `src/.cursor/mcp.json` (gitignored; copy locally): diff --git a/src/BuildingBlocks/Domain.EntityFrameworkCore/BuildingBlocks.Domain.EntityFrameworkCore.csproj b/src/BuildingBlocks/Domain.EntityFrameworkCore/BuildingBlocks.Domain.EntityFrameworkCore.csproj index ceb1946..18be973 100644 --- a/src/BuildingBlocks/Domain.EntityFrameworkCore/BuildingBlocks.Domain.EntityFrameworkCore.csproj +++ b/src/BuildingBlocks/Domain.EntityFrameworkCore/BuildingBlocks.Domain.EntityFrameworkCore.csproj @@ -47,7 +47,7 @@ - + diff --git a/src/BuildingBlocks/Domain/BuildingBlocks.Domain.csproj b/src/BuildingBlocks/Domain/BuildingBlocks.Domain.csproj index 425c0f7..20afb6a 100644 --- a/src/BuildingBlocks/Domain/BuildingBlocks.Domain.csproj +++ b/src/BuildingBlocks/Domain/BuildingBlocks.Domain.csproj @@ -37,7 +37,7 @@ - + diff --git a/src/BuildingBlocks/Idempotency/BuildingBlocks.Idempotency.csproj b/src/BuildingBlocks/Idempotency/BuildingBlocks.Idempotency.csproj index 8c418e4..c867f2d 100644 --- a/src/BuildingBlocks/Idempotency/BuildingBlocks.Idempotency.csproj +++ b/src/BuildingBlocks/Idempotency/BuildingBlocks.Idempotency.csproj @@ -45,7 +45,7 @@ - + diff --git a/src/BuildingBlocks/Mcp/BuildingBlocks.Mcp.csproj b/src/BuildingBlocks/Mcp/BuildingBlocks.Mcp.csproj index 3ce3914..94e7534 100644 --- a/src/BuildingBlocks/Mcp/BuildingBlocks.Mcp.csproj +++ b/src/BuildingBlocks/Mcp/BuildingBlocks.Mcp.csproj @@ -47,7 +47,7 @@ - + diff --git a/src/BuildingBlocks/Mediator/BuildingBlocks.Mediator.csproj b/src/BuildingBlocks/Mediator/BuildingBlocks.Mediator.csproj index d64ab4a..700c716 100644 --- a/src/BuildingBlocks/Mediator/BuildingBlocks.Mediator.csproj +++ b/src/BuildingBlocks/Mediator/BuildingBlocks.Mediator.csproj @@ -47,7 +47,7 @@ - + diff --git a/src/BuildingBlocks/Pagination.EntityFrameworkCore/BuildingBlocks.Pagination.EntityFrameworkCore.csproj b/src/BuildingBlocks/Pagination.EntityFrameworkCore/BuildingBlocks.Pagination.EntityFrameworkCore.csproj index da01a14..2314537 100644 --- a/src/BuildingBlocks/Pagination.EntityFrameworkCore/BuildingBlocks.Pagination.EntityFrameworkCore.csproj +++ b/src/BuildingBlocks/Pagination.EntityFrameworkCore/BuildingBlocks.Pagination.EntityFrameworkCore.csproj @@ -41,7 +41,7 @@ - + diff --git a/src/BuildingBlocks/Pagination/BuildingBlocks.Pagination.csproj b/src/BuildingBlocks/Pagination/BuildingBlocks.Pagination.csproj index 43b7d77..72d82b3 100644 --- a/src/BuildingBlocks/Pagination/BuildingBlocks.Pagination.csproj +++ b/src/BuildingBlocks/Pagination/BuildingBlocks.Pagination.csproj @@ -16,7 +16,7 @@ - + diff --git a/src/Lab/FeatureFusion.AppHost/InfrastructureExtensions.cs b/src/Lab/FeatureFusion.AppHost/InfrastructureExtensions.cs index 7cb3cff..933b85c 100644 --- a/src/Lab/FeatureFusion.AppHost/InfrastructureExtensions.cs +++ b/src/Lab/FeatureFusion.AppHost/InfrastructureExtensions.cs @@ -45,13 +45,11 @@ public static InfrastructureResources AddInfrastructure(this IDistributedApplica // pgAdmin is dashboard-only tooling; FeatureFusion WaitFor(catalogDb), not pgAdmin. // Brief "Unhealthy" in the dashboard while the UI container boots is expected. var postgres = builder.AddPostgres("postgres", userName: username, password: password) - .WithDataVolume("postgres_data") .WithPgAdmin(container => { container.WithEnvironment("PGADMIN_DEFAULT_EMAIL", "guest@admin.com"); container.WithEnvironment("PGADMIN_DEFAULT_PASSWORD", "guest"); }) - .WithLifetime(ContainerLifetime.Persistent) .WithEndpoint("tcp", endpoint => { endpoint.Port = 5432; diff --git a/src/Lab/FeatureFusion/Infrastructure/Migrations/20250502133232_CatalogInitMigration.Designer.cs b/src/Lab/FeatureFusion/Infrastructure/Migrations/20250502133232_CatalogInitMigration.Designer.cs deleted file mode 100644 index cfede01..0000000 --- a/src/Lab/FeatureFusion/Infrastructure/Migrations/20250502133232_CatalogInitMigration.Designer.cs +++ /dev/null @@ -1,264 +0,0 @@ -// -using System; -using FeatureFusion.Infrastructure.Context; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; - -#nullable disable - -namespace FeatureFusion.Infrastructure.Migrations -{ - [DbContext(typeof(CatalogDbContext))] - [Migration("20250502133232_CatalogInitMigration")] - partial class CatalogInitMigration - { - /// - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "9.0.0") - .HasAnnotation("Relational:MaxIdentifierLength", 63); - - NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); - - modelBuilder.Entity("EventBusRabbitMQ.Domain.InboxMessage", b => - { - b.Property("Id") - .HasColumnType("uuid"); - - b.Property("CompletedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("Error") - .HasMaxLength(500) - .HasColumnType("character varying(500)"); - - b.Property("EventType") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.Property("IsProcessed") - .HasColumnType("boolean"); - - b.Property("Payload") - .IsRequired() - .HasColumnType("bytea"); - - b.Property("ProcessedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("RowVersion") - .IsConcurrencyToken() - .ValueGeneratedOnAddOrUpdate() - .HasColumnType("xid") - .HasColumnName("xmin"); - - b.Property("ServiceName") - .IsRequired() - .HasMaxLength(200) - .HasColumnType("character varying(200)"); - - b.Property("Status") - .IsRequired() - .HasMaxLength(20) - .HasColumnType("character varying(20)"); - - b.HasKey("Id"); - - b.HasIndex("Id") - .IsUnique(); - - b.ToTable("inbox_messages", (string)null); - }); - - modelBuilder.Entity("EventBusRabbitMQ.Domain.InboxSubscriber", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("Attempts") - .ValueGeneratedOnAdd() - .HasColumnType("integer") - .HasDefaultValue(0); - - b.Property("Error") - .HasMaxLength(500) - .HasColumnType("character varying(500)"); - - b.Property("LastAttemptedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("MessageId") - .HasColumnType("uuid"); - - b.Property("RowVersion") - .IsConcurrencyToken() - .ValueGeneratedOnAddOrUpdate() - .HasColumnType("xid") - .HasColumnName("xmin"); - - b.Property("Status") - .IsRequired() - .HasMaxLength(20) - .HasColumnType("character varying(20)"); - - b.Property("SubscriberName") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.HasKey("Id"); - - b.HasIndex("Status"); - - b.HasIndex("MessageId", "SubscriberName") - .IsUnique(); - - b.ToTable("inbox_subscribers", (string)null); - }); - - modelBuilder.Entity("EventBusRabbitMQ.Domain.OutboxMessage", b => - { - b.Property("Id") - .HasColumnType("uuid") - .HasColumnName("id"); - - b.Property("CompletedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("CreatedAt") - .HasColumnType("timestamptz") - .HasColumnName("created_at"); - - b.Property("Error") - .HasMaxLength(500) - .HasColumnType("character varying(500)"); - - b.Property("EventType") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)") - .HasColumnName("event_type"); - - b.Property("Payload") - .IsRequired() - .HasColumnType("jsonb") - .HasColumnName("payload"); - - b.Property("ProcessedAt") - .HasColumnType("timestamptz") - .HasColumnName("processed_at"); - - b.Property("RetryCount") - .ValueGeneratedOnAdd() - .HasColumnType("integer") - .HasDefaultValue(0) - .HasColumnName("retry_count"); - - b.Property("Status") - .IsRequired() - .HasMaxLength(20) - .HasColumnType("character varying(20)") - .HasColumnName("status"); - - b.HasKey("Id") - .HasName("pk_outbox_messages"); - - b.HasIndex("CreatedAt") - .HasDatabaseName("ix_outbox_messages_unprocessed") - .HasFilter("processed_at IS NULL"); - - NpgsqlIndexBuilderExtensions.IncludeProperties(b.HasIndex("CreatedAt"), new[] { "Id", "EventType", "Payload" }); - - b.HasIndex("Status", "RetryCount", "CreatedAt") - .HasDatabaseName("ix_outbox_messages_status_retry_created") - .HasFilter("status IN ('Pending', 'Failed')"); - - NpgsqlIndexBuilderExtensions.IncludeProperties(b.HasIndex("Status", "RetryCount", "CreatedAt"), new[] { "Id", "EventType", "Payload" }); - - b.ToTable("outbox_messages", (string)null); - }); - - modelBuilder.Entity("EventBusRabbitMQ.Domain.ProcessedMessage", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("ProcessedAt") - .HasColumnType("timestamp with time zone"); - - b.HasKey("Id"); - - b.ToTable("processed_messages", (string)null); - }); - - modelBuilder.Entity("FeatureFusion.Domain.Catalog.Product", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("Deleted") - .HasColumnType("boolean"); - - b.Property("FullDescription") - .HasColumnType("text"); - - b.Property("Name") - .HasColumnType("text"); - - b.Property("Price") - .HasColumnType("numeric"); - - b.Property("Published") - .HasColumnType("boolean"); - - b.Property("VisibleIndividually") - .HasColumnType("boolean"); - - b.HasKey("Id"); - - b.HasIndex("CreatedAt") - .IsDescending() - .HasDatabaseName("IX_products_created_at_desc"); - - b.HasIndex("Name") - .HasDatabaseName("IX_products_name"); - - b.ToTable("products", (string)null); - }); - - modelBuilder.Entity("EventBusRabbitMQ.Domain.InboxSubscriber", b => - { - b.HasOne("EventBusRabbitMQ.Domain.InboxMessage", "Message") - .WithMany("Subscribers") - .HasForeignKey("MessageId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Message"); - }); - - modelBuilder.Entity("EventBusRabbitMQ.Domain.InboxMessage", b => - { - b.Navigation("Subscribers"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/src/Lab/FeatureFusion/Infrastructure/Migrations/20250502133232_CatalogInitMigration.cs b/src/Lab/FeatureFusion/Infrastructure/Migrations/20250502133232_CatalogInitMigration.cs deleted file mode 100644 index de8e3cb..0000000 --- a/src/Lab/FeatureFusion/Infrastructure/Migrations/20250502133232_CatalogInitMigration.cs +++ /dev/null @@ -1,172 +0,0 @@ -using System; -using Microsoft.EntityFrameworkCore.Migrations; -using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; - -#nullable disable - -namespace FeatureFusion.Infrastructure.Migrations -{ - /// - public partial class CatalogInitMigration : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.CreateTable( - name: "inbox_messages", - columns: table => new - { - Id = table.Column(type: "uuid", nullable: false), - ServiceName = table.Column(type: "character varying(200)", maxLength: 200, nullable: false), - IsProcessed = table.Column(type: "boolean", nullable: false), - xmin = table.Column(type: "xid", rowVersion: true, nullable: false), - EventType = table.Column(type: "character varying(256)", maxLength: 256, nullable: false), - Payload = table.Column(type: "bytea", nullable: false), - CreatedAt = table.Column(type: "timestamp with time zone", nullable: false), - ProcessedAt = table.Column(type: "timestamp with time zone", nullable: true), - CompletedAt = table.Column(type: "timestamp with time zone", nullable: true), - Status = table.Column(type: "character varying(20)", maxLength: 20, nullable: false), - Error = table.Column(type: "character varying(500)", maxLength: 500, nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_inbox_messages", x => x.Id); - }); - - migrationBuilder.CreateTable( - name: "outbox_messages", - columns: table => new - { - id = table.Column(type: "uuid", nullable: false), - retry_count = table.Column(type: "integer", nullable: false, defaultValue: 0), - event_type = table.Column(type: "character varying(256)", maxLength: 256, nullable: false), - payload = table.Column(type: "jsonb", nullable: false), - created_at = table.Column(type: "timestamptz", nullable: false), - processed_at = table.Column(type: "timestamptz", nullable: true), - CompletedAt = table.Column(type: "timestamp with time zone", nullable: true), - status = table.Column(type: "character varying(20)", maxLength: 20, nullable: false), - Error = table.Column(type: "character varying(500)", maxLength: 500, nullable: true) - }, - constraints: table => - { - table.PrimaryKey("pk_outbox_messages", x => x.id); - }); - - migrationBuilder.CreateTable( - name: "processed_messages", - columns: table => new - { - Id = table.Column(type: "uuid", nullable: false), - ProcessedAt = table.Column(type: "timestamp with time zone", nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_processed_messages", x => x.Id); - }); - - migrationBuilder.CreateTable( - name: "products", - columns: table => new - { - Id = table.Column(type: "integer", nullable: false) - .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), - Name = table.Column(type: "text", nullable: true), - FullDescription = table.Column(type: "text", nullable: true), - Published = table.Column(type: "boolean", nullable: false), - Deleted = table.Column(type: "boolean", nullable: false), - VisibleIndividually = table.Column(type: "boolean", nullable: false), - Price = table.Column(type: "numeric", nullable: false), - CreatedAt = table.Column(type: "timestamp with time zone", nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_products", x => x.Id); - }); - - migrationBuilder.CreateTable( - name: "inbox_subscribers", - columns: table => new - { - Id = table.Column(type: "uuid", nullable: false), - SubscriberName = table.Column(type: "character varying(256)", maxLength: 256, nullable: false), - MessageId = table.Column(type: "uuid", nullable: false), - Status = table.Column(type: "character varying(20)", maxLength: 20, nullable: false), - Attempts = table.Column(type: "integer", nullable: false, defaultValue: 0), - LastAttemptedAt = table.Column(type: "timestamp with time zone", nullable: true), - Error = table.Column(type: "character varying(500)", maxLength: 500, nullable: true), - xmin = table.Column(type: "xid", rowVersion: true, nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_inbox_subscribers", x => x.Id); - table.ForeignKey( - name: "FK_inbox_subscribers_inbox_messages_MessageId", - column: x => x.MessageId, - principalTable: "inbox_messages", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateIndex( - name: "IX_inbox_messages_Id", - table: "inbox_messages", - column: "Id", - unique: true); - - migrationBuilder.CreateIndex( - name: "IX_inbox_subscribers_MessageId_SubscriberName", - table: "inbox_subscribers", - columns: new[] { "MessageId", "SubscriberName" }, - unique: true); - - migrationBuilder.CreateIndex( - name: "IX_inbox_subscribers_Status", - table: "inbox_subscribers", - column: "Status"); - - migrationBuilder.CreateIndex( - name: "ix_outbox_messages_status_retry_created", - table: "outbox_messages", - columns: new[] { "status", "retry_count", "created_at" }, - filter: "status IN ('Pending', 'Failed')") - .Annotation("Npgsql:IndexInclude", new[] { "id", "event_type", "payload" }); - - migrationBuilder.CreateIndex( - name: "ix_outbox_messages_unprocessed", - table: "outbox_messages", - column: "created_at", - filter: "processed_at IS NULL") - .Annotation("Npgsql:IndexInclude", new[] { "id", "event_type", "payload" }); - - migrationBuilder.CreateIndex( - name: "IX_products_created_at_desc", - table: "products", - column: "CreatedAt", - descending: new bool[0]); - - migrationBuilder.CreateIndex( - name: "IX_products_name", - table: "products", - column: "Name"); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropTable( - name: "inbox_subscribers"); - - migrationBuilder.DropTable( - name: "outbox_messages"); - - migrationBuilder.DropTable( - name: "processed_messages"); - - migrationBuilder.DropTable( - name: "products"); - - migrationBuilder.DropTable( - name: "inbox_messages"); - } - } -} diff --git a/src/Lab/FeatureFusion/Infrastructure/Migrations/20260829151500_ProductsKeysetIndexes.cs b/src/Lab/FeatureFusion/Infrastructure/Migrations/20260829151500_ProductsKeysetIndexes.cs deleted file mode 100644 index d4f9f06..0000000 --- a/src/Lab/FeatureFusion/Infrastructure/Migrations/20260829151500_ProductsKeysetIndexes.cs +++ /dev/null @@ -1,48 +0,0 @@ -using FeatureFusion.Infrastructure.Context; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; - -#nullable disable - -namespace FeatureFusion.Infrastructure.Migrations -{ - [DbContext(typeof(CatalogDbContext))] - [Migration("20260829151500_ProductsKeysetIndexes")] - public partial class ProductsKeysetIndexes : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.CreateIndex( - name: "IX_products_created_at_id", - table: "products", - columns: new[] { "CreatedAt", "Id" }); - - migrationBuilder.CreateIndex( - name: "IX_products_name_id", - table: "products", - columns: new[] { "Name", "Id" }); - - migrationBuilder.CreateIndex( - name: "IX_products_price_id", - table: "products", - columns: new[] { "Price", "Id" }); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropIndex( - name: "IX_products_created_at_id", - table: "products"); - - migrationBuilder.DropIndex( - name: "IX_products_name_id", - table: "products"); - - migrationBuilder.DropIndex( - name: "IX_products_price_id", - table: "products"); - } - } -} diff --git a/src/Lab/FeatureFusion/Infrastructure/Migrations/20260829164800_ProductsKeysetDirectionIndexes.cs b/src/Lab/FeatureFusion/Infrastructure/Migrations/20260829164800_ProductsKeysetDirectionIndexes.cs deleted file mode 100644 index 374fabb..0000000 --- a/src/Lab/FeatureFusion/Infrastructure/Migrations/20260829164800_ProductsKeysetDirectionIndexes.cs +++ /dev/null @@ -1,51 +0,0 @@ -using FeatureFusion.Infrastructure.Context; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; - -#nullable disable - -namespace FeatureFusion.Infrastructure.Migrations -{ - [DbContext(typeof(CatalogDbContext))] - [Migration("20260829164800_ProductsKeysetDirectionIndexes")] - public partial class ProductsKeysetDirectionIndexes : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.CreateIndex( - name: "IX_products_created_at_id_desc", - table: "products", - columns: new[] { "CreatedAt", "Id" }, - descending: new[] { true, false }); - - migrationBuilder.CreateIndex( - name: "IX_products_name_id_desc", - table: "products", - columns: new[] { "Name", "Id" }, - descending: new[] { true, false }); - - migrationBuilder.CreateIndex( - name: "IX_products_price_id_desc", - table: "products", - columns: new[] { "Price", "Id" }, - descending: new[] { true, false }); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropIndex( - name: "IX_products_created_at_id_desc", - table: "products"); - - migrationBuilder.DropIndex( - name: "IX_products_name_id_desc", - table: "products"); - - migrationBuilder.DropIndex( - name: "IX_products_price_id_desc", - table: "products"); - } - } -} diff --git a/src/Lab/FeatureFusion/Infrastructure/Migrations/20260904180000_ProductsNameThenPriceIndexes.cs b/src/Lab/FeatureFusion/Infrastructure/Migrations/20260904180000_ProductsNameThenPriceIndexes.cs deleted file mode 100644 index 00c8c28..0000000 --- a/src/Lab/FeatureFusion/Infrastructure/Migrations/20260904180000_ProductsNameThenPriceIndexes.cs +++ /dev/null @@ -1,40 +0,0 @@ -using FeatureFusion.Infrastructure.Context; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; - -#nullable disable - -namespace FeatureFusion.Infrastructure.Migrations -{ - [DbContext(typeof(CatalogDbContext))] - [Migration("20260904180000_ProductsNameThenPriceIndexes")] - public partial class ProductsNameThenPriceIndexes : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.CreateIndex( - name: "IX_products_name_price_id", - table: "products", - columns: new[] { "Name", "Price", "Id" }); - - migrationBuilder.CreateIndex( - name: "IX_products_name_price_id_desc", - table: "products", - columns: new[] { "Name", "Price", "Id" }, - descending: new[] { true, true, true }); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropIndex( - name: "IX_products_name_price_id", - table: "products"); - - migrationBuilder.DropIndex( - name: "IX_products_name_price_id_desc", - table: "products"); - } - } -} diff --git a/src/Lab/FeatureFusion/Infrastructure/Migrations/20260904205214_DemoCommerceFoundation.Designer.cs b/src/Lab/FeatureFusion/Infrastructure/Migrations/20260904205214_DemoCommerceFoundation.Designer.cs deleted file mode 100644 index ff2ac5d..0000000 --- a/src/Lab/FeatureFusion/Infrastructure/Migrations/20260904205214_DemoCommerceFoundation.Designer.cs +++ /dev/null @@ -1,584 +0,0 @@ -// -using System; -using FeatureFusion.Infrastructure.Context; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; - -#nullable disable - -namespace FeatureFusion.Infrastructure.Migrations -{ - [DbContext(typeof(CatalogDbContext))] - [Migration("20260904205214_DemoCommerceFoundation")] - partial class DemoCommerceFoundation - { - /// - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "10.0.10") - .HasAnnotation("Relational:MaxIdentifierLength", 63); - - NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); - - modelBuilder.Entity("EventBusRabbitMQ.Domain.InboxMessage", b => - { - b.Property("Id") - .HasColumnType("uuid"); - - b.Property("CompletedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("Error") - .HasMaxLength(500) - .HasColumnType("character varying(500)"); - - b.Property("EventType") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.Property("IsProcessed") - .HasColumnType("boolean"); - - b.Property("Payload") - .IsRequired() - .HasColumnType("bytea"); - - b.Property("ProcessedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("RowVersion") - .IsConcurrencyToken() - .ValueGeneratedOnAddOrUpdate() - .HasColumnType("xid") - .HasColumnName("xmin"); - - b.Property("ServiceName") - .IsRequired() - .HasMaxLength(200) - .HasColumnType("character varying(200)"); - - b.Property("Status") - .IsRequired() - .HasMaxLength(20) - .HasColumnType("character varying(20)"); - - b.HasKey("Id"); - - b.HasIndex("Id") - .IsUnique(); - - b.ToTable("inbox_messages", (string)null); - }); - - modelBuilder.Entity("EventBusRabbitMQ.Domain.InboxSubscriber", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("Attempts") - .ValueGeneratedOnAdd() - .HasColumnType("integer") - .HasDefaultValue(0); - - b.Property("Error") - .HasMaxLength(500) - .HasColumnType("character varying(500)"); - - b.Property("LastAttemptedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("MessageId") - .HasColumnType("uuid"); - - b.Property("RowVersion") - .IsConcurrencyToken() - .ValueGeneratedOnAddOrUpdate() - .HasColumnType("xid") - .HasColumnName("xmin"); - - b.Property("Status") - .IsRequired() - .HasMaxLength(20) - .HasColumnType("character varying(20)"); - - b.Property("SubscriberName") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.HasKey("Id"); - - b.HasIndex("Status"); - - b.HasIndex("MessageId", "SubscriberName") - .IsUnique(); - - b.ToTable("inbox_subscribers", (string)null); - }); - - modelBuilder.Entity("EventBusRabbitMQ.Domain.OutboxMessage", b => - { - b.Property("Id") - .HasColumnType("uuid") - .HasColumnName("id"); - - b.Property("CompletedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("CreatedAt") - .HasColumnType("timestamptz") - .HasColumnName("created_at"); - - b.Property("Error") - .HasMaxLength(500) - .HasColumnType("character varying(500)"); - - b.Property("EventType") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)") - .HasColumnName("event_type"); - - b.PrimitiveCollection("Payload") - .IsRequired() - .HasColumnType("jsonb") - .HasColumnName("payload"); - - b.Property("ProcessedAt") - .HasColumnType("timestamptz") - .HasColumnName("processed_at"); - - b.Property("RetryCount") - .ValueGeneratedOnAdd() - .HasColumnType("integer") - .HasDefaultValue(0) - .HasColumnName("retry_count"); - - b.Property("Status") - .IsRequired() - .HasMaxLength(20) - .HasColumnType("character varying(20)") - .HasColumnName("status"); - - b.HasKey("Id") - .HasName("pk_outbox_messages"); - - b.HasIndex("CreatedAt") - .HasDatabaseName("ix_outbox_messages_unprocessed") - .HasFilter("processed_at IS NULL"); - - NpgsqlIndexBuilderExtensions.IncludeProperties(b.HasIndex("CreatedAt"), new[] { "Id", "EventType", "Payload" }); - - b.HasIndex("Status", "RetryCount", "CreatedAt") - .HasDatabaseName("ix_outbox_messages_status_retry_created") - .HasFilter("status IN ('Pending', 'Failed')"); - - NpgsqlIndexBuilderExtensions.IncludeProperties(b.HasIndex("Status", "RetryCount", "CreatedAt"), new[] { "Id", "EventType", "Payload" }); - - b.ToTable("outbox_messages", (string)null); - }); - - modelBuilder.Entity("EventBusRabbitMQ.Domain.ProcessedMessage", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("ProcessedAt") - .HasColumnType("timestamp with time zone"); - - b.HasKey("Id"); - - b.ToTable("processed_messages", (string)null); - }); - - modelBuilder.Entity("FeatureFusion.Domain.Catalog.Brand", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("Name") - .IsRequired() - .HasMaxLength(128) - .HasColumnType("character varying(128)"); - - b.HasKey("Id"); - - b.HasIndex("Name") - .IsUnique(); - - b.ToTable("brands", (string)null); - }); - - modelBuilder.Entity("FeatureFusion.Domain.Catalog.Category", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("Name") - .IsRequired() - .HasMaxLength(128) - .HasColumnType("character varying(128)"); - - b.HasKey("Id"); - - b.HasIndex("Name") - .IsUnique(); - - b.ToTable("categories", (string)null); - }); - - modelBuilder.Entity("FeatureFusion.Domain.Customers.Customer", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("DisplayName") - .IsRequired() - .HasMaxLength(200) - .HasColumnType("character varying(200)"); - - b.Property("Email") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)") - .HasColumnName("Email"); - - b.HasKey("Id"); - - b.HasIndex("Email") - .IsUnique() - .HasDatabaseName("IX_customers_email"); - - b.ToTable("customers", (string)null); - }); - - modelBuilder.Entity("FeatureFusion.Domain.Orders.Order", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("Currency") - .IsRequired() - .HasMaxLength(3) - .HasColumnType("character varying(3)"); - - b.Property("CustomerId") - .HasColumnType("integer"); - - b.Property("OrderNumber") - .IsRequired() - .HasMaxLength(32) - .HasColumnType("character varying(32)"); - - b.Property("Status") - .IsRequired() - .HasMaxLength(32) - .HasColumnType("character varying(32)"); - - b.Property("Total") - .HasPrecision(18, 2) - .HasColumnType("numeric(18,2)"); - - b.HasKey("Id"); - - b.HasIndex("CreatedAt") - .HasDatabaseName("IX_orders_created_at"); - - b.HasIndex("CustomerId") - .HasDatabaseName("IX_orders_customer_id"); - - b.HasIndex("OrderNumber") - .IsUnique(); - - b.HasIndex("Status") - .HasDatabaseName("IX_orders_status"); - - b.ToTable("orders", (string)null); - }); - - modelBuilder.Entity("FeatureFusion.Domain.Orders.OrderItem", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("OrderId") - .HasColumnType("integer"); - - b.Property("ProductId") - .HasColumnType("integer"); - - b.Property("Quantity") - .HasColumnType("integer"); - - b.Property("UnitPrice") - .HasPrecision(18, 2) - .HasColumnType("numeric(18,2)"); - - b.HasKey("Id"); - - b.HasIndex("OrderId") - .HasDatabaseName("IX_order_items_order_id"); - - b.HasIndex("ProductId") - .HasDatabaseName("IX_order_items_product_id"); - - b.ToTable("order_items", (string)null); - }); - - modelBuilder.Entity("FeatureFusion.Domain.Catalog.Product", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("BrandId") - .HasColumnType("integer"); - - b.Property("CategoryId") - .HasColumnType("integer"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("Deleted") - .HasColumnType("boolean"); - - b.Property("FullDescription") - .HasColumnType("text"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.Property("Price") - .HasPrecision(18, 2) - .HasColumnType("numeric(18,2)"); - - b.Property("Published") - .HasColumnType("boolean"); - - b.Property("Sku") - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.Property("StockQuantity") - .HasColumnType("integer"); - - b.Property("VisibleIndividually") - .HasColumnType("boolean"); - - b.HasKey("Id"); - - b.HasIndex("BrandId") - .HasDatabaseName("IX_products_brand_id"); - - b.HasIndex("CategoryId") - .HasDatabaseName("IX_products_category_id"); - - b.HasIndex("CreatedAt") - .IsDescending() - .HasDatabaseName("IX_products_created_at_desc"); - - b.HasIndex("Name") - .HasDatabaseName("IX_products_name"); - - b.HasIndex("Sku") - .IsUnique() - .HasDatabaseName("IX_products_sku") - .HasFilter("\"Sku\" IS NOT NULL"); - - b.HasIndex(new[] { "CreatedAt", "Id" }, "IX_Product_CreatedAt_Id_AA") - .HasDatabaseName("IX_products_created_at_id"); - - b.HasIndex(new[] { "CreatedAt", "Id" }, "IX_Product_CreatedAt_Id_DA") - .IsDescending(true, false) - .HasDatabaseName("IX_products_created_at_id_desc"); - - b.HasIndex(new[] { "Name", "Id" }, "IX_Product_Name_Id_AA") - .HasDatabaseName("IX_products_name_id"); - - b.HasIndex(new[] { "Name", "Id" }, "IX_Product_Name_Id_DA") - .IsDescending(true, false) - .HasDatabaseName("IX_products_name_id_desc"); - - b.HasIndex(new[] { "Name", "Price", "Id" }, "IX_Product_Name_Price_Id_AAA") - .HasDatabaseName("IX_products_name_price_id"); - - b.HasIndex(new[] { "Name", "Price", "Id" }, "IX_Product_Name_Price_Id_DDD") - .IsDescending() - .HasDatabaseName("IX_products_name_price_id_desc"); - - b.HasIndex(new[] { "Price", "Id" }, "IX_Product_Price_Id_AA") - .HasDatabaseName("IX_products_price_id"); - - b.HasIndex(new[] { "Price", "Id" }, "IX_Product_Price_Id_DA") - .IsDescending(true, false) - .HasDatabaseName("IX_products_price_id_desc"); - - b.ToTable("products", (string)null); - }); - - modelBuilder.Entity("FeatureFusion.Features.Admission.IntentTicket", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("CapabilityId") - .IsRequired() - .HasMaxLength(128) - .HasColumnType("character varying(128)"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("ExecutionOrderId") - .HasColumnType("uuid"); - - b.Property("ExpiresAt") - .HasColumnType("timestamp with time zone"); - - b.Property("IntentHash") - .IsRequired() - .HasMaxLength(128) - .HasColumnType("character varying(128)"); - - b.Property("IntentPayload") - .IsRequired() - .HasColumnType("text"); - - b.Property("ReleasedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("ReleasedBy") - .HasMaxLength(128) - .HasColumnType("character varying(128)"); - - b.Property("RequestKey") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.Property("Status") - .IsRequired() - .HasMaxLength(32) - .HasColumnType("character varying(32)"); - - b.HasKey("Id"); - - b.HasIndex("Status") - .HasDatabaseName("IX_intent_tickets_status"); - - b.HasIndex("CapabilityId", "RequestKey") - .IsUnique() - .HasDatabaseName("IX_intent_tickets_capability_request_key"); - - b.ToTable("intent_tickets", (string)null); - }); - - modelBuilder.Entity("EventBusRabbitMQ.Domain.InboxSubscriber", b => - { - b.HasOne("EventBusRabbitMQ.Domain.InboxMessage", "Message") - .WithMany("Subscribers") - .HasForeignKey("MessageId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Message"); - }); - - modelBuilder.Entity("FeatureFusion.Domain.Orders.Order", b => - { - b.HasOne("FeatureFusion.Domain.Customers.Customer", "Customer") - .WithMany() - .HasForeignKey("CustomerId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.Navigation("Customer"); - }); - - modelBuilder.Entity("FeatureFusion.Domain.Orders.OrderItem", b => - { - b.HasOne("FeatureFusion.Domain.Orders.Order", "Order") - .WithMany("Items") - .HasForeignKey("OrderId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("FeatureFusion.Domain.Catalog.Product", "Product") - .WithMany() - .HasForeignKey("ProductId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.Navigation("Order"); - - b.Navigation("Product"); - }); - - modelBuilder.Entity("FeatureFusion.Domain.Catalog.Product", b => - { - b.HasOne("FeatureFusion.Domain.Catalog.Brand", "Brand") - .WithMany() - .HasForeignKey("BrandId") - .OnDelete(DeleteBehavior.Restrict); - - b.HasOne("FeatureFusion.Domain.Catalog.Category", "Category") - .WithMany() - .HasForeignKey("CategoryId") - .OnDelete(DeleteBehavior.Restrict); - - b.Navigation("Brand"); - - b.Navigation("Category"); - }); - - modelBuilder.Entity("EventBusRabbitMQ.Domain.InboxMessage", b => - { - b.Navigation("Subscribers"); - }); - - modelBuilder.Entity("FeatureFusion.Domain.Orders.Order", b => - { - b.Navigation("Items"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/src/Lab/FeatureFusion/Infrastructure/Migrations/20260904205214_DemoCommerceFoundation.cs b/src/Lab/FeatureFusion/Infrastructure/Migrations/20260904205214_DemoCommerceFoundation.cs deleted file mode 100644 index 3d58cab..0000000 --- a/src/Lab/FeatureFusion/Infrastructure/Migrations/20260904205214_DemoCommerceFoundation.cs +++ /dev/null @@ -1,312 +0,0 @@ -using System; -using Microsoft.EntityFrameworkCore.Migrations; -using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; - -#nullable disable - -namespace FeatureFusion.Infrastructure.Migrations -{ - /// - public partial class DemoCommerceFoundation : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.AlterColumn( - name: "Price", - table: "products", - type: "numeric(18,2)", - precision: 18, - scale: 2, - nullable: false, - oldClrType: typeof(decimal), - oldType: "numeric"); - - migrationBuilder.AlterColumn( - name: "Name", - table: "products", - type: "character varying(256)", - maxLength: 256, - nullable: false, - defaultValue: "", - oldClrType: typeof(string), - oldType: "text", - oldNullable: true); - - migrationBuilder.AddColumn( - name: "BrandId", - table: "products", - type: "integer", - nullable: true); - - migrationBuilder.AddColumn( - name: "CategoryId", - table: "products", - type: "integer", - nullable: true); - - migrationBuilder.AddColumn( - name: "Sku", - table: "products", - type: "character varying(64)", - maxLength: 64, - nullable: true); - - migrationBuilder.AddColumn( - name: "StockQuantity", - table: "products", - type: "integer", - nullable: false, - defaultValue: 0); - - migrationBuilder.CreateTable( - name: "brands", - columns: table => new - { - Id = table.Column(type: "integer", nullable: false) - .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), - Name = table.Column(type: "character varying(128)", maxLength: 128, nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_brands", x => x.Id); - }); - - migrationBuilder.CreateTable( - name: "categories", - columns: table => new - { - Id = table.Column(type: "integer", nullable: false) - .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), - Name = table.Column(type: "character varying(128)", maxLength: 128, nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_categories", x => x.Id); - }); - - migrationBuilder.CreateTable( - name: "customers", - columns: table => new - { - Id = table.Column(type: "integer", nullable: false) - .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), - Email = table.Column(type: "character varying(256)", maxLength: 256, nullable: false), - DisplayName = table.Column(type: "character varying(200)", maxLength: 200, nullable: false), - CreatedAt = table.Column(type: "timestamp with time zone", nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_customers", x => x.Id); - }); - - migrationBuilder.CreateTable( - name: "orders", - columns: table => new - { - Id = table.Column(type: "integer", nullable: false) - .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), - OrderNumber = table.Column(type: "character varying(32)", maxLength: 32, nullable: false), - CustomerId = table.Column(type: "integer", nullable: false), - Status = table.Column(type: "character varying(32)", maxLength: 32, nullable: false), - Total = table.Column(type: "numeric(18,2)", precision: 18, scale: 2, nullable: false), - Currency = table.Column(type: "character varying(3)", maxLength: 3, nullable: false), - CreatedAt = table.Column(type: "timestamp with time zone", nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_orders", x => x.Id); - table.ForeignKey( - name: "FK_orders_customers_CustomerId", - column: x => x.CustomerId, - principalTable: "customers", - principalColumn: "Id", - onDelete: ReferentialAction.Restrict); - }); - - migrationBuilder.CreateTable( - name: "order_items", - columns: table => new - { - Id = table.Column(type: "integer", nullable: false) - .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), - OrderId = table.Column(type: "integer", nullable: false), - ProductId = table.Column(type: "integer", nullable: false), - Quantity = table.Column(type: "integer", nullable: false), - UnitPrice = table.Column(type: "numeric(18,2)", precision: 18, scale: 2, nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_order_items", x => x.Id); - table.ForeignKey( - name: "FK_order_items_orders_OrderId", - column: x => x.OrderId, - principalTable: "orders", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - table.ForeignKey( - name: "FK_order_items_products_ProductId", - column: x => x.ProductId, - principalTable: "products", - principalColumn: "Id", - onDelete: ReferentialAction.Restrict); - }); - - migrationBuilder.CreateIndex( - name: "IX_products_brand_id", - table: "products", - column: "BrandId"); - - migrationBuilder.CreateIndex( - name: "IX_products_category_id", - table: "products", - column: "CategoryId"); - - migrationBuilder.CreateIndex( - name: "IX_products_sku", - table: "products", - column: "Sku", - unique: true, - filter: "\"Sku\" IS NOT NULL"); - - migrationBuilder.CreateIndex( - name: "IX_brands_Name", - table: "brands", - column: "Name", - unique: true); - - migrationBuilder.CreateIndex( - name: "IX_categories_Name", - table: "categories", - column: "Name", - unique: true); - - migrationBuilder.CreateIndex( - name: "IX_customers_email", - table: "customers", - column: "Email", - unique: true); - - migrationBuilder.CreateIndex( - name: "IX_order_items_order_id", - table: "order_items", - column: "OrderId"); - - migrationBuilder.CreateIndex( - name: "IX_order_items_product_id", - table: "order_items", - column: "ProductId"); - - migrationBuilder.CreateIndex( - name: "IX_orders_created_at", - table: "orders", - column: "CreatedAt"); - - migrationBuilder.CreateIndex( - name: "IX_orders_customer_id", - table: "orders", - column: "CustomerId"); - - migrationBuilder.CreateIndex( - name: "IX_orders_OrderNumber", - table: "orders", - column: "OrderNumber", - unique: true); - - migrationBuilder.CreateIndex( - name: "IX_orders_status", - table: "orders", - column: "Status"); - - migrationBuilder.AddForeignKey( - name: "FK_products_brands_BrandId", - table: "products", - column: "BrandId", - principalTable: "brands", - principalColumn: "Id", - onDelete: ReferentialAction.Restrict); - - migrationBuilder.AddForeignKey( - name: "FK_products_categories_CategoryId", - table: "products", - column: "CategoryId", - principalTable: "categories", - principalColumn: "Id", - onDelete: ReferentialAction.Restrict); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropForeignKey( - name: "FK_products_brands_BrandId", - table: "products"); - - migrationBuilder.DropForeignKey( - name: "FK_products_categories_CategoryId", - table: "products"); - - migrationBuilder.DropTable( - name: "brands"); - - migrationBuilder.DropTable( - name: "categories"); - - migrationBuilder.DropTable( - name: "order_items"); - - migrationBuilder.DropTable( - name: "orders"); - - migrationBuilder.DropTable( - name: "customers"); - - migrationBuilder.DropIndex( - name: "IX_products_brand_id", - table: "products"); - - migrationBuilder.DropIndex( - name: "IX_products_category_id", - table: "products"); - - migrationBuilder.DropIndex( - name: "IX_products_sku", - table: "products"); - - migrationBuilder.DropColumn( - name: "BrandId", - table: "products"); - - migrationBuilder.DropColumn( - name: "CategoryId", - table: "products"); - - migrationBuilder.DropColumn( - name: "Sku", - table: "products"); - - migrationBuilder.DropColumn( - name: "StockQuantity", - table: "products"); - - migrationBuilder.AlterColumn( - name: "Price", - table: "products", - type: "numeric", - nullable: false, - oldClrType: typeof(decimal), - oldType: "numeric(18,2)", - oldPrecision: 18, - oldScale: 2); - - migrationBuilder.AlterColumn( - name: "Name", - table: "products", - type: "text", - nullable: true, - oldClrType: typeof(string), - oldType: "character varying(256)", - oldMaxLength: 256); - } - } -} diff --git a/src/Lab/FeatureFusion/Infrastructure/Migrations/20260904220000_IntentTickets.cs b/src/Lab/FeatureFusion/Infrastructure/Migrations/20260904220000_IntentTickets.cs deleted file mode 100644 index 0b0b216..0000000 --- a/src/Lab/FeatureFusion/Infrastructure/Migrations/20260904220000_IntentTickets.cs +++ /dev/null @@ -1,56 +0,0 @@ -using System; -using FeatureFusion.Infrastructure.Context; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; - -#nullable disable - -namespace FeatureFusion.Infrastructure.Migrations -{ - [DbContext(typeof(CatalogDbContext))] - [Migration("20260904220000_IntentTickets")] - public partial class IntentTickets : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.CreateTable( - name: "intent_tickets", - columns: table => new - { - Id = table.Column(type: "uuid", nullable: false), - CapabilityId = table.Column(type: "character varying(128)", maxLength: 128, nullable: false), - RequestKey = table.Column(type: "character varying(256)", maxLength: 256, nullable: false), - IntentHash = table.Column(type: "character varying(128)", maxLength: 128, nullable: false), - IntentPayload = table.Column(type: "text", nullable: false), - Status = table.Column(type: "character varying(32)", maxLength: 32, nullable: false), - CreatedAt = table.Column(type: "timestamp with time zone", nullable: false), - ExpiresAt = table.Column(type: "timestamp with time zone", nullable: false), - ReleasedAt = table.Column(type: "timestamp with time zone", nullable: true), - ReleasedBy = table.Column(type: "character varying(128)", maxLength: 128, nullable: true), - ExecutionOrderId = table.Column(type: "uuid", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_intent_tickets", x => x.Id); - }); - - migrationBuilder.CreateIndex( - name: "IX_intent_tickets_capability_request_key", - table: "intent_tickets", - columns: new[] { "CapabilityId", "RequestKey" }, - unique: true); - - migrationBuilder.CreateIndex( - name: "IX_intent_tickets_status", - table: "intent_tickets", - column: "Status"); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropTable(name: "intent_tickets"); - } - } -} diff --git a/src/Lab/FeatureFusion/Infrastructure/Migrations/20260904222603_CatalogStorefront.Designer.cs b/src/Lab/FeatureFusion/Infrastructure/Migrations/20260904222603_CatalogStorefront.Designer.cs deleted file mode 100644 index 8c55bce..0000000 --- a/src/Lab/FeatureFusion/Infrastructure/Migrations/20260904222603_CatalogStorefront.Designer.cs +++ /dev/null @@ -1,711 +0,0 @@ -// -using System; -using FeatureFusion.Infrastructure.Context; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; - -#nullable disable - -namespace FeatureFusion.Infrastructure.Migrations -{ - [DbContext(typeof(CatalogDbContext))] - [Migration("20260904222603_CatalogStorefront")] - partial class CatalogStorefront - { - /// - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "10.0.10") - .HasAnnotation("Relational:MaxIdentifierLength", 63); - - NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); - - modelBuilder.Entity("EventBusRabbitMQ.Domain.InboxMessage", b => - { - b.Property("Id") - .HasColumnType("uuid"); - - b.Property("CompletedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("Error") - .HasMaxLength(500) - .HasColumnType("character varying(500)"); - - b.Property("EventType") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.Property("IsProcessed") - .HasColumnType("boolean"); - - b.Property("Payload") - .IsRequired() - .HasColumnType("bytea"); - - b.Property("ProcessedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("RowVersion") - .IsConcurrencyToken() - .ValueGeneratedOnAddOrUpdate() - .HasColumnType("xid") - .HasColumnName("xmin"); - - b.Property("ServiceName") - .IsRequired() - .HasMaxLength(200) - .HasColumnType("character varying(200)"); - - b.Property("Status") - .IsRequired() - .HasMaxLength(20) - .HasColumnType("character varying(20)"); - - b.HasKey("Id"); - - b.HasIndex("Id") - .IsUnique(); - - b.ToTable("inbox_messages", (string)null); - }); - - modelBuilder.Entity("EventBusRabbitMQ.Domain.InboxSubscriber", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("Attempts") - .ValueGeneratedOnAdd() - .HasColumnType("integer") - .HasDefaultValue(0); - - b.Property("Error") - .HasMaxLength(500) - .HasColumnType("character varying(500)"); - - b.Property("LastAttemptedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("MessageId") - .HasColumnType("uuid"); - - b.Property("RowVersion") - .IsConcurrencyToken() - .ValueGeneratedOnAddOrUpdate() - .HasColumnType("xid") - .HasColumnName("xmin"); - - b.Property("Status") - .IsRequired() - .HasMaxLength(20) - .HasColumnType("character varying(20)"); - - b.Property("SubscriberName") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.HasKey("Id"); - - b.HasIndex("Status"); - - b.HasIndex("MessageId", "SubscriberName") - .IsUnique(); - - b.ToTable("inbox_subscribers", (string)null); - }); - - modelBuilder.Entity("EventBusRabbitMQ.Domain.OutboxMessage", b => - { - b.Property("Id") - .HasColumnType("uuid") - .HasColumnName("id"); - - b.Property("CompletedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("CreatedAt") - .HasColumnType("timestamptz") - .HasColumnName("created_at"); - - b.Property("Error") - .HasMaxLength(500) - .HasColumnType("character varying(500)"); - - b.Property("EventType") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)") - .HasColumnName("event_type"); - - b.PrimitiveCollection("Payload") - .IsRequired() - .HasColumnType("jsonb") - .HasColumnName("payload"); - - b.Property("ProcessedAt") - .HasColumnType("timestamptz") - .HasColumnName("processed_at"); - - b.Property("RetryCount") - .ValueGeneratedOnAdd() - .HasColumnType("integer") - .HasDefaultValue(0) - .HasColumnName("retry_count"); - - b.Property("Status") - .IsRequired() - .HasMaxLength(20) - .HasColumnType("character varying(20)") - .HasColumnName("status"); - - b.HasKey("Id") - .HasName("pk_outbox_messages"); - - b.HasIndex("CreatedAt") - .HasDatabaseName("ix_outbox_messages_unprocessed") - .HasFilter("processed_at IS NULL"); - - NpgsqlIndexBuilderExtensions.IncludeProperties(b.HasIndex("CreatedAt"), new[] { "Id", "EventType", "Payload" }); - - b.HasIndex("Status", "RetryCount", "CreatedAt") - .HasDatabaseName("ix_outbox_messages_status_retry_created") - .HasFilter("status IN ('Pending', 'Failed')"); - - NpgsqlIndexBuilderExtensions.IncludeProperties(b.HasIndex("Status", "RetryCount", "CreatedAt"), new[] { "Id", "EventType", "Payload" }); - - b.ToTable("outbox_messages", (string)null); - }); - - modelBuilder.Entity("EventBusRabbitMQ.Domain.ProcessedMessage", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("ProcessedAt") - .HasColumnType("timestamp with time zone"); - - b.HasKey("Id"); - - b.ToTable("processed_messages", (string)null); - }); - - modelBuilder.Entity("FeatureFusion.Domain.Catalog.Brand", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("LogoUrl") - .HasMaxLength(512) - .HasColumnType("character varying(512)"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(128) - .HasColumnType("character varying(128)"); - - b.Property("Slug") - .IsRequired() - .HasMaxLength(128) - .HasColumnType("character varying(128)"); - - b.HasKey("Id"); - - b.HasIndex("Name") - .IsUnique(); - - b.HasIndex("Slug") - .IsUnique(); - - b.ToTable("brands", (string)null); - }); - - modelBuilder.Entity("FeatureFusion.Domain.Catalog.Category", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("Name") - .IsRequired() - .HasMaxLength(128) - .HasColumnType("character varying(128)"); - - b.Property("Slug") - .IsRequired() - .HasMaxLength(128) - .HasColumnType("character varying(128)"); - - b.HasKey("Id"); - - b.HasIndex("Name") - .IsUnique(); - - b.HasIndex("Slug") - .IsUnique(); - - b.ToTable("categories", (string)null); - }); - - modelBuilder.Entity("FeatureFusion.Domain.Customers.Customer", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("DisplayName") - .IsRequired() - .HasMaxLength(200) - .HasColumnType("character varying(200)"); - - b.Property("Email") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)") - .HasColumnName("Email"); - - b.HasKey("Id"); - - b.HasIndex("Email") - .IsUnique() - .HasDatabaseName("IX_customers_email"); - - b.ToTable("customers", (string)null); - }); - - modelBuilder.Entity("FeatureFusion.Domain.Orders.Order", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("Currency") - .IsRequired() - .HasMaxLength(3) - .HasColumnType("character varying(3)"); - - b.Property("CustomerId") - .HasColumnType("integer"); - - b.Property("OrderNumber") - .IsRequired() - .HasMaxLength(32) - .HasColumnType("character varying(32)"); - - b.Property("Status") - .IsRequired() - .HasMaxLength(32) - .HasColumnType("character varying(32)"); - - b.Property("Total") - .HasPrecision(18, 2) - .HasColumnType("numeric(18,2)"); - - b.HasKey("Id"); - - b.HasIndex("CreatedAt") - .HasDatabaseName("IX_orders_created_at"); - - b.HasIndex("CustomerId") - .HasDatabaseName("IX_orders_customer_id"); - - b.HasIndex("OrderNumber") - .IsUnique(); - - b.HasIndex("Status") - .HasDatabaseName("IX_orders_status"); - - b.ToTable("orders", (string)null); - }); - - modelBuilder.Entity("FeatureFusion.Domain.Orders.OrderItem", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("OrderId") - .HasColumnType("integer"); - - b.Property("ProductId") - .HasColumnType("integer"); - - b.Property("Quantity") - .HasColumnType("integer"); - - b.Property("UnitPrice") - .HasPrecision(18, 2) - .HasColumnType("numeric(18,2)"); - - b.HasKey("Id"); - - b.HasIndex("OrderId") - .HasDatabaseName("IX_order_items_order_id"); - - b.HasIndex("ProductId") - .HasDatabaseName("IX_order_items_product_id"); - - b.ToTable("order_items", (string)null); - }); - - modelBuilder.Entity("FeatureFusion.Domain.Catalog.Product", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("BrandId") - .HasColumnType("integer"); - - b.Property("CategoryId") - .HasColumnType("integer"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("Deleted") - .HasColumnType("boolean"); - - b.Property("FullDescription") - .HasColumnType("text"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.Property("Price") - .HasPrecision(18, 2) - .HasColumnType("numeric(18,2)"); - - b.Property("Published") - .HasColumnType("boolean"); - - b.Property("ShortDescription") - .HasMaxLength(512) - .HasColumnType("character varying(512)"); - - b.Property("Sku") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.Property("Slug") - .IsRequired() - .HasMaxLength(128) - .HasColumnType("character varying(128)"); - - b.Property("StockQuantity") - .HasColumnType("integer"); - - b.Property("VisibleIndividually") - .HasColumnType("boolean"); - - b.HasKey("Id"); - - b.HasIndex("BrandId") - .HasDatabaseName("IX_products_brand_id"); - - b.HasIndex("CategoryId") - .HasDatabaseName("IX_products_category_id"); - - b.HasIndex("CreatedAt") - .IsDescending() - .HasDatabaseName("IX_products_created_at_desc"); - - b.HasIndex("Name") - .HasDatabaseName("IX_products_name"); - - b.HasIndex("Sku") - .IsUnique() - .HasDatabaseName("IX_products_sku"); - - b.HasIndex("Slug") - .IsUnique() - .HasDatabaseName("IX_products_slug"); - - b.HasIndex(new[] { "CreatedAt", "Id" }, "IX_Product_CreatedAt_Id_AA") - .HasDatabaseName("IX_products_created_at_id"); - - b.HasIndex(new[] { "CreatedAt", "Id" }, "IX_Product_CreatedAt_Id_DA") - .IsDescending(true, false) - .HasDatabaseName("IX_products_created_at_id_desc"); - - b.HasIndex(new[] { "Name", "Id" }, "IX_Product_Name_Id_AA") - .HasDatabaseName("IX_products_name_id"); - - b.HasIndex(new[] { "Name", "Id" }, "IX_Product_Name_Id_DA") - .IsDescending(true, false) - .HasDatabaseName("IX_products_name_id_desc"); - - b.HasIndex(new[] { "Name", "Price", "Id" }, "IX_Product_Name_Price_Id_AAA") - .HasDatabaseName("IX_products_name_price_id"); - - b.HasIndex(new[] { "Name", "Price", "Id" }, "IX_Product_Name_Price_Id_DDD") - .IsDescending() - .HasDatabaseName("IX_products_name_price_id_desc"); - - b.HasIndex(new[] { "Price", "Id" }, "IX_Product_Price_Id_AA") - .HasDatabaseName("IX_products_price_id"); - - b.HasIndex(new[] { "Price", "Id" }, "IX_Product_Price_Id_DA") - .IsDescending(true, false) - .HasDatabaseName("IX_products_price_id_desc"); - - b.ToTable("products", (string)null); - }); - - modelBuilder.Entity("FeatureFusion.Domain.Catalog.ProductImage", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("AltText") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.Property("DisplayOrder") - .HasColumnType("integer"); - - b.Property("IsPrimary") - .HasColumnType("boolean"); - - b.Property("ProductId") - .HasColumnType("integer"); - - b.Property("Url") - .IsRequired() - .HasMaxLength(512) - .HasColumnType("character varying(512)"); - - b.HasKey("Id"); - - b.HasIndex("ProductId") - .HasDatabaseName("IX_product_images_product_id"); - - b.ToTable("product_images", (string)null); - }); - - modelBuilder.Entity("FeatureFusion.Domain.Catalog.ProductSpecification", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("DisplayOrder") - .HasColumnType("integer"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(128) - .HasColumnType("character varying(128)"); - - b.Property("ProductId") - .HasColumnType("integer"); - - b.Property("Value") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.HasKey("Id"); - - b.HasIndex("ProductId") - .HasDatabaseName("IX_product_specifications_product_id"); - - b.ToTable("product_specifications", (string)null); - }); - - modelBuilder.Entity("FeatureFusion.Features.Admission.IntentTicket", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("CapabilityId") - .IsRequired() - .HasMaxLength(128) - .HasColumnType("character varying(128)"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("ExecutionOrderId") - .HasColumnType("uuid"); - - b.Property("ExpiresAt") - .HasColumnType("timestamp with time zone"); - - b.Property("IntentHash") - .IsRequired() - .HasMaxLength(128) - .HasColumnType("character varying(128)"); - - b.Property("IntentPayload") - .IsRequired() - .HasColumnType("text"); - - b.Property("ReleasedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("ReleasedBy") - .HasMaxLength(128) - .HasColumnType("character varying(128)"); - - b.Property("RequestKey") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.Property("Status") - .IsRequired() - .HasMaxLength(32) - .HasColumnType("character varying(32)"); - - b.HasKey("Id"); - - b.HasIndex("Status") - .HasDatabaseName("IX_intent_tickets_status"); - - b.HasIndex("CapabilityId", "RequestKey") - .IsUnique() - .HasDatabaseName("IX_intent_tickets_capability_request_key"); - - b.ToTable("intent_tickets", (string)null); - }); - - modelBuilder.Entity("EventBusRabbitMQ.Domain.InboxSubscriber", b => - { - b.HasOne("EventBusRabbitMQ.Domain.InboxMessage", "Message") - .WithMany("Subscribers") - .HasForeignKey("MessageId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Message"); - }); - - modelBuilder.Entity("FeatureFusion.Domain.Orders.Order", b => - { - b.HasOne("FeatureFusion.Domain.Customers.Customer", "Customer") - .WithMany() - .HasForeignKey("CustomerId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.Navigation("Customer"); - }); - - modelBuilder.Entity("FeatureFusion.Domain.Orders.OrderItem", b => - { - b.HasOne("FeatureFusion.Domain.Orders.Order", "Order") - .WithMany("Items") - .HasForeignKey("OrderId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("FeatureFusion.Domain.Catalog.Product", "Product") - .WithMany() - .HasForeignKey("ProductId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.Navigation("Order"); - - b.Navigation("Product"); - }); - - modelBuilder.Entity("FeatureFusion.Domain.Catalog.Product", b => - { - b.HasOne("FeatureFusion.Domain.Catalog.Brand", "Brand") - .WithMany() - .HasForeignKey("BrandId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.HasOne("FeatureFusion.Domain.Catalog.Category", "Category") - .WithMany() - .HasForeignKey("CategoryId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.Navigation("Brand"); - - b.Navigation("Category"); - }); - - modelBuilder.Entity("FeatureFusion.Domain.Catalog.ProductImage", b => - { - b.HasOne("FeatureFusion.Domain.Catalog.Product", null) - .WithMany("Images") - .HasForeignKey("ProductId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("FeatureFusion.Domain.Catalog.ProductSpecification", b => - { - b.HasOne("FeatureFusion.Domain.Catalog.Product", null) - .WithMany("Specifications") - .HasForeignKey("ProductId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("EventBusRabbitMQ.Domain.InboxMessage", b => - { - b.Navigation("Subscribers"); - }); - - modelBuilder.Entity("FeatureFusion.Domain.Orders.Order", b => - { - b.Navigation("Items"); - }); - - modelBuilder.Entity("FeatureFusion.Domain.Catalog.Product", b => - { - b.Navigation("Images"); - - b.Navigation("Specifications"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/src/Lab/FeatureFusion/Infrastructure/Migrations/20260904222603_CatalogStorefront.cs b/src/Lab/FeatureFusion/Infrastructure/Migrations/20260904222603_CatalogStorefront.cs deleted file mode 100644 index ff1a8b0..0000000 --- a/src/Lab/FeatureFusion/Infrastructure/Migrations/20260904222603_CatalogStorefront.cs +++ /dev/null @@ -1,286 +0,0 @@ -using Microsoft.EntityFrameworkCore.Migrations; -using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; - -#nullable disable - -namespace FeatureFusion.Infrastructure.Migrations -{ - /// - public partial class CatalogStorefront : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropIndex( - name: "IX_products_sku", - table: "products"); - - // Leftover CatalogInit products have NULL BrandId/CategoryId. EF's AlterColumn - // backfill uses 0, which is not a real brand/category (FK 23503). - migrationBuilder.Sql( - """ - INSERT INTO categories ("Name") - SELECT 'Uncategorized' - WHERE EXISTS (SELECT 1 FROM products WHERE "CategoryId" IS NULL) - AND NOT EXISTS (SELECT 1 FROM categories); - - INSERT INTO brands ("Name") - SELECT 'Unknown' - WHERE EXISTS (SELECT 1 FROM products WHERE "BrandId" IS NULL) - AND NOT EXISTS (SELECT 1 FROM brands); - - UPDATE products - SET "CategoryId" = (SELECT MIN("Id") FROM categories) - WHERE "CategoryId" IS NULL; - - UPDATE products - SET "BrandId" = (SELECT MIN("Id") FROM brands) - WHERE "BrandId" IS NULL; - - UPDATE products - SET "Sku" = 'SKU-LEGACY-' || "Id"::text - WHERE "Sku" IS NULL OR BTRIM("Sku") = ''; - """); - - migrationBuilder.AlterColumn( - name: "Sku", - table: "products", - type: "character varying(64)", - maxLength: 64, - nullable: false, - oldClrType: typeof(string), - oldType: "character varying(64)", - oldMaxLength: 64, - oldNullable: true); - - migrationBuilder.AlterColumn( - name: "CategoryId", - table: "products", - type: "integer", - nullable: false, - oldClrType: typeof(int), - oldType: "integer", - oldNullable: true); - - migrationBuilder.AlterColumn( - name: "BrandId", - table: "products", - type: "integer", - nullable: false, - oldClrType: typeof(int), - oldType: "integer", - oldNullable: true); - - migrationBuilder.AddColumn( - name: "ShortDescription", - table: "products", - type: "character varying(512)", - maxLength: 512, - nullable: true); - - migrationBuilder.AddColumn( - name: "Slug", - table: "products", - type: "character varying(128)", - maxLength: 128, - nullable: false, - defaultValue: ""); - - migrationBuilder.AddColumn( - name: "Slug", - table: "categories", - type: "character varying(128)", - maxLength: 128, - nullable: false, - defaultValue: ""); - - migrationBuilder.AddColumn( - name: "LogoUrl", - table: "brands", - type: "character varying(512)", - maxLength: 512, - nullable: true); - - migrationBuilder.AddColumn( - name: "Slug", - table: "brands", - type: "character varying(128)", - maxLength: 128, - nullable: false, - defaultValue: ""); - - migrationBuilder.Sql( - """ - UPDATE products - SET "Slug" = 'product-' || "Id"::text - WHERE "Slug" IS NULL OR BTRIM("Slug") = ''; - - UPDATE categories - SET "Slug" = 'category-' || "Id"::text - WHERE "Slug" IS NULL OR BTRIM("Slug") = ''; - - UPDATE brands - SET "Slug" = 'brand-' || "Id"::text - WHERE "Slug" IS NULL OR BTRIM("Slug") = ''; - """); - - migrationBuilder.CreateTable( - name: "product_images", - columns: table => new - { - Id = table.Column(type: "integer", nullable: false) - .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), - ProductId = table.Column(type: "integer", nullable: false), - Url = table.Column(type: "character varying(512)", maxLength: 512, nullable: false), - AltText = table.Column(type: "character varying(256)", maxLength: 256, nullable: false), - DisplayOrder = table.Column(type: "integer", nullable: false), - IsPrimary = table.Column(type: "boolean", nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_product_images", x => x.Id); - table.ForeignKey( - name: "FK_product_images_products_ProductId", - column: x => x.ProductId, - principalTable: "products", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "product_specifications", - columns: table => new - { - Id = table.Column(type: "integer", nullable: false) - .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), - ProductId = table.Column(type: "integer", nullable: false), - Name = table.Column(type: "character varying(128)", maxLength: 128, nullable: false), - Value = table.Column(type: "character varying(256)", maxLength: 256, nullable: false), - DisplayOrder = table.Column(type: "integer", nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_product_specifications", x => x.Id); - table.ForeignKey( - name: "FK_product_specifications_products_ProductId", - column: x => x.ProductId, - principalTable: "products", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateIndex( - name: "IX_products_sku", - table: "products", - column: "Sku", - unique: true); - - migrationBuilder.CreateIndex( - name: "IX_products_slug", - table: "products", - column: "Slug", - unique: true); - - migrationBuilder.CreateIndex( - name: "IX_categories_Slug", - table: "categories", - column: "Slug", - unique: true); - - migrationBuilder.CreateIndex( - name: "IX_brands_Slug", - table: "brands", - column: "Slug", - unique: true); - - migrationBuilder.CreateIndex( - name: "IX_product_images_product_id", - table: "product_images", - column: "ProductId"); - - migrationBuilder.CreateIndex( - name: "IX_product_specifications_product_id", - table: "product_specifications", - column: "ProductId"); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropTable( - name: "product_images"); - - migrationBuilder.DropTable( - name: "product_specifications"); - - migrationBuilder.DropIndex( - name: "IX_products_sku", - table: "products"); - - migrationBuilder.DropIndex( - name: "IX_products_slug", - table: "products"); - - migrationBuilder.DropIndex( - name: "IX_categories_Slug", - table: "categories"); - - migrationBuilder.DropIndex( - name: "IX_brands_Slug", - table: "brands"); - - migrationBuilder.DropColumn( - name: "ShortDescription", - table: "products"); - - migrationBuilder.DropColumn( - name: "Slug", - table: "products"); - - migrationBuilder.DropColumn( - name: "Slug", - table: "categories"); - - migrationBuilder.DropColumn( - name: "LogoUrl", - table: "brands"); - - migrationBuilder.DropColumn( - name: "Slug", - table: "brands"); - - migrationBuilder.AlterColumn( - name: "Sku", - table: "products", - type: "character varying(64)", - maxLength: 64, - nullable: true, - oldClrType: typeof(string), - oldType: "character varying(64)", - oldMaxLength: 64); - - migrationBuilder.AlterColumn( - name: "CategoryId", - table: "products", - type: "integer", - nullable: true, - oldClrType: typeof(int), - oldType: "integer"); - - migrationBuilder.AlterColumn( - name: "BrandId", - table: "products", - type: "integer", - nullable: true, - oldClrType: typeof(int), - oldType: "integer"); - - migrationBuilder.CreateIndex( - name: "IX_products_sku", - table: "products", - column: "Sku", - unique: true, - filter: "\"Sku\" IS NOT NULL"); - } - } -} diff --git a/src/Lab/FeatureFusion/Infrastructure/Migrations/20260908091824_DemoCommerceCheckout.Designer.cs b/src/Lab/FeatureFusion/Infrastructure/Migrations/20260908091824_DemoCommerceCheckout.Designer.cs deleted file mode 100644 index a1c378b..0000000 --- a/src/Lab/FeatureFusion/Infrastructure/Migrations/20260908091824_DemoCommerceCheckout.Designer.cs +++ /dev/null @@ -1,891 +0,0 @@ -// -using System; -using FeatureFusion.Infrastructure.Context; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; - -#nullable disable - -namespace FeatureFusion.Infrastructure.Migrations -{ - [DbContext(typeof(CatalogDbContext))] - [Migration("20260908091824_DemoCommerceCheckout")] - partial class DemoCommerceCheckout - { - /// - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "10.0.10") - .HasAnnotation("Relational:MaxIdentifierLength", 63); - - NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); - - modelBuilder.Entity("EventBusRabbitMQ.Domain.InboxMessage", b => - { - b.Property("Id") - .HasColumnType("uuid"); - - b.Property("CompletedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("Error") - .HasMaxLength(500) - .HasColumnType("character varying(500)"); - - b.Property("EventType") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.Property("IsProcessed") - .HasColumnType("boolean"); - - b.Property("Payload") - .IsRequired() - .HasColumnType("bytea"); - - b.Property("ProcessedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("RowVersion") - .IsConcurrencyToken() - .ValueGeneratedOnAddOrUpdate() - .HasColumnType("xid") - .HasColumnName("xmin"); - - b.Property("ServiceName") - .IsRequired() - .HasMaxLength(200) - .HasColumnType("character varying(200)"); - - b.Property("Status") - .IsRequired() - .HasMaxLength(20) - .HasColumnType("character varying(20)"); - - b.HasKey("Id"); - - b.HasIndex("Id") - .IsUnique(); - - b.ToTable("inbox_messages", (string)null); - }); - - modelBuilder.Entity("EventBusRabbitMQ.Domain.InboxSubscriber", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("Attempts") - .ValueGeneratedOnAdd() - .HasColumnType("integer") - .HasDefaultValue(0); - - b.Property("Error") - .HasMaxLength(500) - .HasColumnType("character varying(500)"); - - b.Property("LastAttemptedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("MessageId") - .HasColumnType("uuid"); - - b.Property("RowVersion") - .IsConcurrencyToken() - .ValueGeneratedOnAddOrUpdate() - .HasColumnType("xid") - .HasColumnName("xmin"); - - b.Property("Status") - .IsRequired() - .HasMaxLength(20) - .HasColumnType("character varying(20)"); - - b.Property("SubscriberName") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.HasKey("Id"); - - b.HasIndex("Status"); - - b.HasIndex("MessageId", "SubscriberName") - .IsUnique(); - - b.ToTable("inbox_subscribers", (string)null); - }); - - modelBuilder.Entity("EventBusRabbitMQ.Domain.OutboxMessage", b => - { - b.Property("Id") - .HasColumnType("uuid") - .HasColumnName("id"); - - b.Property("CompletedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("CreatedAt") - .HasColumnType("timestamptz") - .HasColumnName("created_at"); - - b.Property("Error") - .HasMaxLength(500) - .HasColumnType("character varying(500)"); - - b.Property("EventType") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)") - .HasColumnName("event_type"); - - b.PrimitiveCollection("Payload") - .IsRequired() - .HasColumnType("jsonb") - .HasColumnName("payload"); - - b.Property("ProcessedAt") - .HasColumnType("timestamptz") - .HasColumnName("processed_at"); - - b.Property("RetryCount") - .ValueGeneratedOnAdd() - .HasColumnType("integer") - .HasDefaultValue(0) - .HasColumnName("retry_count"); - - b.Property("Status") - .IsRequired() - .HasMaxLength(20) - .HasColumnType("character varying(20)") - .HasColumnName("status"); - - b.HasKey("Id") - .HasName("pk_outbox_messages"); - - b.HasIndex("CreatedAt") - .HasDatabaseName("ix_outbox_messages_unprocessed") - .HasFilter("processed_at IS NULL"); - - NpgsqlIndexBuilderExtensions.IncludeProperties(b.HasIndex("CreatedAt"), new[] { "Id", "EventType", "Payload" }); - - b.HasIndex("Status", "RetryCount", "CreatedAt") - .HasDatabaseName("ix_outbox_messages_status_retry_created") - .HasFilter("status IN ('Pending', 'Failed')"); - - NpgsqlIndexBuilderExtensions.IncludeProperties(b.HasIndex("Status", "RetryCount", "CreatedAt"), new[] { "Id", "EventType", "Payload" }); - - b.ToTable("outbox_messages", (string)null); - }); - - modelBuilder.Entity("EventBusRabbitMQ.Domain.ProcessedMessage", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("ProcessedAt") - .HasColumnType("timestamp with time zone"); - - b.HasKey("Id"); - - b.ToTable("processed_messages", (string)null); - }); - - modelBuilder.Entity("FeatureFusion.Domain.Carts.Cart", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("CustomerId") - .HasColumnType("integer"); - - b.Property("UpdatedAtUtc") - .HasColumnType("timestamp with time zone"); - - b.HasKey("Id"); - - b.HasIndex("CustomerId") - .IsUnique() - .HasDatabaseName("IX_carts_customer_id"); - - b.ToTable("carts", (string)null); - }); - - modelBuilder.Entity("FeatureFusion.Domain.Carts.CartItem", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("CartId") - .HasColumnType("integer"); - - b.Property("ProductId") - .HasColumnType("integer"); - - b.Property("Quantity") - .HasColumnType("integer"); - - b.HasKey("Id"); - - b.HasIndex("CartId", "ProductId") - .IsUnique() - .HasDatabaseName("IX_cart_items_cart_product"); - - b.ToTable("cart_items", (string)null); - }); - - modelBuilder.Entity("FeatureFusion.Domain.Catalog.Brand", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("LogoUrl") - .HasMaxLength(512) - .HasColumnType("character varying(512)"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(128) - .HasColumnType("character varying(128)"); - - b.Property("Slug") - .IsRequired() - .HasMaxLength(128) - .HasColumnType("character varying(128)"); - - b.HasKey("Id"); - - b.HasIndex("Name") - .IsUnique(); - - b.HasIndex("Slug") - .IsUnique(); - - b.ToTable("brands", (string)null); - }); - - modelBuilder.Entity("FeatureFusion.Domain.Catalog.Category", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("Name") - .IsRequired() - .HasMaxLength(128) - .HasColumnType("character varying(128)"); - - b.Property("Slug") - .IsRequired() - .HasMaxLength(128) - .HasColumnType("character varying(128)"); - - b.HasKey("Id"); - - b.HasIndex("Name") - .IsUnique(); - - b.HasIndex("Slug") - .IsUnique(); - - b.ToTable("categories", (string)null); - }); - - modelBuilder.Entity("FeatureFusion.Domain.Catalog.Product", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("BrandId") - .HasColumnType("integer"); - - b.Property("CategoryId") - .HasColumnType("integer"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("Deleted") - .HasColumnType("boolean"); - - b.Property("FullDescription") - .HasColumnType("text"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.Property("Price") - .HasPrecision(18, 2) - .HasColumnType("numeric(18,2)"); - - b.Property("Published") - .HasColumnType("boolean"); - - b.Property("ShortDescription") - .HasMaxLength(512) - .HasColumnType("character varying(512)"); - - b.Property("Sku") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.Property("Slug") - .IsRequired() - .HasMaxLength(128) - .HasColumnType("character varying(128)"); - - b.Property("StockQuantity") - .HasColumnType("integer"); - - b.Property("VisibleIndividually") - .HasColumnType("boolean"); - - b.Property("xmin") - .IsConcurrencyToken() - .ValueGeneratedOnAddOrUpdate() - .HasColumnType("xid") - .HasColumnName("xmin"); - - b.HasKey("Id"); - - b.HasIndex("BrandId") - .HasDatabaseName("IX_products_brand_id"); - - b.HasIndex("CategoryId") - .HasDatabaseName("IX_products_category_id"); - - b.HasIndex("CreatedAt") - .IsDescending() - .HasDatabaseName("IX_products_created_at_desc"); - - b.HasIndex("Name") - .HasDatabaseName("IX_products_name"); - - b.HasIndex("Sku") - .IsUnique() - .HasDatabaseName("IX_products_sku"); - - b.HasIndex("Slug") - .IsUnique() - .HasDatabaseName("IX_products_slug"); - - b.HasIndex(new[] { "CreatedAt", "Id" }, "IX_Product_CreatedAt_Id_AA") - .HasDatabaseName("IX_products_created_at_id"); - - b.HasIndex(new[] { "CreatedAt", "Id" }, "IX_Product_CreatedAt_Id_DA") - .IsDescending(true, false) - .HasDatabaseName("IX_products_created_at_id_desc"); - - b.HasIndex(new[] { "Name", "Id" }, "IX_Product_Name_Id_AA") - .HasDatabaseName("IX_products_name_id"); - - b.HasIndex(new[] { "Name", "Id" }, "IX_Product_Name_Id_DA") - .IsDescending(true, false) - .HasDatabaseName("IX_products_name_id_desc"); - - b.HasIndex(new[] { "Name", "Price", "Id" }, "IX_Product_Name_Price_Id_AAA") - .HasDatabaseName("IX_products_name_price_id"); - - b.HasIndex(new[] { "Name", "Price", "Id" }, "IX_Product_Name_Price_Id_DDD") - .IsDescending() - .HasDatabaseName("IX_products_name_price_id_desc"); - - b.HasIndex(new[] { "Price", "Id" }, "IX_Product_Price_Id_AA") - .HasDatabaseName("IX_products_price_id"); - - b.HasIndex(new[] { "Price", "Id" }, "IX_Product_Price_Id_DA") - .IsDescending(true, false) - .HasDatabaseName("IX_products_price_id_desc"); - - b.ToTable("products", (string)null); - }); - - modelBuilder.Entity("FeatureFusion.Domain.Catalog.ProductImage", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("AltText") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.Property("DisplayOrder") - .HasColumnType("integer"); - - b.Property("IsPrimary") - .HasColumnType("boolean"); - - b.Property("ProductId") - .HasColumnType("integer"); - - b.Property("Url") - .IsRequired() - .HasMaxLength(512) - .HasColumnType("character varying(512)"); - - b.HasKey("Id"); - - b.HasIndex("ProductId") - .HasDatabaseName("IX_product_images_product_id"); - - b.ToTable("product_images", (string)null); - }); - - modelBuilder.Entity("FeatureFusion.Domain.Catalog.ProductSpecification", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("DisplayOrder") - .HasColumnType("integer"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(128) - .HasColumnType("character varying(128)"); - - b.Property("ProductId") - .HasColumnType("integer"); - - b.Property("Value") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.HasKey("Id"); - - b.HasIndex("ProductId") - .HasDatabaseName("IX_product_specifications_product_id"); - - b.ToTable("product_specifications", (string)null); - }); - - modelBuilder.Entity("FeatureFusion.Domain.Customers.Customer", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("DisplayName") - .IsRequired() - .HasMaxLength(200) - .HasColumnType("character varying(200)"); - - b.Property("Email") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)") - .HasColumnName("Email"); - - b.HasKey("Id"); - - b.HasIndex("Email") - .IsUnique() - .HasDatabaseName("IX_customers_email"); - - b.ToTable("customers", (string)null); - }); - - modelBuilder.Entity("FeatureFusion.Domain.Orders.Order", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("Currency") - .IsRequired() - .HasMaxLength(3) - .HasColumnType("character varying(3)"); - - b.Property("CustomerId") - .HasColumnType("integer"); - - b.Property("OrderNumber") - .IsRequired() - .HasMaxLength(32) - .HasColumnType("character varying(32)"); - - b.Property("ShippingAmount") - .HasPrecision(18, 2) - .HasColumnType("numeric(18,2)"); - - b.Property("Status") - .IsRequired() - .HasMaxLength(32) - .HasColumnType("character varying(32)"); - - b.Property("Subtotal") - .HasPrecision(18, 2) - .HasColumnType("numeric(18,2)"); - - b.Property("TaxAmount") - .HasPrecision(18, 2) - .HasColumnType("numeric(18,2)"); - - b.Property("Total") - .HasPrecision(18, 2) - .HasColumnType("numeric(18,2)"); - - b.HasKey("Id"); - - b.HasIndex("CreatedAt") - .HasDatabaseName("IX_orders_created_at"); - - b.HasIndex("CustomerId") - .HasDatabaseName("IX_orders_customer_id"); - - b.HasIndex("OrderNumber") - .IsUnique(); - - b.HasIndex("Status") - .HasDatabaseName("IX_orders_status"); - - b.ToTable("orders", (string)null); - }); - - modelBuilder.Entity("FeatureFusion.Domain.Orders.OrderItem", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("OrderId") - .HasColumnType("integer"); - - b.Property("ProductId") - .HasColumnType("integer"); - - b.Property("Quantity") - .HasColumnType("integer"); - - b.Property("UnitPrice") - .HasPrecision(18, 2) - .HasColumnType("numeric(18,2)"); - - b.HasKey("Id"); - - b.HasIndex("OrderId") - .HasDatabaseName("IX_order_items_order_id"); - - b.HasIndex("ProductId") - .HasDatabaseName("IX_order_items_product_id"); - - b.ToTable("order_items", (string)null); - }); - - modelBuilder.Entity("FeatureFusion.Domain.Payments.PaymentRecord", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("Amount") - .HasPrecision(18, 2) - .HasColumnType("numeric(18,2)"); - - b.Property("CorrelationOrderId") - .HasColumnType("uuid"); - - b.Property("CreatedAtUtc") - .HasColumnType("timestamp with time zone"); - - b.Property("Currency") - .IsRequired() - .HasMaxLength(3) - .HasColumnType("character varying(3)"); - - b.Property("DomainOrderId") - .HasColumnType("integer"); - - b.Property("Outcome") - .IsRequired() - .HasMaxLength(32) - .HasColumnType("character varying(32)"); - - b.HasKey("Id"); - - b.HasIndex("CorrelationOrderId") - .HasDatabaseName("IX_payment_records_correlation"); - - b.ToTable("payment_records", (string)null); - }); - - modelBuilder.Entity("FeatureFusion.Features.Admission.IntentTicket", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("CapabilityId") - .IsRequired() - .HasMaxLength(128) - .HasColumnType("character varying(128)"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("ExecutionOrderId") - .HasColumnType("uuid"); - - b.Property("ExpiresAt") - .HasColumnType("timestamp with time zone"); - - b.Property("IntentHash") - .IsRequired() - .HasMaxLength(128) - .HasColumnType("character varying(128)"); - - b.Property("IntentPayload") - .IsRequired() - .HasColumnType("text"); - - b.Property("ReleasedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("ReleasedBy") - .HasMaxLength(128) - .HasColumnType("character varying(128)"); - - b.Property("RequestKey") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.Property("Status") - .IsRequired() - .HasMaxLength(32) - .HasColumnType("character varying(32)"); - - b.HasKey("Id"); - - b.HasIndex("Status") - .HasDatabaseName("IX_intent_tickets_status"); - - b.HasIndex("CapabilityId", "RequestKey") - .IsUnique() - .HasDatabaseName("IX_intent_tickets_capability_request_key"); - - b.ToTable("intent_tickets", (string)null); - }); - - modelBuilder.Entity("EventBusRabbitMQ.Domain.InboxSubscriber", b => - { - b.HasOne("EventBusRabbitMQ.Domain.InboxMessage", "Message") - .WithMany("Subscribers") - .HasForeignKey("MessageId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Message"); - }); - - modelBuilder.Entity("FeatureFusion.Domain.Carts.CartItem", b => - { - b.HasOne("FeatureFusion.Domain.Carts.Cart", "Cart") - .WithMany("Items") - .HasForeignKey("CartId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Cart"); - }); - - modelBuilder.Entity("FeatureFusion.Domain.Catalog.Product", b => - { - b.HasOne("FeatureFusion.Domain.Catalog.Brand", "Brand") - .WithMany() - .HasForeignKey("BrandId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.HasOne("FeatureFusion.Domain.Catalog.Category", "Category") - .WithMany() - .HasForeignKey("CategoryId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.Navigation("Brand"); - - b.Navigation("Category"); - }); - - modelBuilder.Entity("FeatureFusion.Domain.Catalog.ProductImage", b => - { - b.HasOne("FeatureFusion.Domain.Catalog.Product", null) - .WithMany("Images") - .HasForeignKey("ProductId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("FeatureFusion.Domain.Catalog.ProductSpecification", b => - { - b.HasOne("FeatureFusion.Domain.Catalog.Product", null) - .WithMany("Specifications") - .HasForeignKey("ProductId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("FeatureFusion.Domain.Orders.Order", b => - { - b.HasOne("FeatureFusion.Domain.Customers.Customer", "Customer") - .WithMany() - .HasForeignKey("CustomerId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.OwnsOne("FeatureFusion.Domain.Orders.OrderShipping", "Shipping", b1 => - { - b1.Property("OrderId") - .HasColumnType("integer"); - - b1.Property("City") - .IsRequired() - .HasMaxLength(128) - .HasColumnType("character varying(128)") - .HasColumnName("shipping_city"); - - b1.Property("Country") - .IsRequired() - .HasMaxLength(2) - .HasColumnType("character varying(2)") - .HasColumnName("shipping_country"); - - b1.Property("Line1") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)") - .HasColumnName("shipping_line1"); - - b1.Property("Method") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)") - .HasColumnName("shipping_method"); - - b1.Property("PostalCode") - .IsRequired() - .HasMaxLength(32) - .HasColumnType("character varying(32)") - .HasColumnName("shipping_postal"); - - b1.Property("RecipientName") - .IsRequired() - .HasMaxLength(128) - .HasColumnType("character varying(128)") - .HasColumnName("shipping_recipient"); - - b1.Property("Status") - .IsRequired() - .HasMaxLength(32) - .HasColumnType("character varying(32)") - .HasColumnName("shipping_status"); - - b1.HasKey("OrderId"); - - b1.ToTable("orders"); - - b1.WithOwner() - .HasForeignKey("OrderId"); - }); - - b.Navigation("Customer"); - - b.Navigation("Shipping") - .IsRequired(); - }); - - modelBuilder.Entity("FeatureFusion.Domain.Orders.OrderItem", b => - { - b.HasOne("FeatureFusion.Domain.Orders.Order", "Order") - .WithMany("Items") - .HasForeignKey("OrderId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("FeatureFusion.Domain.Catalog.Product", "Product") - .WithMany() - .HasForeignKey("ProductId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.Navigation("Order"); - - b.Navigation("Product"); - }); - - modelBuilder.Entity("EventBusRabbitMQ.Domain.InboxMessage", b => - { - b.Navigation("Subscribers"); - }); - - modelBuilder.Entity("FeatureFusion.Domain.Carts.Cart", b => - { - b.Navigation("Items"); - }); - - modelBuilder.Entity("FeatureFusion.Domain.Catalog.Product", b => - { - b.Navigation("Images"); - - b.Navigation("Specifications"); - }); - - modelBuilder.Entity("FeatureFusion.Domain.Orders.Order", b => - { - b.Navigation("Items"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/src/Lab/FeatureFusion/Infrastructure/Migrations/20260908091824_DemoCommerceCheckout.cs b/src/Lab/FeatureFusion/Infrastructure/Migrations/20260908091824_DemoCommerceCheckout.cs deleted file mode 100644 index f996c51..0000000 --- a/src/Lab/FeatureFusion/Infrastructure/Migrations/20260908091824_DemoCommerceCheckout.cs +++ /dev/null @@ -1,234 +0,0 @@ -using System; -using Microsoft.EntityFrameworkCore.Migrations; -using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; - -#nullable disable - -namespace FeatureFusion.Infrastructure.Migrations -{ - /// - public partial class DemoCommerceCheckout : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.AddColumn( - name: "xmin", - table: "products", - type: "xid", - rowVersion: true, - nullable: false, - defaultValue: 0u); - - migrationBuilder.AddColumn( - name: "ShippingAmount", - table: "orders", - type: "numeric(18,2)", - precision: 18, - scale: 2, - nullable: false, - defaultValue: 0m); - - migrationBuilder.AddColumn( - name: "Subtotal", - table: "orders", - type: "numeric(18,2)", - precision: 18, - scale: 2, - nullable: false, - defaultValue: 0m); - - migrationBuilder.AddColumn( - name: "TaxAmount", - table: "orders", - type: "numeric(18,2)", - precision: 18, - scale: 2, - nullable: false, - defaultValue: 0m); - - migrationBuilder.AddColumn( - name: "shipping_city", - table: "orders", - type: "character varying(128)", - maxLength: 128, - nullable: false, - defaultValue: ""); - - migrationBuilder.AddColumn( - name: "shipping_country", - table: "orders", - type: "character varying(2)", - maxLength: 2, - nullable: false, - defaultValue: ""); - - migrationBuilder.AddColumn( - name: "shipping_line1", - table: "orders", - type: "character varying(256)", - maxLength: 256, - nullable: false, - defaultValue: ""); - - migrationBuilder.AddColumn( - name: "shipping_method", - table: "orders", - type: "character varying(64)", - maxLength: 64, - nullable: false, - defaultValue: ""); - - migrationBuilder.AddColumn( - name: "shipping_postal", - table: "orders", - type: "character varying(32)", - maxLength: 32, - nullable: false, - defaultValue: ""); - - migrationBuilder.AddColumn( - name: "shipping_recipient", - table: "orders", - type: "character varying(128)", - maxLength: 128, - nullable: false, - defaultValue: ""); - - migrationBuilder.AddColumn( - name: "shipping_status", - table: "orders", - type: "character varying(32)", - maxLength: 32, - nullable: false, - defaultValue: ""); - - migrationBuilder.CreateTable( - name: "carts", - columns: table => new - { - Id = table.Column(type: "integer", nullable: false) - .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), - CustomerId = table.Column(type: "integer", nullable: false), - UpdatedAtUtc = table.Column(type: "timestamp with time zone", nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_carts", x => x.Id); - }); - - migrationBuilder.CreateTable( - name: "payment_records", - columns: table => new - { - Id = table.Column(type: "integer", nullable: false) - .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), - CorrelationOrderId = table.Column(type: "uuid", nullable: false), - DomainOrderId = table.Column(type: "integer", nullable: true), - Outcome = table.Column(type: "character varying(32)", maxLength: 32, nullable: false), - Amount = table.Column(type: "numeric(18,2)", precision: 18, scale: 2, nullable: false), - Currency = table.Column(type: "character varying(3)", maxLength: 3, nullable: false), - CreatedAtUtc = table.Column(type: "timestamp with time zone", nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_payment_records", x => x.Id); - }); - - migrationBuilder.CreateTable( - name: "cart_items", - columns: table => new - { - Id = table.Column(type: "integer", nullable: false) - .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), - CartId = table.Column(type: "integer", nullable: false), - ProductId = table.Column(type: "integer", nullable: false), - Quantity = table.Column(type: "integer", nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_cart_items", x => x.Id); - table.ForeignKey( - name: "FK_cart_items_carts_CartId", - column: x => x.CartId, - principalTable: "carts", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateIndex( - name: "IX_cart_items_cart_product", - table: "cart_items", - columns: new[] { "CartId", "ProductId" }, - unique: true); - - migrationBuilder.CreateIndex( - name: "IX_carts_customer_id", - table: "carts", - column: "CustomerId", - unique: true); - - migrationBuilder.CreateIndex( - name: "IX_payment_records_correlation", - table: "payment_records", - column: "CorrelationOrderId"); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropTable( - name: "cart_items"); - - migrationBuilder.DropTable( - name: "payment_records"); - - migrationBuilder.DropTable( - name: "carts"); - - migrationBuilder.DropColumn( - name: "xmin", - table: "products"); - - migrationBuilder.DropColumn( - name: "ShippingAmount", - table: "orders"); - - migrationBuilder.DropColumn( - name: "Subtotal", - table: "orders"); - - migrationBuilder.DropColumn( - name: "TaxAmount", - table: "orders"); - - migrationBuilder.DropColumn( - name: "shipping_city", - table: "orders"); - - migrationBuilder.DropColumn( - name: "shipping_country", - table: "orders"); - - migrationBuilder.DropColumn( - name: "shipping_line1", - table: "orders"); - - migrationBuilder.DropColumn( - name: "shipping_method", - table: "orders"); - - migrationBuilder.DropColumn( - name: "shipping_postal", - table: "orders"); - - migrationBuilder.DropColumn( - name: "shipping_recipient", - table: "orders"); - - migrationBuilder.DropColumn( - name: "shipping_status", - table: "orders"); - } - } -} diff --git a/src/Lab/FeatureFusion/Infrastructure/Migrations/20260908092920_ProductOriginalVersionConcurrency.cs b/src/Lab/FeatureFusion/Infrastructure/Migrations/20260908092920_ProductOriginalVersionConcurrency.cs deleted file mode 100644 index d6a8cb1..0000000 --- a/src/Lab/FeatureFusion/Infrastructure/Migrations/20260908092920_ProductOriginalVersionConcurrency.cs +++ /dev/null @@ -1,41 +0,0 @@ -using Microsoft.EntityFrameworkCore.Migrations; - -#nullable disable - -namespace FeatureFusion.Infrastructure.Migrations -{ - /// - public partial class ProductOriginalVersionConcurrency : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropColumn( - name: "xmin", - table: "products"); - - migrationBuilder.AddColumn( - name: "OriginalVersion", - table: "products", - type: "bigint", - nullable: false, - defaultValue: 0L); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropColumn( - name: "OriginalVersion", - table: "products"); - - migrationBuilder.AddColumn( - name: "xmin", - table: "products", - type: "xid", - rowVersion: true, - nullable: false, - defaultValue: 0u); - } - } -} diff --git a/src/Lab/FeatureFusion/Infrastructure/Migrations/20260908092920_ProductOriginalVersionConcurrency.Designer.cs b/src/Lab/FeatureFusion/Infrastructure/Migrations/20260913180808_DemoCommerceInitial.Designer.cs similarity index 99% rename from src/Lab/FeatureFusion/Infrastructure/Migrations/20260908092920_ProductOriginalVersionConcurrency.Designer.cs rename to src/Lab/FeatureFusion/Infrastructure/Migrations/20260913180808_DemoCommerceInitial.Designer.cs index ad6dd8a..4d75022 100644 --- a/src/Lab/FeatureFusion/Infrastructure/Migrations/20260908092920_ProductOriginalVersionConcurrency.Designer.cs +++ b/src/Lab/FeatureFusion/Infrastructure/Migrations/20260913180808_DemoCommerceInitial.Designer.cs @@ -12,8 +12,8 @@ namespace FeatureFusion.Infrastructure.Migrations { [DbContext(typeof(CatalogDbContext))] - [Migration("20260908092920_ProductOriginalVersionConcurrency")] - partial class ProductOriginalVersionConcurrency + [Migration("20260913180808_DemoCommerceInitial")] + partial class DemoCommerceInitial { /// protected override void BuildTargetModel(ModelBuilder modelBuilder) diff --git a/src/Lab/FeatureFusion/Infrastructure/Migrations/20260913180808_DemoCommerceInitial.cs b/src/Lab/FeatureFusion/Infrastructure/Migrations/20260913180808_DemoCommerceInitial.cs new file mode 100644 index 0000000..4150d50 --- /dev/null +++ b/src/Lab/FeatureFusion/Infrastructure/Migrations/20260913180808_DemoCommerceInitial.cs @@ -0,0 +1,614 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace FeatureFusion.Infrastructure.Migrations +{ + /// + public partial class DemoCommerceInitial : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "brands", + columns: table => new + { + Id = table.Column(type: "integer", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + Name = table.Column(type: "character varying(128)", maxLength: 128, nullable: false), + Slug = table.Column(type: "character varying(128)", maxLength: 128, nullable: false), + LogoUrl = table.Column(type: "character varying(512)", maxLength: 512, nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_brands", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "carts", + columns: table => new + { + Id = table.Column(type: "integer", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + CustomerId = table.Column(type: "integer", nullable: false), + UpdatedAtUtc = table.Column(type: "timestamp with time zone", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_carts", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "categories", + columns: table => new + { + Id = table.Column(type: "integer", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + Name = table.Column(type: "character varying(128)", maxLength: 128, nullable: false), + Slug = table.Column(type: "character varying(128)", maxLength: 128, nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_categories", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "customers", + columns: table => new + { + Id = table.Column(type: "integer", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + Email = table.Column(type: "character varying(256)", maxLength: 256, nullable: false), + DisplayName = table.Column(type: "character varying(200)", maxLength: 200, nullable: false), + CreatedAt = table.Column(type: "timestamp with time zone", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_customers", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "inbox_messages", + columns: table => new + { + Id = table.Column(type: "uuid", nullable: false), + ServiceName = table.Column(type: "character varying(200)", maxLength: 200, nullable: false), + IsProcessed = table.Column(type: "boolean", nullable: false), + xmin = table.Column(type: "xid", rowVersion: true, nullable: false), + EventType = table.Column(type: "character varying(256)", maxLength: 256, nullable: false), + Payload = table.Column(type: "bytea", nullable: false), + CreatedAt = table.Column(type: "timestamp with time zone", nullable: false), + ProcessedAt = table.Column(type: "timestamp with time zone", nullable: true), + CompletedAt = table.Column(type: "timestamp with time zone", nullable: true), + Status = table.Column(type: "character varying(20)", maxLength: 20, nullable: false), + Error = table.Column(type: "character varying(500)", maxLength: 500, nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_inbox_messages", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "intent_tickets", + columns: table => new + { + Id = table.Column(type: "uuid", nullable: false), + CapabilityId = table.Column(type: "character varying(128)", maxLength: 128, nullable: false), + RequestKey = table.Column(type: "character varying(256)", maxLength: 256, nullable: false), + IntentHash = table.Column(type: "character varying(128)", maxLength: 128, nullable: false), + IntentPayload = table.Column(type: "text", nullable: false), + Status = table.Column(type: "character varying(32)", maxLength: 32, nullable: false), + CreatedAt = table.Column(type: "timestamp with time zone", nullable: false), + ExpiresAt = table.Column(type: "timestamp with time zone", nullable: false), + ReleasedAt = table.Column(type: "timestamp with time zone", nullable: true), + ReleasedBy = table.Column(type: "character varying(128)", maxLength: 128, nullable: true), + ExecutionOrderId = table.Column(type: "uuid", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_intent_tickets", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "outbox_messages", + columns: table => new + { + id = table.Column(type: "uuid", nullable: false), + retry_count = table.Column(type: "integer", nullable: false, defaultValue: 0), + event_type = table.Column(type: "character varying(256)", maxLength: 256, nullable: false), + payload = table.Column(type: "jsonb", nullable: false), + created_at = table.Column(type: "timestamptz", nullable: false), + processed_at = table.Column(type: "timestamptz", nullable: true), + CompletedAt = table.Column(type: "timestamp with time zone", nullable: true), + status = table.Column(type: "character varying(20)", maxLength: 20, nullable: false), + Error = table.Column(type: "character varying(500)", maxLength: 500, nullable: true) + }, + constraints: table => + { + table.PrimaryKey("pk_outbox_messages", x => x.id); + }); + + migrationBuilder.CreateTable( + name: "payment_records", + columns: table => new + { + Id = table.Column(type: "integer", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + CorrelationOrderId = table.Column(type: "uuid", nullable: false), + DomainOrderId = table.Column(type: "integer", nullable: true), + Outcome = table.Column(type: "character varying(32)", maxLength: 32, nullable: false), + Amount = table.Column(type: "numeric(18,2)", precision: 18, scale: 2, nullable: false), + Currency = table.Column(type: "character varying(3)", maxLength: 3, nullable: false), + CreatedAtUtc = table.Column(type: "timestamp with time zone", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_payment_records", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "processed_messages", + columns: table => new + { + Id = table.Column(type: "uuid", nullable: false), + ProcessedAt = table.Column(type: "timestamp with time zone", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_processed_messages", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "cart_items", + columns: table => new + { + Id = table.Column(type: "integer", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + CartId = table.Column(type: "integer", nullable: false), + ProductId = table.Column(type: "integer", nullable: false), + Quantity = table.Column(type: "integer", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_cart_items", x => x.Id); + table.ForeignKey( + name: "FK_cart_items_carts_CartId", + column: x => x.CartId, + principalTable: "carts", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "products", + columns: table => new + { + Id = table.Column(type: "integer", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + Name = table.Column(type: "character varying(256)", maxLength: 256, nullable: false), + Sku = table.Column(type: "character varying(64)", maxLength: 64, nullable: false), + Slug = table.Column(type: "character varying(128)", maxLength: 128, nullable: false), + ShortDescription = table.Column(type: "character varying(512)", maxLength: 512, nullable: true), + FullDescription = table.Column(type: "text", nullable: true), + Published = table.Column(type: "boolean", nullable: false), + Deleted = table.Column(type: "boolean", nullable: false), + VisibleIndividually = table.Column(type: "boolean", nullable: false), + Price = table.Column(type: "numeric(18,2)", precision: 18, scale: 2, nullable: false), + StockQuantity = table.Column(type: "integer", nullable: false), + BrandId = table.Column(type: "integer", nullable: false), + CategoryId = table.Column(type: "integer", nullable: false), + CreatedAt = table.Column(type: "timestamp with time zone", nullable: false), + OriginalVersion = table.Column(type: "bigint", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_products", x => x.Id); + table.ForeignKey( + name: "FK_products_brands_BrandId", + column: x => x.BrandId, + principalTable: "brands", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + table.ForeignKey( + name: "FK_products_categories_CategoryId", + column: x => x.CategoryId, + principalTable: "categories", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + }); + + migrationBuilder.CreateTable( + name: "orders", + columns: table => new + { + Id = table.Column(type: "integer", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + OrderNumber = table.Column(type: "character varying(32)", maxLength: 32, nullable: false), + CustomerId = table.Column(type: "integer", nullable: false), + Status = table.Column(type: "character varying(32)", maxLength: 32, nullable: false), + Subtotal = table.Column(type: "numeric(18,2)", precision: 18, scale: 2, nullable: false), + TaxAmount = table.Column(type: "numeric(18,2)", precision: 18, scale: 2, nullable: false), + ShippingAmount = table.Column(type: "numeric(18,2)", precision: 18, scale: 2, nullable: false), + Total = table.Column(type: "numeric(18,2)", precision: 18, scale: 2, nullable: false), + Currency = table.Column(type: "character varying(3)", maxLength: 3, nullable: false), + CreatedAt = table.Column(type: "timestamp with time zone", nullable: false), + shipping_recipient = table.Column(type: "character varying(128)", maxLength: 128, nullable: false), + shipping_line1 = table.Column(type: "character varying(256)", maxLength: 256, nullable: false), + shipping_city = table.Column(type: "character varying(128)", maxLength: 128, nullable: false), + shipping_postal = table.Column(type: "character varying(32)", maxLength: 32, nullable: false), + shipping_country = table.Column(type: "character varying(2)", maxLength: 2, nullable: false), + shipping_method = table.Column(type: "character varying(64)", maxLength: 64, nullable: false), + shipping_status = table.Column(type: "character varying(32)", maxLength: 32, nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_orders", x => x.Id); + table.ForeignKey( + name: "FK_orders_customers_CustomerId", + column: x => x.CustomerId, + principalTable: "customers", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + }); + + migrationBuilder.CreateTable( + name: "inbox_subscribers", + columns: table => new + { + Id = table.Column(type: "uuid", nullable: false), + SubscriberName = table.Column(type: "character varying(256)", maxLength: 256, nullable: false), + MessageId = table.Column(type: "uuid", nullable: false), + Status = table.Column(type: "character varying(20)", maxLength: 20, nullable: false), + Attempts = table.Column(type: "integer", nullable: false, defaultValue: 0), + LastAttemptedAt = table.Column(type: "timestamp with time zone", nullable: true), + Error = table.Column(type: "character varying(500)", maxLength: 500, nullable: true), + xmin = table.Column(type: "xid", rowVersion: true, nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_inbox_subscribers", x => x.Id); + table.ForeignKey( + name: "FK_inbox_subscribers_inbox_messages_MessageId", + column: x => x.MessageId, + principalTable: "inbox_messages", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "product_images", + columns: table => new + { + Id = table.Column(type: "integer", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + ProductId = table.Column(type: "integer", nullable: false), + Url = table.Column(type: "character varying(512)", maxLength: 512, nullable: false), + AltText = table.Column(type: "character varying(256)", maxLength: 256, nullable: false), + DisplayOrder = table.Column(type: "integer", nullable: false), + IsPrimary = table.Column(type: "boolean", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_product_images", x => x.Id); + table.ForeignKey( + name: "FK_product_images_products_ProductId", + column: x => x.ProductId, + principalTable: "products", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "product_specifications", + columns: table => new + { + Id = table.Column(type: "integer", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + ProductId = table.Column(type: "integer", nullable: false), + Name = table.Column(type: "character varying(128)", maxLength: 128, nullable: false), + Value = table.Column(type: "character varying(256)", maxLength: 256, nullable: false), + DisplayOrder = table.Column(type: "integer", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_product_specifications", x => x.Id); + table.ForeignKey( + name: "FK_product_specifications_products_ProductId", + column: x => x.ProductId, + principalTable: "products", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "order_items", + columns: table => new + { + Id = table.Column(type: "integer", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + OrderId = table.Column(type: "integer", nullable: false), + ProductId = table.Column(type: "integer", nullable: false), + Quantity = table.Column(type: "integer", nullable: false), + UnitPrice = table.Column(type: "numeric(18,2)", precision: 18, scale: 2, nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_order_items", x => x.Id); + table.ForeignKey( + name: "FK_order_items_orders_OrderId", + column: x => x.OrderId, + principalTable: "orders", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_order_items_products_ProductId", + column: x => x.ProductId, + principalTable: "products", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + }); + + migrationBuilder.CreateIndex( + name: "IX_brands_Name", + table: "brands", + column: "Name", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_brands_Slug", + table: "brands", + column: "Slug", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_cart_items_cart_product", + table: "cart_items", + columns: new[] { "CartId", "ProductId" }, + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_carts_customer_id", + table: "carts", + column: "CustomerId", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_categories_Name", + table: "categories", + column: "Name", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_categories_Slug", + table: "categories", + column: "Slug", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_customers_email", + table: "customers", + column: "Email", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_inbox_messages_Id", + table: "inbox_messages", + column: "Id", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_inbox_subscribers_MessageId_SubscriberName", + table: "inbox_subscribers", + columns: new[] { "MessageId", "SubscriberName" }, + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_inbox_subscribers_Status", + table: "inbox_subscribers", + column: "Status"); + + migrationBuilder.CreateIndex( + name: "IX_intent_tickets_capability_request_key", + table: "intent_tickets", + columns: new[] { "CapabilityId", "RequestKey" }, + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_intent_tickets_status", + table: "intent_tickets", + column: "Status"); + + migrationBuilder.CreateIndex( + name: "IX_order_items_order_id", + table: "order_items", + column: "OrderId"); + + migrationBuilder.CreateIndex( + name: "IX_order_items_product_id", + table: "order_items", + column: "ProductId"); + + migrationBuilder.CreateIndex( + name: "IX_orders_created_at", + table: "orders", + column: "CreatedAt"); + + migrationBuilder.CreateIndex( + name: "IX_orders_customer_id", + table: "orders", + column: "CustomerId"); + + migrationBuilder.CreateIndex( + name: "IX_orders_OrderNumber", + table: "orders", + column: "OrderNumber", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_orders_status", + table: "orders", + column: "Status"); + + migrationBuilder.CreateIndex( + name: "ix_outbox_messages_status_retry_created", + table: "outbox_messages", + columns: new[] { "status", "retry_count", "created_at" }, + filter: "status IN ('Pending', 'Failed')") + .Annotation("Npgsql:IndexInclude", new[] { "id", "event_type", "payload" }); + + migrationBuilder.CreateIndex( + name: "ix_outbox_messages_unprocessed", + table: "outbox_messages", + column: "created_at", + filter: "processed_at IS NULL") + .Annotation("Npgsql:IndexInclude", new[] { "id", "event_type", "payload" }); + + migrationBuilder.CreateIndex( + name: "IX_payment_records_correlation", + table: "payment_records", + column: "CorrelationOrderId"); + + migrationBuilder.CreateIndex( + name: "IX_product_images_product_id", + table: "product_images", + column: "ProductId"); + + migrationBuilder.CreateIndex( + name: "IX_product_specifications_product_id", + table: "product_specifications", + column: "ProductId"); + + migrationBuilder.CreateIndex( + name: "IX_products_brand_id", + table: "products", + column: "BrandId"); + + migrationBuilder.CreateIndex( + name: "IX_products_category_id", + table: "products", + column: "CategoryId"); + + migrationBuilder.CreateIndex( + name: "IX_products_created_at_desc", + table: "products", + column: "CreatedAt", + descending: new bool[0]); + + migrationBuilder.CreateIndex( + name: "IX_products_created_at_id", + table: "products", + columns: new[] { "CreatedAt", "Id" }); + + migrationBuilder.CreateIndex( + name: "IX_products_created_at_id_desc", + table: "products", + columns: new[] { "CreatedAt", "Id" }, + descending: new[] { true, false }); + + migrationBuilder.CreateIndex( + name: "IX_products_name", + table: "products", + column: "Name"); + + migrationBuilder.CreateIndex( + name: "IX_products_name_id", + table: "products", + columns: new[] { "Name", "Id" }); + + migrationBuilder.CreateIndex( + name: "IX_products_name_id_desc", + table: "products", + columns: new[] { "Name", "Id" }, + descending: new[] { true, false }); + + migrationBuilder.CreateIndex( + name: "IX_products_name_price_id", + table: "products", + columns: new[] { "Name", "Price", "Id" }); + + migrationBuilder.CreateIndex( + name: "IX_products_name_price_id_desc", + table: "products", + columns: new[] { "Name", "Price", "Id" }, + descending: new bool[0]); + + migrationBuilder.CreateIndex( + name: "IX_products_price_id", + table: "products", + columns: new[] { "Price", "Id" }); + + migrationBuilder.CreateIndex( + name: "IX_products_price_id_desc", + table: "products", + columns: new[] { "Price", "Id" }, + descending: new[] { true, false }); + + migrationBuilder.CreateIndex( + name: "IX_products_sku", + table: "products", + column: "Sku", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_products_slug", + table: "products", + column: "Slug", + unique: true); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "cart_items"); + + migrationBuilder.DropTable( + name: "inbox_subscribers"); + + migrationBuilder.DropTable( + name: "intent_tickets"); + + migrationBuilder.DropTable( + name: "order_items"); + + migrationBuilder.DropTable( + name: "outbox_messages"); + + migrationBuilder.DropTable( + name: "payment_records"); + + migrationBuilder.DropTable( + name: "processed_messages"); + + migrationBuilder.DropTable( + name: "product_images"); + + migrationBuilder.DropTable( + name: "product_specifications"); + + migrationBuilder.DropTable( + name: "carts"); + + migrationBuilder.DropTable( + name: "inbox_messages"); + + migrationBuilder.DropTable( + name: "orders"); + + migrationBuilder.DropTable( + name: "products"); + + migrationBuilder.DropTable( + name: "customers"); + + migrationBuilder.DropTable( + name: "brands"); + + migrationBuilder.DropTable( + name: "categories"); + } + } +} diff --git a/src/Lab/FeatureFusion/appsettings.Production.json b/src/Lab/FeatureFusion/appsettings.Production.json index c50e7c4..83a4cd4 100644 --- a/src/Lab/FeatureFusion/appsettings.Production.json +++ b/src/Lab/FeatureFusion/appsettings.Production.json @@ -45,7 +45,7 @@ "AllowedHosts": "*", "ConnectionStrings": { "eventbus": "amqp://guest:guest@eventbus:5672/", - "catalogdb": "Host=postgres;Port=5432;Username=username;Password=password;Database=eventstore;" + "catalogdb": "Host=postgres;Port=5432;Username=username;Password=password;Database=catalogdb;" }, "EventBus": { "EnableDeduplication": false, @@ -57,7 +57,7 @@ "Npgsql": { "EntityFrameworkCore": { "PostgreSQL": { - "catalogdb": "Host=postgres;Port=5432;Username=username;Password=password;Database=eventstore;" + "catalogdb": "Host=postgres;Port=5432;Username=username;Password=password;Database=catalogdb;" } } } diff --git a/tests/BuildingBlocks/Pagination.EntityFrameworkCore.Tests/MultiColumnEfTests.cs b/tests/BuildingBlocks/Pagination.EntityFrameworkCore.Tests/MultiColumnEfTests.cs index 3c028bb..e030edd 100644 --- a/tests/BuildingBlocks/Pagination.EntityFrameworkCore.Tests/MultiColumnEfTests.cs +++ b/tests/BuildingBlocks/Pagination.EntityFrameworkCore.Tests/MultiColumnEfTests.cs @@ -119,7 +119,9 @@ public void Nine_Column_Value_Types_Are_Tuple_Eligible() { Assert.True(SeekOps.TupleEligible(CatalogSeed.ByNineValueTypes, walkBackward: false)); Assert.True(SeekOps.TupleSlotsNonNull(CatalogSeed.ByNineValueTypes)); +#pragma warning disable EF1001 // CursorSeekTuple is an internal EF adapter used by the package Assert.True(CursorSeekTuple.CanUse(CatalogSeed.ByNineValueTypes, walkBackward: false)); +#pragma warning restore EF1001 Assert.Equal(9, CatalogSeed.ByNineValueTypes.Slots.Count); } }