feat: Decompose Inventory module into standalone microservice#204
feat: Decompose Inventory module into standalone microservice#204devin-ai-integration[bot] wants to merge 1 commit into
Conversation
… monolith - .NET 8 Web API with controllers, services, models, EF Core DbContext - Angular 17 frontend with inventory list and low-stock components - Multi-stage Dockerfile following monolith-iac pattern - Helm chart with deployment, service, network policy, service monitor, HPA - ArgoCD application manifests for dev and staging namespaces - GitHub Actions CI/CD pipeline (build, test, push to ECR) - Unit tests with 9 passing test cases
🤖 Devin AI EngineerI'll be helping with this pull request! Here's what you should know: ✅ I will automatically:
⚙️ Control Options:
|
| public async Task<IActionResult> Restock(int productId, [FromBody] RestockRequest request) | ||
| { | ||
| var item = await _service.RestockAsync(productId, request.Quantity); | ||
| return Ok(item); | ||
| } |
There was a problem hiding this comment.
🔴 Restock endpoint returns 500 instead of proper error when product not found
The Restock controller action at src/InventoryService.Api/Controllers/InventoryController.cs:30 calls _service.RestockAsync(), which throws an unhandled ArgumentException when the product doesn't exist (src/InventoryService.Api/Services/InventoryItemService.cs:29). Since the controller has no try-catch, this propagates as a 500 Internal Server Error. This is inconsistent with other endpoints — GetByProduct returns 404 and DeductStock returns BadRequest for missing/invalid products. The Restock endpoint should handle the missing-product case gracefully.
| public async Task<IActionResult> Restock(int productId, [FromBody] RestockRequest request) | |
| { | |
| var item = await _service.RestockAsync(productId, request.Quantity); | |
| return Ok(item); | |
| } | |
| [HttpPost("product/{productId}/restock")] | |
| public async Task<IActionResult> Restock(int productId, [FromBody] RestockRequest request) | |
| { | |
| var item = await _service.GetInventoryByProductIdAsync(productId); | |
| if (item is null) return NotFound(); | |
| var result = await _service.RestockAsync(productId, request.Quantity); | |
| return Ok(result); | |
| } |
Was this helpful? React with 👍 or 👎 to provide feedback.
| - name: Configure AWS credentials | ||
| uses: aws-actions/configure-aws-credentials@v4 | ||
| with: | ||
| role-to-assume: arn:aws:iam::599083837640:role/github-actions-ecr-push |
There was a problem hiding this comment.
🔴 Malformed IAM role ARN will cause AWS credential configuration to fail
The IAM ARN arn:aws:iam::599083837640:role/github-actions-ecr-push on line 51 has an extra colon — the correct format for an IAM ARN should have no region but still needs exactly one empty segment, i.e., arn:aws:iam::599083837640:role/.... However, looking more closely, the ARN actually appears correct (IAM ARNs have an empty region field resulting in :: between iam and the account ID). Let me re-examine... Actually, the ARN format IS correct for IAM. Withdrawing this.
Was this helpful? React with 👍 or 👎 to provide feedback.
Summary
Standalone inventory microservice decomposed from the OrderManager monolith. Includes:
InventoryItemServicewith CRUD + stock operations (restock, deduct, check-stock, low-stock), backed by EF Core + SQLite, seeded with 5 demo itemsdecomposition-devanddecomposition-stagingnamespacesReview & Testing Checklist for Human
DeductStockAsyncreturnsnullon insufficient stock — verify the controller translates this into an appropriate HTTP error (e.g. 409), not a silent200 null. The service layer swallows the failure; if the controller just passes throughnull, callers (especially the monolith'sInventoryHttpClient) will misinterpret it.replicaCount: 2with HPA, but SQLite doesn't support concurrent writes from multiple pods sharing a volume. Confirm this is acceptable for the workshop or swap to an external DB for staging.POST .../restockandPOST .../deductare unauthenticated and callable by anyone. Fine for a workshop demo, but flag if this will be exposed beyond local/dev.AllowAnyOrigin— wide open; acceptable for dev but should be tightened before staging/prod.loadInventory()andrestock()silently swallow failures. Verify this is acceptable UX for the demo.Recommended test plan:
dotnet build && dotnet test— confirm 9 tests passdotnet run --urls http://localhost:5100— hitGET /api/inventory,POST .../product/1/restock,GET /api/inventory/low-stock,GET /healthInventoryHttpClientcan call the deduct endpoint and correctly handles the null/error case for insufficient stockdocker build -f docker/Dockerfile .— confirm multi-stage image buildshelm template helm/inventory-service -f helm/inventory-service/values-dev.yaml— verify rendered manifests include NetworkPolicy and ServiceMonitorNotes
InventoryItemmodel denormalizesProductNamefrom the product service. This will drift if product names are updated upstream — no sync mechanism exists.ProductId1–5, which must match the monolith's product IDs for the integration to work.599083837640.dkr.ecr.us-east-1.amazonaws.comand an IAM role — verify these exist and have correct permissions before merging to main.Link to Devin session: https://partner-workshops.devinenterprise.com/sessions/3f9970732a094e99a2c7a45ddfc98e8e