Skip to content

Setup repo: merge all services, fix DB config, add solution file#210

Open
devin-ai-integration[bot] wants to merge 18 commits into
mainfrom
devin/1775601781-setup-repo
Open

Setup repo: merge all services, fix DB config, add solution file#210
devin-ai-integration[bot] wants to merge 18 commits into
mainfrom
devin/1775601781-setup-repo

Conversation

@devin-ai-integration
Copy link
Copy Markdown
Contributor

@devin-ai-integration devin-ai-integration Bot commented Apr 7, 2026

Summary

Consolidates all microservice code (previously split across individual feature branches) into a single working branch and fixes issues preventing the application from running under Docker Compose.

Key changes on top of the merged feature branch code:

  • Database provider swap: All 4 services (CustomerService, ProductService, InventoryService, OrderService) switched from Npgsql.EntityFrameworkCore.PostgreSQL to Microsoft.EntityFrameworkCore.Sqlite. The original code referenced PostgreSQL via UseNpgsql() but the docker-compose.yml defined no PostgreSQL container, causing 3 services to crash on startup (exit code 139).
  • SQLite paths hardcoded to /data/*.db inside each service's Program.cs, matching the Docker volume mounts.
  • EnsureCreated() added to OrderService/Program.cs — the other 3 services already call this in their SeedData.Initialize() methods, but OrderService lacked it.
  • docker-compose.yml port fix: Web-frontend mapping changed from 4200:80 to 4200:8080 to match the nginx config inside the container (which listens on 8080, not 80).
  • docker-compose.yml env var fix: Environment variable names corrected to match the flat config keys the code reads (CUSTOMER_SERVICE_URL, PRODUCT_SERVICE_URL, INVENTORY_SERVICE_URL) instead of the ASP.NET hierarchical format (CustomerService__BaseUrl, etc.) which was silently ignored.
  • EShop.sln added for unified dotnet build / dotnet test across all projects.
  • Swagger enabled unconditionally in InventoryService and ProductService — these two services gated Swagger behind IsDevelopment(), but Docker containers default to Production. CustomerService and OrderService already enabled Swagger unconditionally; now all 4 are consistent.
  • Unhandled exception fixes in InventoryController.Restock and OrdersController.Create/UpdateStatus — added try-catch blocks for ArgumentException and InvalidOperationException, returning proper 404/400 responses instead of 500s. This matches the existing pattern in InventoryController.Reserve.

Verified locally:

  • dotnet build EShop.sln — 0 warnings, 0 errors
  • dotnet test EShop.sln — 3/3 tests passed
  • docker compose up --build — all 6 containers healthy
  • All API endpoints return data (/api/customers, /api/products, /api/inventory, /api/orders)
  • Angular frontend loads at localhost:4200 with all 4 pages rendering data from backend services

Review & Testing Checklist for Human

  • SQLite vs PostgreSQL decision: The original services were coded for PostgreSQL but no Postgres container existed in docker-compose.yml. This PR substitutes SQLite as a pragmatic fix. If PostgreSQL was the intended database, a postgres service should be added to docker-compose.yml instead, and these SQLite changes should be reverted.
  • Hardcoded /data paths: Each service uses Path.Combine("/data", "xxx.db") — this works inside Docker (volumes mount to /data) but will fail if services are run locally outside Docker without creating that directory. Consider whether an appsettings.json connection string fallback is needed.
  • HasColumnType("decimal(18,2)") in OrderDbContext: This PostgreSQL-specific column type annotation is still present. EF Core's SQLite provider silently ignores it, but it could cause confusion or issues if migrating back to PostgreSQL later.
  • Run docker compose up --build and verify all 6 services come up healthy, then navigate localhost:4200 → Products, Customers, Inventory, and Orders pages to confirm data loads. Also verify Swagger is accessible on all 4 service ports (/swagger).

Notes

  • The bulk of this diff is the merged feature branch code (services, Angular frontend, tests, Dockerfiles, README). The actual fix commits touch only a handful of files: 4× .csproj, 4× Program.cs, 2× controller files, docker-compose.yml, and the new EShop.sln.
  • Tests use Microsoft.EntityFrameworkCore.InMemory (not SQLite), so the SQLite swap does not affect test correctness.
  • 44 npm audit vulnerabilities exist in the Angular frontend (inherited from feature branch) — not addressed here.
  • OrderService.CreateOrderAsync lacks saga compensation for inventory reservations on partial failure — this is pre-existing application logic from the feature branch, not introduced by this PR.

Link to Devin session: https://partner-workshops.devinenterprise.com/sessions/d268d727d3dc4e298b9a2bc8f25c7371


Open with Devin

- .NET 8 Web API with EF Core + PostgreSQL
- InventoryItem model (standalone, no Product navigation)
- InventoryDbContext with seed data for ProductIds 1-5
- InventorySvc with CRUD + ReserveStock method
- InventoryController with all endpoints including /reserve
- Program.cs with health, metrics, CORS, Swagger
- Multi-stage Dockerfile
- .NET 8 Web API with PostgreSQL (EF Core)
- Product CRUD endpoints (GET all, GET by id, GET by category, POST)
- Health check, Prometheus metrics, Swagger, CORS
- Seed data with 5 products
- Multi-stage Dockerfile
- .NET 8 Web API extracted from OrderManager monolith
- Customer model, DbContext, seed data, service, and controller
- PostgreSQL via EF Core, health checks, Prometheus metrics, Swagger
- Multi-stage Dockerfile targeting port 8080
- CRUD endpoints: GET/POST /api/customers, GET /api/customers/{id}
- ApiGateway.csproj with Yarp.ReverseProxy, prometheus-net, Swashbuckle
- Program.cs with YARP routing, env var overrides, health/metrics/CORS/Swagger
- appsettings.json with route/cluster config for 4 microservices
- Multi-stage Dockerfile targeting .NET 8 Alpine
- README.md: Document microservices architecture, 6 services, local dev with docker-compose, deployment info
- .gitignore: Standard .NET + Node.js ignores
- docker-compose.yml: All 6 services with correct ports, env vars, and dependencies
…ix frontend port mapping

- Replace Npgsql.EntityFrameworkCore.PostgreSQL with Microsoft.EntityFrameworkCore.Sqlite in all 4 services
- Update Program.cs in CustomerService, ProductService, InventoryService, OrderService to use UseSqlite()
- Add EnsureCreated() to OrderService for database initialization
- Fix docker-compose.yml web-frontend port mapping from 80 to 8080 (matching nginx config)
- Add EShop.sln solution file for unified build management
@devin-ai-integration
Copy link
Copy Markdown
Contributor Author

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment and CI monitoring

Copy link
Copy Markdown
Contributor Author

@devin-ai-integration devin-ai-integration Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 3 potential issues.

View 5 additional findings in Devin Review.

Open in Devin Review

Comment on lines +53 to +67
foreach (var (productId, quantity) in items)
{
var product = await _productClient.GetProductAsync(productId)
?? throw new ArgumentException($"Product {productId} not found");

var reserveResult = await _inventoryClient.ReserveStockAsync(productId, quantity)
?? throw new InvalidOperationException($"Insufficient stock for {product.Name}");

order.Items.Add(new OrderItem
{
ProductId = productId,
Quantity = quantity,
UnitPrice = product.Price
});
}
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 No inventory compensation when multi-item order creation fails partway through

In CreateOrderAsync, the loop iterates over items and calls _inventoryClient.ReserveStockAsync for each one, which permanently deducts stock in the inventory service's database (src/InventoryService/Services/InventoryService.cs:56). If a later item fails (e.g., product not found at line 55-56 or insufficient stock at line 58-59), an exception is thrown but the inventory already reserved for earlier items is never rolled back. There is no compensation/restock logic and no try-catch in the loop. This causes permanent inventory data loss — stock is deducted with no corresponding order created. The README mentions a "saga pattern" but no compensation is implemented.

Prompt for agents
The CreateOrderAsync method in src/OrderService/Services/OrderService.cs reserves inventory for each item sequentially in a loop (lines 53-67). If any item fails after previous items have had their stock reserved, the already-reserved inventory is permanently lost because there is no compensation logic.

To fix this, you need to track which reservations have been made and add a try-catch around the loop that calls a restock/release endpoint on the inventory service for all previously reserved items when a failure occurs. The InventoryClient (src/OrderService/Clients/InventoryClient.cs) needs a new method like ReleaseStockAsync that calls the existing restock endpoint at POST /api/inventory/product/{productId}/restock. Then in CreateOrderAsync, maintain a list of (productId, quantity) for successful reservations, and in the catch block iterate through that list calling the release method for each.

Alternatively, consider implementing a two-phase approach: validate all products exist and check stock levels first, then reserve all in a second pass, with compensation on any failure.
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Valid observation about the missing saga compensation. This is pre-existing application logic from the feature branch — the lack of rollback in CreateOrderAsync is a design limitation, not a regression introduced by this setup PR. The README's mention of "saga pattern" appears aspirational. Leaving this as-is since the scope of this PR is infrastructure/setup fixes, not business logic changes.

Comment thread docker-compose.yml Outdated
Comment thread docker-compose.yml Outdated
- inventory-service: ProductService__BaseUrl -> PRODUCT_SERVICE_URL
- order-service: CustomerService__BaseUrl -> CUSTOMER_SERVICE_URL
- order-service: ProductService__BaseUrl -> PRODUCT_SERVICE_URL
- order-service: InventoryService__BaseUrl -> INVENTORY_SERVICE_URL
devin-ai-integration[bot]

This comment was marked as resolved.

- Enable Swagger unconditionally in InventoryService and ProductService (matching CustomerService/OrderService)
- Add try-catch for ArgumentException in InventoryController.Restock (matching Reserve action)
- Add try-catch for ArgumentException/InvalidOperationException in OrdersController.Create and UpdateStatus
devin-ai-integration[bot]

This comment was marked as resolved.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant