From 1227d4d6202b5fb086b64344e81c698837200ee1 Mon Sep 17 00:00:00 2001 From: "Olivier Delmotte (Avanade)" <70886462+odeatavanade@users.noreply.github.com> Date: Tue, 10 Mar 2026 15:12:20 +0000 Subject: [PATCH 1/8] feat: init devcontainer support --- .devcontainer/devcontainer.json | 28 ++++++++++++++++++++++++++++ .github/dependabot.yml | 4 ++++ 2 files changed, 32 insertions(+) create mode 100644 .devcontainer/devcontainer.json diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 000000000..a23906c3e --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,28 @@ +// For format details, see https://aka.ms/devcontainer.json. For config options, see the +// README at: https://github.com/devcontainers/templates/tree/main/src/alpine +{ + "name": "Alpine", + // Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile + "image": "mcr.microsoft.com/devcontainers/base:alpine-3.22", + "features": { + "ghcr.io/devcontainers/features/copilot-cli:1": {}, + "ghcr.io/dotnet/aspire-devcontainer-feature/dotnetaspire:1": {}, + "ghcr.io/daniellindemann/dev-container-features/dotnet-usersecrets-persistence:0": {}, + "ghcr.io/devcontainer-config/features/dot-config:4": {} + } + + // Features to add to the dev container. More info: https://containers.dev/features. + // "features": {}, + + // Use 'forwardPorts' to make a list of ports inside the container available locally. + // "forwardPorts": [], + + // Use 'postCreateCommand' to run commands after the container is created. + // "postCreateCommand": "uname -a", + + // Configure tool-specific properties. + // "customizations": {}, + + // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root. + // "remoteUser": "root" +} diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 992bf5180..802c1dffa 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -4,6 +4,10 @@ registries: type: nuget-feed url: https://api.nuget.org/v3/index.json updates: + - package-ecosystem: "devcontainers" + directory: "/" + schedule: + interval: weekly - package-ecosystem: nuget directory: "/" registries: From 5de27e8cc26b4b8b4cc981d0fa37c221a811dbb9 Mon Sep 17 00:00:00 2001 From: "Olivier Delmotte (Avanade)" <70886462+odeatavanade@users.noreply.github.com> Date: Tue, 10 Mar 2026 15:23:46 +0000 Subject: [PATCH 2/8] fix: remove features --- .devcontainer/devcontainer.json | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index a23906c3e..c5c07ee64 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -6,9 +6,7 @@ "image": "mcr.microsoft.com/devcontainers/base:alpine-3.22", "features": { "ghcr.io/devcontainers/features/copilot-cli:1": {}, - "ghcr.io/dotnet/aspire-devcontainer-feature/dotnetaspire:1": {}, - "ghcr.io/daniellindemann/dev-container-features/dotnet-usersecrets-persistence:0": {}, - "ghcr.io/devcontainer-config/features/dot-config:4": {} + "ghcr.io/dotnet/aspire-devcontainer-feature/dotnetaspire:1": {} } // Features to add to the dev container. More info: https://containers.dev/features. From ca2b52440bc19e9ba21738fd9969d36f8062f871 Mon Sep 17 00:00:00 2001 From: "Olivier Delmotte (Avanade)" <70886462+odeatavanade@users.noreply.github.com> Date: Tue, 10 Mar 2026 15:40:02 +0000 Subject: [PATCH 3/8] feat: add lfs --- .devcontainer/devcontainer.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index c5c07ee64..284d6fb41 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -6,7 +6,8 @@ "image": "mcr.microsoft.com/devcontainers/base:alpine-3.22", "features": { "ghcr.io/devcontainers/features/copilot-cli:1": {}, - "ghcr.io/dotnet/aspire-devcontainer-feature/dotnetaspire:1": {} + "ghcr.io/dotnet/aspire-devcontainer-feature/dotnetaspire:1": {}, + "ghcr.io/devcontainers/features/git-lfs:1": {} } // Features to add to the dev container. More info: https://containers.dev/features. From d29870a6924a2082df580bde419465444dce06d4 Mon Sep 17 00:00:00 2001 From: "Olivier Delmotte (Avanade)" <70886462+odeatavanade@users.noreply.github.com> Date: Tue, 10 Mar 2026 15:52:37 +0000 Subject: [PATCH 4/8] fix: devcontainer.json --- .devcontainer/devcontainer.json | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 284d6fb41..ee456bde5 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,13 +1,16 @@ // For format details, see https://aka.ms/devcontainer.json. For config options, see the -// README at: https://github.com/devcontainers/templates/tree/main/src/alpine +// README at: https://github.com/devcontainers/templates/tree/main/src/ubuntu { - "name": "Alpine", + "name": "Ubuntu", // Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile - "image": "mcr.microsoft.com/devcontainers/base:alpine-3.22", + "image": "mcr.microsoft.com/devcontainers/base:noble", "features": { "ghcr.io/devcontainers/features/copilot-cli:1": {}, + "ghcr.io/devcontainers/features/dotnet:2": {}, + "ghcr.io/devcontainers/features/git-lfs:1": {}, + "ghcr.io/devcontainers/features/powershell:2": {}, "ghcr.io/dotnet/aspire-devcontainer-feature/dotnetaspire:1": {}, - "ghcr.io/devcontainers/features/git-lfs:1": {} + "ghcr.io/daniellindemann/dev-container-features/dotnet-usersecrets-persistence:0": {} } // Features to add to the dev container. More info: https://containers.dev/features. From 896a0b4e4df67630ef52697fed57287c1b0feb0e Mon Sep 17 00:00:00 2001 From: "Olivier Delmotte (Avanade)" <70886462+odeatavanade@users.noreply.github.com> Date: Tue, 10 Mar 2026 15:58:02 +0000 Subject: [PATCH 5/8] feat: init devcontainer Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .devcontainer/devcontainer.json | 30 ++++++++++++++++++++++++++++++ .github/dependabot.yml | 4 ++++ 2 files changed, 34 insertions(+) create mode 100644 .devcontainer/devcontainer.json diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 000000000..ee456bde5 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,30 @@ +// For format details, see https://aka.ms/devcontainer.json. For config options, see the +// README at: https://github.com/devcontainers/templates/tree/main/src/ubuntu +{ + "name": "Ubuntu", + // Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile + "image": "mcr.microsoft.com/devcontainers/base:noble", + "features": { + "ghcr.io/devcontainers/features/copilot-cli:1": {}, + "ghcr.io/devcontainers/features/dotnet:2": {}, + "ghcr.io/devcontainers/features/git-lfs:1": {}, + "ghcr.io/devcontainers/features/powershell:2": {}, + "ghcr.io/dotnet/aspire-devcontainer-feature/dotnetaspire:1": {}, + "ghcr.io/daniellindemann/dev-container-features/dotnet-usersecrets-persistence:0": {} + } + + // Features to add to the dev container. More info: https://containers.dev/features. + // "features": {}, + + // Use 'forwardPorts' to make a list of ports inside the container available locally. + // "forwardPorts": [], + + // Use 'postCreateCommand' to run commands after the container is created. + // "postCreateCommand": "uname -a", + + // Configure tool-specific properties. + // "customizations": {}, + + // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root. + // "remoteUser": "root" +} diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 992bf5180..802c1dffa 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -4,6 +4,10 @@ registries: type: nuget-feed url: https://api.nuget.org/v3/index.json updates: + - package-ecosystem: "devcontainers" + directory: "/" + schedule: + interval: weekly - package-ecosystem: nuget directory: "/" registries: From a2b0c7ffb128750f22c9b7809346dc1e6bea16d8 Mon Sep 17 00:00:00 2001 From: "Olivier Delmotte (Avanade)" <70886462+odeatavanade@users.noreply.github.com> Date: Tue, 10 Mar 2026 16:54:04 +0000 Subject: [PATCH 6/8] feat: add more features to devcontainer --- .devcontainer/devcontainer.json | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index ee456bde5..013bf1c99 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -6,11 +6,18 @@ "image": "mcr.microsoft.com/devcontainers/base:noble", "features": { "ghcr.io/devcontainers/features/copilot-cli:1": {}, - "ghcr.io/devcontainers/features/dotnet:2": {}, + "ghcr.io/devcontainers/features/dotnet:2": { + "version": "10.0", + "additionalVersions": "7.0, 8.0, 9.0" + }, + "ghcr.io/devcontainers/features/azure-cli:1": {}, + "ghcr.io/devcontainers/features/github-cli:1": {}, + "ghcr.io/devcontainers/features/docker-in-docker:2": {}, "ghcr.io/devcontainers/features/git-lfs:1": {}, "ghcr.io/devcontainers/features/powershell:2": {}, "ghcr.io/dotnet/aspire-devcontainer-feature/dotnetaspire:1": {}, - "ghcr.io/daniellindemann/dev-container-features/dotnet-usersecrets-persistence:0": {} + "ghcr.io/daniellindemann/dev-container-features/dotnet-usersecrets-persistence:0": {}, + "ghcr.io/devcontainers/features/terraform:1": {} } // Features to add to the dev container. More info: https://containers.dev/features. From 93509ed759217a12126754bf6589b434883181fb Mon Sep 17 00:00:00 2001 From: "Olivier Delmotte (Avanade)" <70886462+odeatavanade@users.noreply.github.com> Date: Tue, 10 Mar 2026 17:28:28 +0000 Subject: [PATCH 7/8] feat: pre-build solution --- .devcontainer/devcontainer.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 013bf1c99..e6bfc3a78 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -18,7 +18,7 @@ "ghcr.io/dotnet/aspire-devcontainer-feature/dotnetaspire:1": {}, "ghcr.io/daniellindemann/dev-container-features/dotnet-usersecrets-persistence:0": {}, "ghcr.io/devcontainers/features/terraform:1": {} - } + }, // Features to add to the dev container. More info: https://containers.dev/features. // "features": {}, @@ -27,7 +27,7 @@ // "forwardPorts": [], // Use 'postCreateCommand' to run commands after the container is created. - // "postCreateCommand": "uname -a", + "postCreateCommand": "dotnet run eShop.slnx --project src/eShop.AppHost/eShop.AppHost.csproj" // Configure tool-specific properties. // "customizations": {}, From 0663d449737cdf4de3eb51f0fde53a4d8fbd51ca Mon Sep 17 00:00:00 2001 From: Aurelien Tournier Date: Thu, 19 Mar 2026 18:14:34 +0100 Subject: [PATCH 8/8] docs: add project overview and onboarding guide Adds a concise developer onboarding document covering: - Business purpose and main features - Architecture overview with service diagram - Key technologies and frameworks - Repository structure - Important entry points and API endpoints - CI/CD and deployment guidance Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- docs/project-overview.md | 189 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 189 insertions(+) create mode 100644 docs/project-overview.md diff --git a/docs/project-overview.md b/docs/project-overview.md new file mode 100644 index 000000000..96dac14fa --- /dev/null +++ b/docs/project-overview.md @@ -0,0 +1,189 @@ +# eShop – Project Overview & Onboarding Guide + +## Business Purpose + +**eShop** is a reference .NET application implementing a fully functional e-commerce website ("AdventureWorks"). It demonstrates modern **microservices architecture** patterns using **.NET Aspire** and serves as a best-practice blueprint for building scalable, cloud-ready applications. + +--- + +## Main Features + +| Feature | Description | +|---|---| +| Product Catalog | Browse, search, and filter products with AI-powered recommendations | +| Shopping Basket | Cart management backed by Redis | +| Order Processing | Full order lifecycle with grace period and state machine | +| Payment Processing | Event-driven payment handling | +| Authentication | OpenID Connect / JWT via Duende IdentityServer | +| Webhooks | External system integration via webhook subscriptions | +| Web UI | Blazor Interactive Server web application | +| Mobile App | Cross-platform .NET MAUI application | +| AI Integration | Product recommendations via OpenAI / Azure OpenAI / Ollama | + +--- + +## Architecture Overview + +This is a **true microservices architecture** orchestrated by **.NET Aspire**. + +``` +┌─────────────────────────────────────────────────────────────┐ +│ eShop.AppHost │ +│ (.NET Aspire Orchestration Host) │ +└──────────────────────────┬──────────────────────────────────┘ + │ Manages + ┌──────────────────┼──────────────────┐ + ▼ ▼ ▼ +┌──────────────┐ ┌──────────────┐ ┌──────────────────┐ +│ Identity.API │ │ Catalog.API │ │ Basket.API │ +│ (AuthN/Z) │ │ (Products) │ │ (Cart + Redis) │ +└──────────────┘ └──────────────┘ └──────────────────┘ + ┌──────────────────┬──────────────────┐ + ▼ ▼ ▼ +┌──────────────┐ ┌──────────────┐ ┌──────────────────┐ +│ Ordering.API │ │ Webhooks.API │ │ OrderProcessor │ +│ (Orders) │ │ (Webhooks) │ │ PaymentProcessor │ +└──────────────┘ └──────────────┘ └──────────────────┘ + ┌──────────────────┬──────────────────┐ + ▼ ▼ ▼ +┌──────────────┐ ┌──────────────┐ ┌──────────────────┐ +│ WebApp │ │ HybridApp │ │ WebhookClient │ +│ (Blazor) │ │ (MAUI) │ │ (Test Client) │ +└──────────────┘ └──────────────┘ └──────────────────┘ + +Infrastructure: PostgreSQL + pgvector | Redis | RabbitMQ +``` + +### Key Architecture Patterns + +- **CQRS** – Commands/Queries separated via MediatR (see `Ordering.API/Application/`) +- **Domain-Driven Design (DDD)** – Aggregates, Value Objects, Domain Events in `Ordering.Domain` +- **Event-Driven** – Integration events published over RabbitMQ between services +- **Transactional Outbox** – `IntegrationEventLogEF` ensures reliable event delivery +- **Repository Pattern** – Abstracted data access in `Ordering.Infrastructure` +- **gRPC** – High-performance communication for Basket service +- **Idempotency** – Duplicate request detection via `IdentifiedCommand` + +--- + +## Key Technologies & Frameworks + +| Category | Technology | Version | +|---|---|---| +| Runtime | .NET SDK | 10.0 | +| Orchestration | .NET Aspire | 13.1.0 | +| Web Framework | ASP.NET Core / Blazor | 10.0 | +| Mobile | .NET MAUI | Latest | +| CQRS / Mediator | MediatR | 13.0.0 | +| ORM | Entity Framework Core | 10.0.1 | +| Database | PostgreSQL + pgvector | – | +| Cache | Redis | – | +| Message Bus | RabbitMQ | – | +| Identity | Duende IdentityServer | 7.3.2 | +| gRPC | gRPC.AspNetCore | 2.71.0 | +| Validation | FluentValidation | 12.0.0 | +| Observability | OpenTelemetry | 1.14.0 | +| API Versioning | Asp.Versioning | 8.1.0 | +| API Docs | Scalar / OpenAPI | 2.8.6 | +| AI | Azure OpenAI / Ollama | Beta | +| Testing | MSTest + Playwright | – | + +--- + +## Repository Structure + +``` +eShop/ +├── src/ +│ ├── eShop.AppHost/ # ▶ PRIMARY ENTRY POINT – Aspire orchestration +│ ├── eShop.ServiceDefaults/ # Shared service config (health, auth, OpenAPI) +│ ├── Identity.API/ # Authentication & authorization +│ ├── Catalog.API/ # Product catalog + AI recommendations +│ ├── Basket.API/ # Shopping cart (Redis + gRPC) +│ ├── Ordering.API/ # Order management (CQRS, REST) +│ ├── Ordering.Domain/ # DDD aggregates & domain events +│ ├── Ordering.Infrastructure/ # EF Core persistence & repositories +│ ├── Webhooks.API/ # External webhook management +│ ├── OrderProcessor/ # Background: order grace period state machine +│ ├── PaymentProcessor/ # Background: payment event handling +│ ├── WebApp/ # Blazor Interactive Server frontend +│ ├── WebAppComponents/ # Shared Razor component library +│ ├── HybridApp/ # .NET MAUI mobile app +│ ├── ClientApp/ # Mobile client app +│ ├── WebhookClient/ # Webhook test client +│ ├── EventBus/ # Event bus abstraction +│ ├── EventBusRabbitMQ/ # RabbitMQ event bus implementation +│ └── IntegrationEventLogEF/ # Outbox pattern implementation +├── tests/ +│ ├── Basket.UnitTests/ +│ ├── Ordering.UnitTests/ +│ ├── Ordering.FunctionalTests/ +│ ├── Catalog.FunctionalTests/ +│ └── ClientApp.UnitTests/ +├── e2e/ # Playwright end-to-end tests +├── docs/ # Documentation +├── .github/workflows/ # CI/CD pipelines +├── eShop.slnx # Full solution +├── eShop.Web.slnf # Web projects solution filter +├── Directory.Packages.props # Centralized NuGet package versions +└── global.json # SDK version pin +``` + +--- + +## Important Entry Points & Components + +### Starting the Application + +```powershell +dotnet run --project src/eShop.AppHost/eShop.AppHost.csproj +``` + +The **Aspire Dashboard** URL is printed to the console — use it to monitor all services, traces, logs, and metrics. + +### Key Files + +| File | Purpose | +|---|---| +| `src/eShop.AppHost/Program.cs` | Service composition – wires all microservices, databases, and message brokers | +| `src/WebApp/Program.cs` | Blazor web app startup | +| `src/Ordering.API/Application/` | CQRS commands, queries, handlers, and MediatR pipeline behaviors | +| `src/Ordering.Domain/AggregatesModel/` | DDD aggregates: `OrderAggregate`, `BuyerAggregate` | +| `src/EventBusRabbitMQ/RabbitMQEventBus.cs` | Event bus implementation | +| `src/eShop.ServiceDefaults/Extensions.cs` | Common extensions applied to all services | +| `Directory.Packages.props` | Central place to update NuGet dependency versions | + +### Key API Endpoints + +| Service | Endpoint | Description | +|---|---|---| +| Ordering.API | `POST /api/orders/` | Create a new order | +| Ordering.API | `GET /api/orders/{id}` | Get order by ID | +| Ordering.API | `PUT /api/orders/cancel` | Cancel an order | +| Ordering.API | `PUT /api/orders/ship` | Ship an order | +| Catalog.API | `GET /api/catalog/items` | List catalog items | +| Basket.API | gRPC `BasketService` | Manage shopping basket | +| Identity.API | `/.well-known/openid-configuration` | OIDC discovery endpoint | + +--- + +## CI/CD + +| Workflow | Trigger | What it does | +|---|---|---| +| `pr-validation.yml` | PR / push to `main` | Build + test all web projects | +| `pr-validation-maui.yml` | PR / push to `main` | Build + test MAUI app | +| `playwright.yml` | Scheduled / manual | End-to-end browser tests | +| `markdownlint.yml` | PR | Lint documentation | + +--- + +## Deployment + +```bash +# Azure (via Azure Developer CLI) +azd init +azd up +``` + +Aspire auto-detects all services and provisions Azure Container Apps, PostgreSQL, Redis, and Service Bus.