Small distributed commerce system.
catalog - products, brands, categories, variants/SKUs and current prices
inventory - warehouses, locations, stock, reservations and stock allocation
cart - shopping carts and cart items
ordering - orders, product snapshots and inventory reservation references
payment - payment records and payment simulation
fulfillment - shipments and shipment lifecycle
frontend - Angular UI
Catalog - working backend flow, API, tests, documentation, Docker Compose integration
Inventory - working backend flow, API, tests, documentation, Docker Compose integration
Cart - working backend flow, API, tests, documentation, Docker Compose integration, frontend integration
Ordering - working backend flow, Catalog and Inventory integration, API, tests, documentation, Docker Compose integration
Payment - working backend flow, Ordering integration, API, tests, documentation, Docker Compose integration
Fulfillment - working backend flow, Ordering integration, API, tests, documentation, Docker Compose integration
Frontend - working catalog browsing, backend cart integration, checkout and payment flow
Create brand
Create category
Create product as Draft
Add product variant/SKU
Publish product
List active products
Get product details
Get active product variant snapshot
Archive product
GET /health
GET /api/brands
POST /api/brands
GET /api/categories
POST /api/categories
GET /api/products
GET /api/products/{id}
GET /api/products/variants/{variantId}/snapshot
POST /api/products
POST /api/products/{id}/variants
POST /api/products/{id}/publish
POST /api/products/{id}/archive
Create warehouse
Create storage location
Receive stock for SKU
Get stock by SKU
Reserve stock explicitly
Allocate stock reservation by SKU
Release reservation
Commit reservation
Get stock movements
GET /health
GET /api/warehouses
POST /api/warehouses
GET /api/locations
POST /api/locations
POST /api/stock/receipts
GET /api/stock/{sku}
GET /api/stock/movements
POST /api/stock/reservations
POST /api/stock/reservations/allocate
POST /api/stock/reservations/{id}/release
POST /api/stock/reservations/{id}/commit
Create cart
Get cart details
Add product variant to cart
Increase quantity when adding the same product variant again
Update cart item quantity
Remove cart item
Clear cart
GET /health
POST /api/carts
GET /api/carts/{id}
POST /api/carts/{id}/items
PUT /api/carts/{id}/items/{productVariantId}
DELETE /api/carts/{id}/items/{productVariantId}
POST /api/carts/{id}/clear
Create order from product variant IDs and quantities
Load product snapshots from Catalog
Allocate Inventory stock reservations by SKU
Store inventoryReservationId on order item
Calculate line totals
Calculate order total
List orders
Get order details
Cancel order
Release Inventory reservation
Mark order as Paid
Keep Inventory reservation allocated while order is Paid
Mark paid order as Shipped
Commit Inventory reservation during mark-shipped
GET /health
GET /api/orders
GET /api/orders/{id}
POST /api/orders
POST /api/orders/{id}/cancel
POST /api/orders/{id}/mark-paid
POST /api/orders/{id}/mark-shipped
Create payment for order
List payments
Get payment details
Mark payment as succeeded
Mark linked order as Paid through Ordering
Keep Inventory reservation allocated until the paid order is shipped
Mark payment as failed
Reject status changes after payment completion
GET /health
GET /api/payments
GET /api/payments/{id}
POST /api/payments
POST /api/payments/{id}/succeed
POST /api/payments/{id}/fail
Create shipment for paid order
Validate linked order through Ordering
List shipments
Get shipment details
Ship shipment
Mark linked order as Shipped through Ordering
Commit Inventory reservation through Ordering mark-shipped
Cancel pending shipment
Reject shipment changes after terminal status
GET /health
GET /api/shipments
GET /api/shipments/{id}
POST /api/shipments
POST /api/shipments/{id}/ship
POST /api/shipments/{id}/cancel
Catalog defines product variants, SKUs and current prices.
Inventory stores stock by SKU.
Cart stores product variant IDs and quantities before checkout.
Ordering creates orders from product variant IDs and quantities.
Ordering loads trusted product snapshots from Catalog.
Ordering asks Inventory to allocate stock reservations by SKU.
Ordering releases Inventory reservation when an order is cancelled.
Payment stores simulated payment records for orders.
Payment calls Ordering when a pending payment succeeds.
Ordering marks the order as Paid.
Ordering keeps Inventory reservation allocated while the order is Paid.
Fulfillment validates paid orders through Ordering.
Fulfillment stores shipment records for orders.
Fulfillment calls Ordering when a shipment is shipped.
Ordering commits Inventory reservation during mark-shipped.
Ordering marks the order as Shipped.
Current Inventory commit boundary:
Ordering allocates Inventory reservations during order creation.
Ordering releases Inventory reservations when PendingPayment orders are cancelled.
Ordering keeps Inventory reservations allocated when orders are marked as Paid.
Fulfillment triggers mark-shipped through Ordering when shipments are shipped.
Ordering commits Inventory reservations when Paid orders are marked as Shipped.
Fulfillment does not call Inventory directly.
Ordering owns inventory_reservation_id references stored on order items.
Completed scenarios:
Cart flow:
Cart is created
Product variant is added to Cart with quantity
Adding the same product variant again increases quantity
Cart item quantity can be updated
Cart item can be removed
Cart can be cleared
Cart does not reserve Inventory stock
Cart does not store trusted product names, prices, SKUs or currencies
Cancel flow:
Product exists in Catalog
Stock exists in Inventory
Order is created in Ordering from product variant ID and quantity
Ordering loads product snapshot from Catalog
Inventory stock reservation is allocated
Order stores inventoryReservationId
Order is cancelled
Inventory reservation is released
Payment success flow:
Product exists in Catalog
Stock exists in Inventory
Order is created in Ordering from product variant ID and quantity
Ordering loads product snapshot from Catalog
Inventory stock reservation is allocated
Order stores inventoryReservationId
Payment is created for the order
Payment is marked as Succeeded
Payment calls Ordering to mark the order as Paid
Order is marked as Paid
Inventory reservation remains allocated
Inventory reservation is not committed yet
Inventory on-hand stock is not decreased yet
Payment failure flow:
Payment is created
Payment is marked as Failed
Payment remains terminal Failed
Payment failure does not call Ordering
No Inventory reservation is committed by Payment failure
Shipment flow:
Product exists in Catalog
Stock exists in Inventory
Order is created in Ordering from product variant ID and quantity
Ordering loads product snapshot from Catalog
Inventory stock reservation is allocated
Payment calls Ordering to mark the order as Paid
Inventory reservation remains allocated
Shipment is created in Fulfillment for the Paid order
Fulfillment validates linked order through Ordering
Shipment is shipped
Fulfillment calls Ordering to mark the order as Shipped
Ordering commits Inventory reservation during mark-shipped
Order is marked as Shipped
Inventory on-hand stock is decreased
Start databases and services:
docker compose up -dDocker Compose local service ports:
Catalog API - http://localhost:5001
Ordering API - http://localhost:5002
Inventory API - http://localhost:5003
Payment API - http://localhost:5004
Cart API - http://localhost:5005
Fulfillment API - http://localhost:5006
Inside Docker Compose, services use internal service names:
Ordering -> Catalog: http://catalog-api:8080
Ordering -> Inventory: http://inventory-api:8080
Payment -> Ordering: http://ordering-api:8080
Fulfillment -> Ordering: http://ordering-api:8080
Cart Service is currently independent from other backend services.
Catalog database from host:
Host=localhost;Port=5433;Database=catalog_db;Username=postgres;Password=postgres
Ordering database from host:
Host=localhost;Port=5434;Database=ordering_db;Username=postgres;Password=postgres
Inventory database from host:
Host=localhost;Port=5435;Database=inventory_db;Username=postgres;Password=postgres
Payment database from host:
Host=localhost;Port=5436;Database=payment_db;Username=postgres;Password=postgres
Cart database from host:
Host=localhost;Port=5437;Database=cart_db;Username=postgres;Password=postgres
Fulfillment database from host:
Host=localhost;Port=5438;Database=fulfillment_db;Username=postgres;Password=postgres
ASPNETCORE_ENVIRONMENT=Development \
ConnectionStrings__DefaultConnection="Host=localhost;Port=5433;Database=catalog_db;Username=postgres;Password=postgres" \
dotnet run --project services/catalog/Catalog.Api/Catalog.Api.csprojASPNETCORE_ENVIRONMENT=Development \
ConnectionStrings__DefaultConnection="Host=localhost;Port=5435;Database=inventory_db;Username=postgres;Password=postgres" \
dotnet run --project services/inventory/Inventory.Api/Inventory.Api.csprojCart API can be started independently.
ASPNETCORE_ENVIRONMENT=Development \
ConnectionStrings__DefaultConnection="Host=localhost;Port=5437;Database=cart_db;Username=postgres;Password=postgres" \
dotnet run --project services/cart/Cart.Api/Cart.Api.csprojOrdering API requires Catalog API for product snapshots and Inventory API for stock reservations.
Run Catalog API and Inventory API first.
Then run Ordering API:
ASPNETCORE_ENVIRONMENT=Development \
ConnectionStrings__DefaultConnection="Host=localhost;Port=5434;Database=ordering_db;Username=postgres;Password=postgres" \
CatalogApi__BaseUrl="http://localhost:5001" \
InventoryApi__BaseUrl="http://localhost:5245" \
dotnet run --project services/ordering/Ordering.Api/Ordering.Api.csprojPayment API requires Ordering API for successful payment flow.
Run Catalog API, Inventory API and Ordering API first.
Then run Payment API:
ASPNETCORE_ENVIRONMENT=Development \
ConnectionStrings__DefaultConnection="Host=localhost;Port=5436;Database=payment_db;Username=postgres;Password=postgres" \
OrderingApi__BaseUrl="http://localhost:5172" \
dotnet run --project services/payment/Payment.Api/Payment.Api.csprojFulfillment API requires Ordering API for shipment creation validation and shipment shipping flow.
Run Ordering API first.
Then run Fulfillment API:
ASPNETCORE_ENVIRONMENT=Development \
ConnectionStrings__DefaultConnection="Host=localhost;Port=5438;Database=fulfillment_db;Username=postgres;Password=postgres" \
OrderingApi__BaseUrl="http://localhost:5172" \
dotnet run --project services/fulfillment/Fulfillment.Api/Fulfillment.Api.csprojCatalog:
dotnet test services/catalog/Catalog.slnInventory:
dotnet test services/inventory/Inventory.slnCart:
dotnet test services/cart/Cart.slnOrdering:
dotnet test services/ordering/Ordering.slnPayment:
dotnet test services/payment/Payment.slnFulfillment:
dotnet test services/fulfillment/Fulfillment.slnCatalog:
services/catalog/Catalog.Api/Catalog.Api.http
services/catalog/Catalog.Api/Catalog.Api.readonly.http
Inventory:
services/inventory/Inventory.Api/Inventory.Api.http
services/inventory/Inventory.Api/Inventory.Api.readonly.http
Cart:
services/cart/Cart.Api/Cart.Api.http
services/cart/Cart.Api/Cart.Api.readonly.http
Ordering:
services/ordering/Ordering.Api/Ordering.Api.http
services/ordering/Ordering.Api/Ordering.Api.readonly.http
Payment:
services/payment/Payment.Api/Payment.Api.http
services/payment/Payment.Api/Payment.Api.readonly.http
Fulfillment:
services/fulfillment/Fulfillment.Api/Fulfillment.Api.http
services/fulfillment/Fulfillment.Api/Fulfillment.Api.readonly.http
Files ending with .readonly.http contain only safe read-only requests.
Write .http files may change local development data, but flows are designed to finish in terminal states and avoid active dangling reservations.
- Architecture and service boundaries: docs/architecture.md
- Local development and environment notes: docs/local-development.md
- Reliability and idempotency rules: docs/reliability.md
- Service-owned data model docs:
- API Specs & BDD Specifications:
Catalog owns:
products
brands
categories
variants/SKUs
product images
current product prices
Inventory owns:
warehouses
storage locations
stock balances
stock movements
stock reservations
stock allocation
Cart owns:
carts
cart items
product variant references
quantities
Ordering owns:
orders
order items
order statuses
order totals
product snapshots inside orders
Inventory reservation references inside order items
Payment owns:
payments
payment statuses
payment provider references
payment failure reasons
Fulfillment owns:
shipments
shipment statuses
carrier information
tracking numbers
shipment timestamps
Catalog does not store stock.
Inventory does not store product descriptions or prices.
Cart stores productVariantId and quantity only.
Cart does not store trusted product prices, product names, SKUs, currencies or stock data.
Cart does not reserve stock.
Cart does not create orders.
Cart does not process payments.
Ordering does not store live product data.
Ordering stores product snapshots so old orders do not change when Catalog data changes.
Frontend does not send trusted product prices, product names, SKUs or currencies to Ordering.
Frontend does not choose warehouse or storage location.
Ordering gets product snapshots from Catalog through Catalog API.
Inventory stores stock by SKU.
Inventory chooses warehouse and storage location during stock allocation.
Ordering may reference Catalog data by product_id, product_variant_id and sku.
Ordering may reference Inventory reservations by inventory_reservation_id.
Ordering creates Inventory reservations when orders are created.
Ordering releases Inventory reservations when PendingPayment orders are cancelled.
Ordering keeps Inventory reservations allocated when orders are marked as Paid.
Ordering commits Inventory reservations when Paid orders are marked as Shipped.
Payment does not store order details.
Payment references orders by order_id.
Payment calls Ordering when a pending payment succeeds.
Payment does not write OrderingDb directly.
Payment does not write InventoryDb directly.
Fulfillment does not store order details.
Fulfillment references orders by order_id.
Fulfillment calls Ordering when a shipment is shipped.
Fulfillment validates linked orders through Ordering before shipment creation.
Fulfillment does not write OrderingDb directly.
Fulfillment does not write InventoryDb directly.
Fulfillment does not call Inventory directly.
Fulfillment does not commit Inventory reservations directly.
Inventory still allocates stock reservations during order creation, not during cart changes.
Ordering still loads trusted product snapshots from Catalog when creating an order.