---
id: cart-checked-out
name: Cart Checked Out
version: 1.0.0
summary: |
Published when a customer has checked out their cart.
owners:
- shopping-platform
badges:
- content: 'Broker:Kafka'
backgroundColor: blue
textColor: blue
icon: BoltIcon
schemaPath: schema.json
---
import Footer from '@catalog/components/footer.astro';
## Overview
`CartCheckedOut` is published by the [[service|cart-api]] when a customer checks out. Downstream systems consume this event to create an order, take payment, and begin fulfilment.
## Architecture diagram
## Raw Schema:schema.json
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "CartCheckedOut",
"description": "Emitted when a customer checks out their cart",
"type": "object",
"properties": {
"eventId": {
"type": "string",
"format": "uuid"
},
"occurredAt": {
"type": "string",
"format": "date-time"
},
"cartId": {
"type": "string",
"format": "uuid"
},
"customerId": {
"type": "string",
"format": "uuid"
},
"items": {
"type": "array",
"items": {
"type": "object",
"properties": {
"productId": {
"type": "string",
"format": "uuid"
},
"quantity": {
"type": "integer",
"minimum": 1
},
"unitPrice": {
"description": "Price per unit in minor units (e.g. cents)",
"type": "integer"
}
},
"required": ["productId", "quantity", "unitPrice"]
}
},
"subtotal": {
"description": "Total before discounts, in minor units (e.g. cents)",
"type": "integer"
},
"discount": {
"description": "Total discount applied, in minor units (e.g. cents)",
"type": "integer"
},
"total": {
"description": "Final total, in minor units (e.g. cents)",
"type": "integer"
},
"currency": {
"type": "string",
"pattern": "^[A-Z]{3}$"
}
},
"required": ["eventId", "occurredAt", "cartId", "customerId", "items", "total", "currency"]
}
---
id: customer-authenticated
name: Customer Authenticated
version: 1.0.0
summary: |
Published when a customer has successfully authenticated.
owners:
- customer-platform
badges:
- content: 'Broker:Kafka'
backgroundColor: blue
textColor: blue
icon: BoltIcon
schemaPath: schema.json
---
import Footer from '@catalog/components/footer.astro';
## Overview
`CustomerAuthenticated` is published by the [[service|oauth-api]] whenever a customer successfully signs in. Other systems consume this event for auditing, session tracking, and security monitoring.
## Architecture diagram
## Raw Schema:schema.json
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "CustomerAuthenticated",
"description": "Emitted when a customer successfully authenticates",
"type": "object",
"properties": {
"eventId": {
"description": "Unique identifier for this event",
"type": "string",
"format": "uuid"
},
"occurredAt": {
"description": "Time the customer authenticated",
"type": "string",
"format": "date-time"
},
"customerId": {
"description": "Unique identifier of the customer that authenticated",
"type": "string",
"format": "uuid"
},
"method": {
"description": "How the customer authenticated",
"type": "string",
"enum": ["PASSWORD", "SSO", "MFA"]
},
"ipAddress": {
"description": "IP address the sign-in came from",
"type": "string"
}
},
"required": ["eventId", "occurredAt", "customerId", "method"]
}
---
id: customer-registered
name: Customer Registered
version: 1.0.0
summary: |
Published when a new customer has registered.
owners:
- customer-platform
badges:
- content: 'Broker:Kafka'
backgroundColor: blue
textColor: blue
icon: BoltIcon
schemaPath: schema.json
---
import Footer from '@catalog/components/footer.astro';
## Overview
`CustomerRegistered` is published by the [[service|customer-api]] whenever a new customer successfully registers. Downstream systems consume this event to onboard the customer.
## Architecture diagram
## Raw Schema:schema.json
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "CustomerRegistered",
"description": "Emitted when a new customer registers",
"type": "object",
"properties": {
"eventId": {
"description": "Unique identifier for this event",
"type": "string",
"format": "uuid"
},
"occurredAt": {
"description": "Time the customer registered",
"type": "string",
"format": "date-time"
},
"customer": {
"description": "The customer that registered",
"type": "object",
"properties": {
"customerId": {
"description": "Unique identifier for the customer",
"type": "string",
"format": "uuid"
},
"email": {
"description": "Customer's email address",
"type": "string",
"format": "email"
},
"name": {
"description": "Customer's full name",
"type": "string"
},
"status": {
"description": "Lifecycle status of the customer account",
"type": "string",
"enum": ["ACTIVE", "SUSPENDED", "CLOSED"]
}
},
"required": ["customerId", "email", "status"]
}
},
"required": ["eventId", "occurredAt", "customer"]
}
---
id: customer-updated
name: Customer Updated
version: 1.0.0
summary: |
Published when an existing customer's profile has changed.
owners:
- customer-platform
badges:
- content: 'Broker:Kafka'
backgroundColor: blue
textColor: blue
icon: BoltIcon
schemaPath: schema.json
---
import Footer from '@catalog/components/footer.astro';
## Overview
`CustomerUpdated` is published by the [[service|customer-api]] whenever an existing customer's profile changes. Downstream systems consume this event to keep their copy of customer data in sync.
## Architecture diagram
## Raw Schema:schema.json
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "CustomerUpdated",
"description": "Emitted when an existing customer's profile changes",
"type": "object",
"properties": {
"eventId": {
"description": "Unique identifier for this event",
"type": "string",
"format": "uuid"
},
"occurredAt": {
"description": "Time the customer was updated",
"type": "string",
"format": "date-time"
},
"customerId": {
"description": "Unique identifier for the customer that changed",
"type": "string",
"format": "uuid"
},
"changes": {
"description": "The fields that changed and their new values",
"type": "object",
"properties": {
"email": {
"type": "string",
"format": "email"
},
"name": {
"type": "string"
},
"status": {
"type": "string",
"enum": ["ACTIVE", "SUSPENDED", "CLOSED"]
}
},
"minProperties": 1
}
},
"required": ["eventId", "occurredAt", "customerId", "changes"]
}
---
id: discount-calculated
name: Discount Calculated
version: 1.0.0
summary: |
Published when a discount has been calculated for a cart.
owners:
- shopping-platform
badges:
- content: 'Broker:Kafka'
backgroundColor: blue
textColor: blue
icon: BoltIcon
schemaPath: schema.json
---
import Footer from '@catalog/components/footer.astro';
## Overview
`DiscountCalculated` is published by the [[service|promotion-service]] after evaluating the promotion rules for a cart. The [[system|cart-system]] uses the result to price the cart, and other systems can consume it for analytics.
## Architecture diagram
## Raw Schema:schema.json
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "DiscountCalculated",
"description": "Emitted when a discount has been calculated for a cart",
"type": "object",
"properties": {
"eventId": {
"type": "string",
"format": "uuid"
},
"occurredAt": {
"type": "string",
"format": "date-time"
},
"cartId": {
"type": "string",
"format": "uuid"
},
"discount": {
"description": "Total discount applied, in minor units (e.g. cents)",
"type": "integer",
"minimum": 0
},
"currency": {
"type": "string",
"pattern": "^[A-Z]{3}$"
},
"appliedPromotions": {
"description": "Identifiers of the promotions that were applied",
"type": "array",
"items": {
"type": "string"
}
}
},
"required": ["eventId", "occurredAt", "cartId", "discount", "currency"]
}
---
id: fraud-check-failed
name: Fraud Check Failed
version: 1.0.0
summary: |
Published when a payment fails fraud screening.
owners:
- payments-platform
badges:
- content: 'Broker:Kafka'
backgroundColor: blue
textColor: blue
icon: BoltIcon
schemaPath: schema.json
---
import Footer from '@catalog/components/footer.astro';
## Overview
`FraudCheckFailed` is published by the [[service|fraud-api]] when a payment is flagged as fraudulent. The [[system|payment-processing-system]] uses it to block the charge and cancel the order.
## Architecture diagram
## Raw Schema:schema.json
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "FraudCheckFailed",
"description": "Published when a payment fails fraud screening",
"type": "object",
"properties": {
"paymentId": { "type": "string", "format": "uuid" },
"orderId": { "type": "string", "format": "uuid" },
"score": {
"type": "number",
"minimum": 0,
"maximum": 1,
"description": "Fraud risk score; higher is riskier"
},
"reason": {
"type": "string",
"enum": ["HIGH_RISK_SCORE", "BLOCKLISTED", "VELOCITY", "MISMATCH"]
},
"checkedAt": { "type": "string", "format": "date-time" }
},
"required": ["paymentId", "orderId", "reason", "checkedAt"]
}
---
id: fraud-check-passed
name: Fraud Check Passed
version: 1.0.0
summary: |
Published when a payment passes fraud screening.
owners:
- payments-platform
badges:
- content: 'Broker:Kafka'
backgroundColor: blue
textColor: blue
icon: BoltIcon
schemaPath: schema.json
---
import Footer from '@catalog/components/footer.astro';
## Overview
`FraudCheckPassed` is published by the [[service|fraud-api]] when a payment clears fraud screening. The [[system|payment-processing-system]] uses it to allow the charge to proceed.
## Architecture diagram
## Raw Schema:schema.json
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "FraudCheckPassed",
"description": "Published when a payment passes fraud screening",
"type": "object",
"properties": {
"paymentId": { "type": "string", "format": "uuid" },
"orderId": { "type": "string", "format": "uuid" },
"score": {
"type": "number",
"minimum": 0,
"maximum": 1,
"description": "Fraud risk score; lower is safer"
},
"checkedAt": { "type": "string", "format": "date-time" }
},
"required": ["paymentId", "orderId", "checkedAt"]
}
---
id: inventory-reserved
name: Inventory Reserved
version: 1.0.0
summary: |
Published when stock has been successfully reserved for an order.
owners:
- fulfilment-platform
badges:
- content: 'Broker:Kafka'
backgroundColor: blue
textColor: blue
icon: BoltIcon
schemaPath: schema.json
---
import Footer from '@catalog/components/footer.astro';
## Overview
`InventoryReserved` is published by the [[service|inventory-service]] when stock for an order has been successfully reserved. The Ordering domain's checkout saga relies on this to continue placing the order.
## Architecture diagram
## Raw Schema:schema.json
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "InventoryReserved",
"description": "Published when stock has been successfully reserved for an order",
"type": "object",
"properties": {
"reservationId": { "type": "string", "format": "uuid" },
"orderId": { "type": "string", "format": "uuid" },
"cartId": { "type": "string", "format": "uuid" },
"items": {
"type": "array",
"items": {
"type": "object",
"properties": {
"productId": { "type": "string", "format": "uuid" },
"quantity": { "type": "integer", "minimum": 1 }
},
"required": ["productId", "quantity"]
}
},
"reservedAt": { "type": "string", "format": "date-time" }
},
"required": ["reservationId", "items", "reservedAt"]
}
---
id: inventory-unavailable
name: Inventory Unavailable
version: 1.0.0
summary: |
Published when stock could not be reserved for an order.
owners:
- fulfilment-platform
badges:
- content: 'Broker:Kafka'
backgroundColor: blue
textColor: blue
icon: BoltIcon
schemaPath: schema.json
---
import Footer from '@catalog/components/footer.astro';
## Overview
`InventoryUnavailable` is published by the [[service|inventory-service]] when stock for an order cannot be reserved. The Ordering domain's checkout saga uses it to fail checkout and cancel the order.
## Architecture diagram
## Raw Schema:schema.json
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "InventoryUnavailable",
"description": "Published when stock could not be reserved for an order",
"type": "object",
"properties": {
"orderId": { "type": "string", "format": "uuid" },
"cartId": { "type": "string", "format": "uuid" },
"unavailableItems": {
"type": "array",
"items": {
"type": "object",
"properties": {
"productId": { "type": "string", "format": "uuid" },
"requested": { "type": "integer", "minimum": 1 },
"available": { "type": "integer", "minimum": 0 }
},
"required": ["productId", "requested", "available"]
}
},
"checkedAt": { "type": "string", "format": "date-time" }
},
"required": ["unavailableItems", "checkedAt"]
}
---
id: order-cancelled
name: Order Cancelled
version: 1.0.0
summary: |
Published when an order has been cancelled.
owners:
- ordering-platform
badges:
- content: 'Broker:Kafka'
backgroundColor: blue
textColor: blue
icon: BoltIcon
schemaPath: schema.json
---
import Footer from '@catalog/components/footer.astro';
## Overview
`OrderCancelled` is published by the [[service|order-service]] when an order is cancelled — whether at the customer's request or because a downstream step (payment, inventory) failed. Downstream systems consume it to release inventory, refund or void payment, and stop fulfilment.
## Architecture diagram
## Raw Schema:schema.json
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "OrderCancelled",
"description": "Published when an order has been cancelled",
"type": "object",
"properties": {
"orderId": {
"type": "string",
"format": "uuid"
},
"customerId": {
"type": "string",
"format": "uuid"
},
"reason": {
"type": "string",
"enum": ["CUSTOMER_REQUESTED", "PAYMENT_FAILED", "OUT_OF_STOCK", "FRAUD"]
},
"cancelledAt": {
"type": "string",
"format": "date-time"
}
},
"required": ["orderId", "reason", "cancelledAt"]
}
---
id: order-completed
name: Order Completed
version: 1.0.0
summary: |
Published when an order has been fulfilled and completed.
owners:
- ordering-platform
badges:
- content: 'Broker:Kafka'
backgroundColor: blue
textColor: blue
icon: BoltIcon
schemaPath: schema.json
---
import Footer from '@catalog/components/footer.astro';
## Overview
`OrderCompleted` is published by the [[service|order-service]] when an order has been fully fulfilled. It marks the end of the happy path for an order. Downstream systems consume it to close out fulfilment, capture payment, and update reporting.
## Architecture diagram
## Raw Schema:schema.json
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "OrderCompleted",
"description": "Published when an order has been fulfilled and completed",
"type": "object",
"properties": {
"orderId": {
"type": "string",
"format": "uuid"
},
"customerId": {
"type": "string",
"format": "uuid"
},
"completedAt": {
"type": "string",
"format": "date-time"
}
},
"required": ["orderId", "customerId", "completedAt"]
}
---
id: order-created
name: Order Created
version: 0.3.0
summary: |
Published when a new order has been created. This early contract only included identifiers and the creation timestamp.
owners:
- ordering-platform
badges:
- content: 'Broker:Kafka'
backgroundColor: blue
textColor: blue
icon: BoltIcon
schemaPath: schema.json
---
import Footer from '@catalog/components/footer.astro';
## Overview
`OrderCreated` version `0.3.0` was the first stable order creation event contract used by downstream fulfilment consumers.
## Raw Schema:schema.json
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "OrderCreated",
"description": "Published when a new order has been created",
"type": "object",
"properties": {
"orderId": {
"type": "string",
"format": "uuid"
},
"customerId": {
"type": "string",
"format": "uuid"
},
"createdAt": {
"type": "string",
"format": "date-time"
}
},
"required": ["orderId", "customerId", "createdAt"]
}
---
id: order-created
name: Order Created
version: 0.6.0
summary: |
Published when a new order has been created. This version added the order total and currency for payment reconciliation.
owners:
- ordering-platform
badges:
- content: 'Broker:Kafka'
backgroundColor: blue
textColor: blue
icon: BoltIcon
schemaPath: schema.json
---
import Footer from '@catalog/components/footer.astro';
## Overview
`OrderCreated` version `0.6.0` added monetary fields so consumers could reconcile order totals without calling the Order API.
## Raw Schema:schema.json
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "OrderCreated",
"description": "Published when a new order has been created",
"type": "object",
"properties": {
"orderId": {
"type": "string",
"format": "uuid"
},
"customerId": {
"type": "string",
"format": "uuid"
},
"total": {
"type": "integer",
"description": "Order total in minor units (e.g. cents)"
},
"currency": {
"type": "string",
"pattern": "^[A-Z]{3}$"
},
"createdAt": {
"type": "string",
"format": "date-time"
}
},
"required": ["orderId", "customerId", "total", "currency", "createdAt"]
}
---
id: order-created
name: Order Created
version: 1.0.0
summary: |
Published when a new order has been created.
owners:
- ordering-platform
badges:
- content: 'Broker:Kafka'
backgroundColor: blue
textColor: blue
icon: BoltIcon
schemaPath: schema.json
---
import Footer from '@catalog/components/footer.astro';
## Overview
`OrderCreated` is published by the [[service|order-service]] when a new order is created from a checked-out cart. Downstream systems consume this event to begin fulfilment, send confirmation to the customer, and update reporting.
## Architecture diagram
## Raw Schema:schema.json
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "OrderCreated",
"description": "Published when a new order has been created",
"type": "object",
"properties": {
"orderId": {
"type": "string",
"format": "uuid"
},
"customerId": {
"type": "string",
"format": "uuid"
},
"total": {
"type": "integer",
"description": "Order total in minor units (e.g. cents)"
},
"currency": {
"type": "string",
"pattern": "^[A-Z]{3}$"
},
"status": {
"type": "string",
"enum": ["created"],
"description": "Initial lifecycle status for the order"
},
"items": {
"type": "array",
"description": "Line items captured at order creation time",
"items": {
"type": "object",
"properties": {
"sku": {
"type": "string"
},
"quantity": {
"type": "integer",
"minimum": 1
},
"unitPrice": {
"type": "integer",
"description": "Unit price in minor units (e.g. cents)"
}
},
"required": ["sku", "quantity", "unitPrice"]
}
},
"createdAt": {
"type": "string",
"format": "date-time"
}
},
"required": ["orderId", "customerId", "total", "currency", "status", "items", "createdAt"]
}
---
id: order-packed
name: Order Packed
version: 1.0.0
summary: |
Published when an order has been picked and packed in the warehouse.
owners:
- fulfilment-platform
badges:
- content: 'Broker:Kafka'
backgroundColor: blue
textColor: blue
icon: BoltIcon
schemaPath: schema.json
---
import Footer from '@catalog/components/footer.astro';
## Overview
`OrderPacked` is published by the [[service|picking-worker]] when an order has been fully picked and packed. The [[service|warehouse-service]] consumes it to mark the order ready and publish [[event|order-ready-for-shipping]].
## Architecture diagram
## Raw Schema:schema.json
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "OrderPacked",
"description": "Published when an order has been picked and packed in the warehouse",
"type": "object",
"properties": {
"orderId": { "type": "string", "format": "uuid" },
"pickingJobId": { "type": "string", "format": "uuid" },
"parcelCount": { "type": "integer", "minimum": 1 },
"packedAt": { "type": "string", "format": "date-time" }
},
"required": ["orderId", "packedAt"]
}
---
id: order-ready-for-shipping
name: Order Ready For Shipping
version: 1.0.0
summary: |
Published when a packed order is ready to be handed to a carrier for shipping.
owners:
- fulfilment-platform
badges:
- content: 'Broker:Kafka'
backgroundColor: blue
textColor: blue
icon: BoltIcon
schemaPath: schema.json
---
import Footer from '@catalog/components/footer.astro';
## Overview
`OrderReadyForShipping` is published by the [[service|warehouse-service]] once an order has been packed. The [[system|shipping-system]] consumes it to create a shipment with a carrier.
## Architecture diagram
## Raw Schema:schema.json
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "OrderReadyForShipping",
"description": "Published when a packed order is ready to be handed to a carrier",
"type": "object",
"properties": {
"orderId": { "type": "string", "format": "uuid" },
"customerId": { "type": "string", "format": "uuid" },
"parcelCount": { "type": "integer", "minimum": 1 },
"shippingAddress": {
"type": "object",
"properties": {
"line1": { "type": "string" },
"city": { "type": "string" },
"postcode": { "type": "string" },
"country": { "type": "string", "pattern": "^[A-Z]{2}$" }
},
"required": ["line1", "city", "postcode", "country"]
},
"readyAt": { "type": "string", "format": "date-time" }
},
"required": ["orderId", "shippingAddress", "readyAt"]
}
---
id: payment-failed
name: Payment Failed
version: 1.0.0
summary: |
Published by Stripe when a charge fails.
owners:
- payments-platform
badges:
- content: 'Broker:Kafka'
backgroundColor: blue
textColor: blue
icon: BoltIcon
schemaPath: schema.json
---
import Footer from '@catalog/components/footer.astro';
## Overview
`PaymentFailed` is delivered by Stripe's [[service|stripe-webhook-endpoint]] when a requested charge fails — for example a declined card. The [[service|payment-worker]] consumes it and records the payment as failed, which ultimately leads the order to be cancelled.
## Architecture diagram
## Raw Schema:schema.json
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "PaymentFailed",
"description": "Published when a charge fails",
"type": "object",
"properties": {
"paymentId": { "type": "string", "format": "uuid" },
"orderId": { "type": "string", "format": "uuid" },
"reason": {
"type": "string",
"enum": ["CARD_DECLINED", "INSUFFICIENT_FUNDS", "EXPIRED_CARD", "PROCESSING_ERROR"]
},
"failedAt": { "type": "string", "format": "date-time" }
},
"required": ["paymentId", "orderId", "reason", "failedAt"]
}
---
id: payment-requested
name: Payment Requested
version: 1.0.0
summary: |
Published when the Payment Processing System requests a charge from the payment processor.
owners:
- payments-platform
badges:
- content: 'Broker:Kafka'
backgroundColor: blue
textColor: blue
icon: BoltIcon
schemaPath: schema.json
---
import Footer from '@catalog/components/footer.astro';
## Overview
`PaymentRequested` is published by the [[service|payment-worker]] to ask the external [[system|stripe]] to charge a customer for an order. Stripe responds with [[event|payment-succeeded]] or [[event|payment-failed]]. The [[system|fraud-detection]] system also consumes this event to screen the payment.
## Architecture diagram
## Raw Schema:schema.json
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "PaymentRequested",
"description": "Published when a charge is requested from the payment processor",
"type": "object",
"properties": {
"paymentId": { "type": "string", "format": "uuid" },
"orderId": { "type": "string", "format": "uuid" },
"customerId": { "type": "string", "format": "uuid" },
"amount": {
"type": "integer",
"minimum": 0,
"description": "Amount to charge, in minor units (e.g. cents)"
},
"currency": { "type": "string", "pattern": "^[A-Z]{3}$" },
"requestedAt": { "type": "string", "format": "date-time" }
},
"required": ["paymentId", "orderId", "amount", "currency", "requestedAt"]
}
---
id: payment-succeeded
name: Payment Succeeded
version: 1.0.0
summary: |
Published by Stripe when a charge succeeds.
owners:
- payments-platform
badges:
- content: 'Broker:Kafka'
backgroundColor: blue
textColor: blue
icon: BoltIcon
schemaPath: schema.json
---
import Footer from '@catalog/components/footer.astro';
## Overview
`PaymentSucceeded` is delivered by Stripe's [[service|stripe-webhook-endpoint]] when a requested charge succeeds. The [[service|payment-worker]] consumes it and records the payment as succeeded.
## Architecture diagram
## Raw Schema:schema.json
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "PaymentSucceeded",
"description": "Published when a charge succeeds",
"type": "object",
"properties": {
"paymentId": { "type": "string", "format": "uuid" },
"orderId": { "type": "string", "format": "uuid" },
"amount": { "type": "integer", "description": "Amount charged, in minor units (e.g. cents)" },
"currency": { "type": "string", "pattern": "^[A-Z]{3}$" },
"processorReference": { "type": "string", "description": "Stripe's charge identifier" },
"succeededAt": { "type": "string", "format": "date-time" }
},
"required": ["paymentId", "orderId", "amount", "currency", "succeededAt"]
}
---
id: product-created
name: Product Created
version: 1.0.0
summary: |
Published when a new product has been added to the catalog.
owners:
- product-platform
badges:
- content: 'Broker:Kafka'
backgroundColor: blue
textColor: blue
icon: BoltIcon
schemaPath: schema.json
---
import Footer from '@catalog/components/footer.astro';
## Overview
`ProductCreated` is published by the [[service|product-search-publisher]] whenever a new product is successfully added to the catalog by the [[service|product-api]]. The [[system|search-system]] consumes this event to index the new product so it becomes discoverable.
## Architecture diagram
## Raw Schema:schema.json
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "ProductCreated",
"description": "Emitted when a new product is added to the catalog",
"type": "object",
"properties": {
"eventId": {
"description": "Unique identifier for this event",
"type": "string",
"format": "uuid"
},
"occurredAt": {
"description": "Time the product was created",
"type": "string",
"format": "date-time"
},
"product": {
"description": "The product that was created",
"type": "object",
"properties": {
"productId": {
"description": "Unique identifier for the product",
"type": "string",
"format": "uuid"
},
"sku": {
"description": "Stock keeping unit",
"type": "string"
},
"name": {
"description": "Display name of the product",
"type": "string"
},
"description": {
"description": "Long-form product description",
"type": "string"
},
"price": {
"description": "Price in minor units (e.g. cents)",
"type": "integer",
"minimum": 0
},
"currency": {
"description": "ISO 4217 currency code",
"type": "string",
"pattern": "^[A-Z]{3}$"
},
"category": {
"description": "Category the product belongs to",
"type": "string"
},
"status": {
"description": "Lifecycle status of the product",
"type": "string",
"enum": ["DRAFT", "ACTIVE", "ARCHIVED"]
}
},
"required": ["productId", "sku", "name", "price", "currency", "status"]
}
},
"required": ["eventId", "occurredAt", "product"]
}
---
id: product-deleted
name: Product Deleted
version: 1.0.0
summary: |
Published when a product has been removed from the catalog.
owners:
- product-platform
badges:
- content: 'Broker:Kafka'
backgroundColor: blue
textColor: blue
icon: BoltIcon
schemaPath: schema.json
---
import Footer from '@catalog/components/footer.astro';
## Overview
`ProductDeleted` is published by the [[service|product-search-publisher]] when a product is removed from the catalog via the [[service|product-api]]. The [[system|search-system]] consumes this event to remove the product from the search index.
## Architecture diagram
## Raw Schema:schema.json
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "ProductDeleted",
"description": "Emitted when a product is removed from the catalog",
"type": "object",
"properties": {
"eventId": {
"description": "Unique identifier for this event",
"type": "string",
"format": "uuid"
},
"occurredAt": {
"description": "Time the product was deleted",
"type": "string",
"format": "date-time"
},
"productId": {
"description": "Unique identifier for the product that was deleted",
"type": "string",
"format": "uuid"
},
"reason": {
"description": "Optional reason the product was removed",
"type": "string",
"enum": ["DISCONTINUED", "DUPLICATE", "MERCHANT_REQUEST", "OTHER"]
}
},
"required": ["eventId", "occurredAt", "productId"]
}
---
id: product-updated
name: Product Updated
version: 1.0.0
summary: |
Published when an existing product's data has changed.
owners:
- product-platform
badges:
- content: 'Broker:Kafka'
backgroundColor: blue
textColor: blue
icon: BoltIcon
schemaPath: schema.json
---
import Footer from '@catalog/components/footer.astro';
## Overview
`ProductUpdated` is published by the [[service|product-search-publisher]] whenever an existing product is changed via the [[service|product-api]]. The [[system|search-system]] consumes this event to re-index the product so search results stay accurate.
## Architecture diagram
## Raw Schema:schema.json
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "ProductUpdated",
"description": "Emitted when an existing product's data changes",
"type": "object",
"properties": {
"eventId": {
"description": "Unique identifier for this event",
"type": "string",
"format": "uuid"
},
"occurredAt": {
"description": "Time the product was updated",
"type": "string",
"format": "date-time"
},
"productId": {
"description": "Unique identifier for the product that changed",
"type": "string",
"format": "uuid"
},
"changes": {
"description": "The fields that changed and their new values",
"type": "object",
"properties": {
"name": {
"type": "string"
},
"description": {
"type": "string"
},
"price": {
"description": "Price in minor units (e.g. cents)",
"type": "integer",
"minimum": 0
},
"currency": {
"description": "ISO 4217 currency code",
"type": "string",
"pattern": "^[A-Z]{3}$"
},
"category": {
"type": "string"
},
"status": {
"description": "Lifecycle status of the product",
"type": "string",
"enum": ["DRAFT", "ACTIVE", "ARCHIVED"]
}
},
"minProperties": 1
}
},
"required": ["eventId", "occurredAt", "productId", "changes"]
}
---
id: rating-updated
name: Rating Updated
version: 1.0.0
summary: |
Published when a product's aggregate rating changes as a result of a newly published review.
owners:
- reviews-platform
schemaPath: schema.json
badges:
- content: 'Broker:Kafka'
backgroundColor: blue
textColor: blue
icon: BoltIcon
---
import Footer from '@catalog/components/footer.astro';
## Overview
`RatingUpdated` is published by the [[service|rating-aggregator]] whenever a product's aggregate rating changes. Other domains (such as the storefront and search) can consume it to keep displayed ratings fresh.
## Architecture diagram
## Raw Schema:schema.json
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "RatingUpdated",
"type": "object",
"properties": {
"productId": { "type": "string" },
"averageRating": { "type": "number", "minimum": 0, "maximum": 5 },
"reviewCount": { "type": "integer", "minimum": 0 },
"updatedAt": { "type": "string", "format": "date-time" }
},
"required": ["productId", "averageRating", "reviewCount", "updatedAt"]
}
---
id: refund-processed
name: Refund Processed
version: 1.0.0
summary: |
Published by Stripe when a refund has been processed.
owners:
- payments-platform
badges:
- content: 'Broker:Kafka'
backgroundColor: blue
textColor: blue
icon: BoltIcon
schemaPath: schema.json
---
import Footer from '@catalog/components/footer.astro';
## Overview
`RefundProcessed` is delivered by Stripe's [[service|stripe-webhook-endpoint]] when a requested refund has been processed. The [[service|payment-worker]] consumes it and records the refund as complete.
## Architecture diagram
## Raw Schema:schema.json
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "RefundProcessed",
"description": "Published when a refund has been processed",
"type": "object",
"properties": {
"refundId": { "type": "string", "format": "uuid" },
"paymentId": { "type": "string", "format": "uuid" },
"amount": { "type": "integer", "description": "Amount refunded, in minor units (e.g. cents)" },
"currency": { "type": "string", "pattern": "^[A-Z]{3}$" },
"processedAt": { "type": "string", "format": "date-time" }
},
"required": ["refundId", "paymentId", "amount", "currency", "processedAt"]
}
---
id: refund-requested
name: Refund Requested
version: 1.0.0
summary: |
Published when the Payment Processing System requests a refund from the payment processor.
owners:
- payments-platform
badges:
- content: 'Broker:Kafka'
backgroundColor: blue
textColor: blue
icon: BoltIcon
schemaPath: schema.json
---
import Footer from '@catalog/components/footer.astro';
## Overview
`RefundRequested` is published by the [[service|payment-worker]] to ask the external [[system|stripe]] to refund a previous charge — for example when an order is cancelled after payment. Stripe responds with [[event|refund-processed]].
## Architecture diagram
## Raw Schema:schema.json
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "RefundRequested",
"description": "Published when a refund is requested from the payment processor",
"type": "object",
"properties": {
"refundId": { "type": "string", "format": "uuid" },
"paymentId": { "type": "string", "format": "uuid" },
"orderId": { "type": "string", "format": "uuid" },
"amount": {
"type": "integer",
"minimum": 0,
"description": "Amount to refund, in minor units (e.g. cents)"
},
"currency": { "type": "string", "pattern": "^[A-Z]{3}$" },
"reason": { "type": "string" },
"requestedAt": { "type": "string", "format": "date-time" }
},
"required": ["refundId", "paymentId", "amount", "currency", "requestedAt"]
}
---
id: review-flagged
name: Review Flagged
version: 1.0.0
summary: |
Published when a published review is flagged and needs to be screened again.
owners:
- reviews-platform
schemaPath: schema.json
badges:
- content: 'Broker:Kafka'
backgroundColor: blue
textColor: blue
icon: BoltIcon
---
import Footer from '@catalog/components/footer.astro';
## Overview
`ReviewFlagged` is published by the [[service|review-api]] when a published review is flagged. The [[service|review-moderation-worker]] consumes it and re-screens the review, which may lead to it being rejected.
## Architecture diagram
## Raw Schema:schema.json
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "ReviewFlagged",
"type": "object",
"properties": {
"reviewId": { "type": "string", "format": "uuid" },
"productId": { "type": "string" },
"reason": { "type": "string", "enum": ["spam", "abuse", "off_topic", "inappropriate", "other"] },
"flagCount": { "type": "integer", "minimum": 1, "description": "Total flags this review has now received." },
"flaggedAt": { "type": "string", "format": "date-time" }
},
"required": ["reviewId", "productId", "reason", "flaggedAt"]
}
---
id: review-helpful-voted
name: Review Helpful Voted
version: 1.0.0
summary: |
Published when a review's helpful count changes as a result of a customer vote.
owners:
- reviews-platform
schemaPath: schema.json
badges:
- content: 'Broker:Kafka'
backgroundColor: blue
textColor: blue
icon: BoltIcon
---
import Footer from '@catalog/components/footer.astro';
## Overview
`ReviewHelpfulVoted` is published by the [[service|review-api]] whenever a review's helpful count changes. It lets other surfaces (such as the storefront) keep "most helpful" ordering fresh.
## Architecture diagram
## Raw Schema:schema.json
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "ReviewHelpfulVoted",
"type": "object",
"properties": {
"reviewId": { "type": "string", "format": "uuid" },
"productId": { "type": "string" },
"helpfulCount": { "type": "integer", "minimum": 0 },
"updatedAt": { "type": "string", "format": "date-time" }
},
"required": ["reviewId", "productId", "helpfulCount", "updatedAt"]
}
---
id: review-published
name: Review Published
version: 1.0.0
summary: |
Published when a submitted review passes moderation and becomes visible on the storefront.
owners:
- reviews-platform
schemaPath: schema.json
badges:
- content: 'Broker:Kafka'
backgroundColor: blue
textColor: blue
icon: BoltIcon
---
import Footer from '@catalog/components/footer.astro';
## Overview
`ReviewPublished` is published by the [[service|review-moderation-worker]] when a review passes moderation. The [[service|rating-aggregator]] consumes it to update the product's aggregate rating.
## Architecture diagram
## Raw Schema:schema.json
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "ReviewPublished",
"type": "object",
"properties": {
"reviewId": { "type": "string", "format": "uuid" },
"productId": { "type": "string" },
"customerId": { "type": "string" },
"rating": { "type": "integer", "minimum": 1, "maximum": 5 },
"publishedAt": { "type": "string", "format": "date-time" }
},
"required": ["reviewId", "productId", "rating", "publishedAt"]
}
---
id: review-rejected
name: Review Rejected
version: 1.0.0
summary: |
Published when a submitted review fails moderation (spam, abuse or policy violation) and will not be shown.
owners:
- reviews-platform
schemaPath: schema.json
badges:
- content: 'Broker:Kafka'
backgroundColor: blue
textColor: blue
icon: BoltIcon
---
import Footer from '@catalog/components/footer.astro';
## Overview
`ReviewRejected` is published by the [[service|review-moderation-worker]] when a review fails moderation. The review is kept for audit but never published to the storefront.
## Architecture diagram
## Raw Schema:schema.json
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "ReviewRejected",
"type": "object",
"properties": {
"reviewId": { "type": "string", "format": "uuid" },
"productId": { "type": "string" },
"reason": { "type": "string", "enum": ["spam", "abuse", "off_topic", "policy_violation"] },
"rejectedAt": { "type": "string", "format": "date-time" }
},
"required": ["reviewId", "productId", "reason", "rejectedAt"]
}
---
id: review-submitted
name: Review Submitted
version: 1.0.0
summary: |
Published when a customer submits a review. The review is stored but not yet visible — it awaits moderation.
owners:
- reviews-platform
schemaPath: schema.json
badges:
- content: 'Broker:Kafka'
backgroundColor: blue
textColor: blue
icon: BoltIcon
---
import Footer from '@catalog/components/footer.astro';
## Overview
`ReviewSubmitted` is published by the [[service|review-api]] once a review has been accepted and stored. The [[service|review-moderation-worker]] consumes it to screen the review before it can be published.
## Architecture diagram
## Raw Schema:schema.json
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "ReviewSubmitted",
"type": "object",
"properties": {
"reviewId": { "type": "string", "format": "uuid" },
"productId": { "type": "string" },
"customerId": { "type": "string" },
"rating": { "type": "integer", "minimum": 1, "maximum": 5 },
"title": { "type": "string" },
"body": { "type": "string" },
"submittedAt": { "type": "string", "format": "date-time" }
},
"required": ["reviewId", "productId", "customerId", "rating", "submittedAt"]
}
---
id: shipment-created
name: Shipment Created
version: 1.0.0
summary: |
Published by the carrier when a shipment has been created and dispatched.
owners:
- fulfilment-platform
badges:
- content: 'Broker:Kafka'
backgroundColor: blue
textColor: blue
icon: BoltIcon
schemaPath: schema.json
---
import Footer from '@catalog/components/footer.astro';
## Overview
`ShipmentCreated` is published by the carrier's [[service|carrier-tracking-api]] when a shipment has been created and dispatched. Acme Inc consumes it to give the customer a tracking number and expected delivery date.
## Architecture diagram
## Raw Schema:schema.json
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "ShipmentCreated",
"description": "Published when a shipment has been created and dispatched",
"type": "object",
"properties": {
"shipmentId": { "type": "string", "format": "uuid" },
"orderId": { "type": "string", "format": "uuid" },
"trackingNumber": { "type": "string" },
"carrier": { "type": "string" },
"estimatedDelivery": { "type": "string", "format": "date" },
"createdAt": { "type": "string", "format": "date-time" }
},
"required": ["shipmentId", "orderId", "trackingNumber", "createdAt"]
}
---
id: shipment-delivered
name: Shipment Delivered
version: 1.0.0
summary: |
Published by the carrier when a shipment has been delivered to the customer.
owners:
- fulfilment-platform
badges:
- content: 'Broker:Kafka'
backgroundColor: blue
textColor: blue
icon: BoltIcon
schemaPath: schema.json
---
import Footer from '@catalog/components/footer.astro';
## Overview
`ShipmentDelivered` is published by the carrier's [[service|carrier-tracking-api]] when a shipment reaches the customer. This is the happy-path end of the fulfilment journey — Acme Inc consumes it to close out the order and prompt the customer for feedback.
## Architecture diagram
## Raw Schema:schema.json
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "ShipmentDelivered",
"description": "Published when a shipment has been delivered to the customer",
"type": "object",
"properties": {
"shipmentId": { "type": "string", "format": "uuid" },
"orderId": { "type": "string", "format": "uuid" },
"deliveredAt": { "type": "string", "format": "date-time" },
"signedBy": { "type": "string", "description": "Name of the person who accepted delivery, if captured" }
},
"required": ["shipmentId", "orderId", "deliveredAt"]
}
---
id: shipment-failed
name: Shipment Failed
version: 1.0.0
summary: |
Published by the carrier when a shipment could not be delivered.
owners:
- fulfilment-platform
badges:
- content: 'Broker:Kafka'
backgroundColor: blue
textColor: blue
icon: BoltIcon
schemaPath: schema.json
---
import Footer from '@catalog/components/footer.astro';
## Overview
`ShipmentFailed` is published by the carrier's [[service|carrier-tracking-api]] when a shipment cannot be delivered — for example a failed delivery attempt or a lost parcel. Acme Inc consumes it to trigger a redelivery, refund, or customer follow-up.
## Architecture diagram
## Raw Schema:schema.json
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "ShipmentFailed",
"description": "Published when a shipment could not be delivered",
"type": "object",
"properties": {
"shipmentId": { "type": "string", "format": "uuid" },
"orderId": { "type": "string", "format": "uuid" },
"reason": {
"type": "string",
"enum": ["FAILED_DELIVERY", "LOST", "DAMAGED", "RETURNED_TO_SENDER"]
},
"failedAt": { "type": "string", "format": "date-time" }
},
"required": ["shipmentId", "orderId", "reason", "failedAt"]
}
---
id: add-item-to-cart
name: Add Item To Cart
version: 1.0.0
summary: |
Command to add an item to a shopping cart.
owners:
- shopping-platform
schemaPath: schema.json
operation:
method: POST
path: /carts/{cartId}/items
statusCodes: ['200', '400', '404']
sidebar:
badge: 'POST'
---
import Footer from '@catalog/components/footer.astro';
## Overview
`AddItemToCart` is handled by the [[service|cart-api]]. It adds an item (or increases its quantity) in the cart and persists the change to the [[container|cart-database]].
## Architecture diagram
## Schema
## Raw Schema:schema.json
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "AddItemToCart",
"description": "Command to add an item to a shopping cart",
"type": "object",
"properties": {
"cartId": {
"description": "Unique identifier of the cart",
"type": "string",
"format": "uuid"
},
"productId": {
"description": "Identifier of the product to add",
"type": "string",
"format": "uuid"
},
"quantity": {
"description": "Number of units to add",
"type": "integer",
"minimum": 1,
"default": 1
}
},
"required": ["cartId", "productId", "quantity"]
}
---
id: authenticate-customer
name: Authenticate Customer
version: 1.0.0
summary: |
Command to authenticate a customer with their credentials.
owners:
- customer-platform
schemaPath: schema.json
operation:
method: POST
path: /oauth/token
statusCodes: ['200', '400', '401']
sidebar:
badge: 'POST'
---
import Footer from '@catalog/components/footer.astro';
## Overview
`AuthenticateCustomer` is handled by the [[service|oauth-api]]. It verifies the supplied credentials against the [[container|user-directory]] and, on success, returns an access token and publishes a [[event|customer-authenticated]] event.
## Architecture diagram
## Schema
## Raw Schema:schema.json
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "AuthenticateCustomer",
"description": "Command to authenticate a customer with their credentials, and the token returned",
"type": "object",
"properties": {
"request": {
"description": "The credentials to authenticate",
"type": "object",
"properties": {
"email": {
"type": "string",
"format": "email"
},
"password": {
"type": "string"
}
},
"required": ["email", "password"]
},
"response": {
"description": "The access token issued on a successful sign-in",
"type": "object",
"properties": {
"accessToken": {
"type": "string"
},
"tokenType": {
"type": "string",
"enum": ["Bearer"]
},
"expiresIn": {
"description": "Token lifetime in seconds",
"type": "integer"
}
},
"required": ["accessToken", "tokenType", "expiresIn"]
}
},
"required": ["request", "response"]
}
---
id: authorize-payment
name: Authorize Payment
version: 1.0.0
summary: |
Command to authorize payment for the total of a checked-out cart.
owners:
- ordering-platform
schemaPath: schema.json
operation:
method: POST
path: /payments/authorize
statusCodes: ['201', '400', '402', '409']
sidebar:
badge: 'POST'
---
import Footer from '@catalog/components/footer.astro';
## Overview
`AuthorizePayment` is sent by the [[service|checkout-orchestrator]] to authorize payment for the order total. Authorization places a hold on the customer's payment method; the funds are captured once the order is created. If a later step fails, the authorization is voided.
## Architecture diagram
## Schema
## Raw Schema:schema.json
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "AuthorizePayment",
"description": "Command to authorize payment for the total of a checked-out cart",
"type": "object",
"properties": {
"cartId": {
"description": "Identifier of the cart being checked out",
"type": "string",
"format": "uuid"
},
"customerId": {
"description": "Identifier of the customer paying",
"type": "string",
"format": "uuid"
},
"amount": {
"description": "Amount to authorize, in minor units (e.g. cents)",
"type": "integer",
"minimum": 0
},
"currency": {
"description": "ISO 4217 currency code",
"type": "string",
"pattern": "^[A-Z]{3}$"
}
},
"required": ["cartId", "amount", "currency"]
}
---
id: calculate-discount
name: Calculate Discount
version: 1.0.0
summary: |
Command to calculate the discount that applies to a cart.
owners:
- shopping-platform
schemaPath: schema.json
operation:
method: POST
path: /discounts/calculate
statusCodes: ['200', '400']
sidebar:
badge: 'POST'
---
import Footer from '@catalog/components/footer.astro';
## Overview
`CalculateDiscount` is handled by the [[service|promotion-service]]. It is sent by the [[service|cart-api]] when pricing a cart. The service evaluates the applicable promotion rules and returns the discount, also publishing a [[event|discount-calculated]] event.
## Architecture diagram
## Schema
## Raw Schema:schema.json
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "CalculateDiscount",
"description": "Command to calculate the discount for a cart, and the discount returned",
"type": "object",
"properties": {
"request": {
"type": "object",
"properties": {
"cartId": {
"type": "string",
"format": "uuid"
},
"customerId": {
"type": "string",
"format": "uuid"
},
"subtotal": {
"description": "Cart subtotal before discounts, in minor units (e.g. cents)",
"type": "integer",
"minimum": 0
},
"currency": {
"type": "string",
"pattern": "^[A-Z]{3}$"
},
"promotionCode": {
"description": "Optional promotion code supplied by the customer",
"type": "string"
}
},
"required": ["cartId", "subtotal", "currency"]
},
"response": {
"type": "object",
"properties": {
"discount": {
"description": "Total discount to apply, in minor units (e.g. cents)",
"type": "integer",
"minimum": 0
},
"appliedPromotions": {
"type": "array",
"items": {
"type": "string"
}
}
},
"required": ["discount"]
}
},
"required": ["request", "response"]
}
---
id: cancel-order
name: Cancel Order
version: 1.0.0
summary: |
Command to cancel an existing order.
owners:
- ordering-platform
schemaPath: schema.json
operation:
method: POST
path: /orders/{orderId}/cancel
statusCodes: ['200', '404', '409']
sidebar:
badge: 'POST'
---
import Footer from '@catalog/components/footer.astro';
## Overview
`CancelOrder` is handled by the [[service|order-service]]. It cancels an order that has not yet been completed — releasing any reservations and voiding the payment authorization where needed. On success the Order Service publishes an [[event|order-cancelled]] event.
## Architecture diagram
## Schema
## Raw Schema:schema.json
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "CancelOrder",
"description": "Command to cancel an existing order",
"type": "object",
"properties": {
"orderId": {
"description": "Identifier of the order to cancel",
"type": "string",
"format": "uuid"
},
"reason": {
"description": "Why the order is being cancelled",
"type": "string",
"enum": ["CUSTOMER_REQUESTED", "PAYMENT_FAILED", "OUT_OF_STOCK", "FRAUD"]
}
},
"required": ["orderId", "reason"]
}
---
id: checkout-cart
name: Checkout Cart
version: 1.0.0
summary: |
Command to check out a shopping cart.
owners:
- shopping-platform
schemaPath: schema.json
operation:
method: POST
path: /carts/{cartId}/checkout
statusCodes: ['200', '400', '404', '409']
sidebar:
badge: 'POST'
---
import Footer from '@catalog/components/footer.astro';
## Overview
`CheckoutCart` is handled by the [[service|cart-api]]. It finalises the cart — pricing it (including discounts from the [[system|promotion-system]]) — and on success publishes a [[event|cart-checked-out]] event.
## Architecture diagram
## Schema
## Raw Schema:schema.json
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "CheckoutCart",
"description": "Command to check out a shopping cart",
"type": "object",
"properties": {
"cartId": {
"description": "Unique identifier of the cart to check out",
"type": "string",
"format": "uuid"
},
"customerId": {
"description": "Identifier of the customer checking out",
"type": "string",
"format": "uuid"
},
"promotionCode": {
"description": "Optional promotion code to apply at checkout",
"type": "string"
}
},
"required": ["cartId", "customerId"]
}
---
id: create-order
name: Create Order
version: 1.0.0
summary: |
Command to create a new order from a checked-out cart.
owners:
- ordering-platform
schemaPath: schema.json
operation:
method: POST
path: /orders
statusCodes: ['201', '400', '409']
sidebar:
badge: 'POST'
---
import Footer from '@catalog/components/footer.astro';
## Overview
`CreateOrder` is sent by the [[service|checkout-orchestrator]] and handled by the [[service|order-service]]. It is the final step of the checkout saga — once inventory is reserved and payment is authorized, this command creates the order. On success the Order Service publishes an [[event|order-created]] event.
## Architecture diagram
## Schema
## Raw Schema:schema.json
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "CreateOrder",
"description": "Command to create a new order from a checked-out cart",
"type": "object",
"properties": {
"cartId": {
"description": "Identifier of the cart this order was created from",
"type": "string",
"format": "uuid"
},
"customerId": {
"description": "Identifier of the customer placing the order",
"type": "string",
"format": "uuid"
},
"items": {
"description": "The items in the order",
"type": "array",
"items": {
"type": "object",
"properties": {
"productId": {
"type": "string",
"format": "uuid"
},
"quantity": {
"type": "integer",
"minimum": 1
},
"unitPrice": {
"type": "integer",
"description": "Price per unit in minor units (e.g. cents)"
}
},
"required": ["productId", "quantity", "unitPrice"]
}
},
"total": {
"description": "Order total in minor units (e.g. cents)",
"type": "integer",
"minimum": 0
},
"currency": {
"description": "ISO 4217 currency code",
"type": "string",
"pattern": "^[A-Z]{3}$"
},
"paymentAuthorizationId": {
"description": "Identifier of the payment authorization for this order",
"type": "string"
}
},
"required": ["cartId", "customerId", "items", "total", "currency"]
}
---
id: create-product
name: Create Product
version: 1.0.0
summary: |
Command to add a new product to the catalog.
owners:
- product-platform
schemaPath: schema.json
operation:
method: POST
path: /products
statusCodes: ['201', '400', '409']
sidebar:
badge: 'POST'
---
import Footer from '@catalog/components/footer.astro';
## Overview
`CreateProduct` is handled by the [[service|product-api]]. It validates the incoming product, writes it to the [[container|product-database]], and on success publishes a [[event|product-created]] event.
## Architecture diagram
## Schema
## Raw Schema:schema.json
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "CreateProduct",
"description": "Command to add a new product to the catalog",
"type": "object",
"properties": {
"sku": {
"description": "Stock keeping unit — must be unique",
"type": "string"
},
"name": {
"description": "Display name of the product",
"type": "string",
"minLength": 1
},
"description": {
"description": "Long-form product description",
"type": "string"
},
"price": {
"description": "Price in minor units (e.g. cents)",
"type": "integer",
"minimum": 0
},
"currency": {
"description": "ISO 4217 currency code",
"type": "string",
"pattern": "^[A-Z]{3}$"
},
"category": {
"description": "Category the product belongs to",
"type": "string"
},
"status": {
"description": "Initial lifecycle status — defaults to DRAFT",
"type": "string",
"enum": ["DRAFT", "ACTIVE", "ARCHIVED"]
}
},
"required": ["sku", "name", "price", "currency"]
}
---
id: create-shipment
name: Create Shipment
version: 1.0.0
summary: |
Command to create a shipment with a carrier for a packed order.
owners:
- fulfilment-platform
schemaPath: schema.json
operation:
method: POST
path: /shipments
statusCodes: ['201', '400', '422']
sidebar:
badge: 'POST'
---
import Footer from '@catalog/components/footer.astro';
## Overview
`CreateShipment` is sent by the [[service|carrier-adapter]] to the external [[system|carrier]] to dispatch a packed order. The carrier responds asynchronously with [[event|shipment-created]] and later [[event|shipment-delivered]] or [[event|shipment-failed]].
## Architecture diagram
## Schema
## Raw Schema:schema.json
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "CreateShipment",
"description": "Command to create a shipment with a carrier for a packed order",
"type": "object",
"properties": {
"orderId": { "type": "string", "format": "uuid" },
"carrier": { "type": "string", "description": "The carrier to ship with" },
"service": {
"type": "string",
"enum": ["STANDARD", "EXPRESS", "NEXT_DAY"]
},
"parcelCount": { "type": "integer", "minimum": 1 },
"destination": {
"type": "object",
"properties": {
"line1": { "type": "string" },
"city": { "type": "string" },
"postcode": { "type": "string" },
"country": { "type": "string", "pattern": "^[A-Z]{2}$" }
},
"required": ["line1", "city", "postcode", "country"]
}
},
"required": ["orderId", "destination"]
}
---
id: delete-product
name: Delete Product
version: 1.0.0
summary: |
Command to remove a product from the catalog.
owners:
- product-platform
schemaPath: schema.json
operation:
method: DELETE
path: /products/{productId}
statusCodes: ['204', '404']
sidebar:
badge: 'DELETE'
---
import Footer from '@catalog/components/footer.astro';
## Overview
`DeleteProduct` is handled by the [[service|product-api]]. It removes a product from the [[container|product-database]] and, on success, publishes a [[event|product-deleted]] event so downstream systems can clean up.
## Architecture diagram
## Schema
## Raw Schema:schema.json
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "DeleteProduct",
"description": "Command to remove a product from the catalog",
"type": "object",
"properties": {
"productId": {
"description": "Unique identifier of the product to delete",
"type": "string",
"format": "uuid"
},
"reason": {
"description": "Optional reason the product is being removed",
"type": "string",
"enum": ["DISCONTINUED", "DUPLICATE", "MERCHANT_REQUEST", "OTHER"]
}
},
"required": ["productId"]
}
---
id: flag-review
name: Flag Review
version: 1.0.0
summary: |
Command issued by a customer or moderator to flag a published review for re-moderation.
owners:
- reviews-platform
schemaPath: schema.json
badges:
- content: 'Broker:Kafka'
backgroundColor: blue
textColor: blue
icon: BoltIcon
---
import Footer from '@catalog/components/footer.astro';
## Overview
`FlagReview` is sent to the [[service|review-api]] when someone reports a published review as inappropriate. The API records the flag and publishes [[event|review-flagged]] so the review can be screened again.
## Architecture diagram
## Raw Schema:schema.json
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "FlagReview",
"type": "object",
"properties": {
"reviewId": { "type": "string", "format": "uuid" },
"flaggedBy": { "type": "string", "description": "Customer or moderator id raising the flag." },
"reason": { "type": "string", "enum": ["spam", "abuse", "off_topic", "inappropriate", "other"] },
"notes": { "type": "string", "maxLength": 1000 },
"flaggedAt": { "type": "string", "format": "date-time" }
},
"required": ["reviewId", "flaggedBy", "reason", "flaggedAt"]
}
---
id: register-customer
name: Register Customer
version: 1.0.0
summary: |
Command to register a new customer.
owners:
- customer-platform
schemaPath: schema.json
operation:
method: POST
path: /customers
statusCodes: ['201', '400', '409']
sidebar:
badge: 'POST'
---
import Footer from '@catalog/components/footer.astro';
## Overview
`RegisterCustomer` is handled by the [[service|customer-api]]. It validates the new customer, writes it to the [[container|customer-database]], and on success publishes a [[event|customer-registered]] event.
## Architecture diagram
## Schema
## Raw Schema:schema.json
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "RegisterCustomer",
"description": "Command to register a new customer",
"type": "object",
"properties": {
"email": {
"description": "Customer's email address — must be unique",
"type": "string",
"format": "email"
},
"name": {
"description": "Customer's full name",
"type": "string",
"minLength": 1
},
"password": {
"description": "Initial password for the customer's credentials",
"type": "string",
"minLength": 8
}
},
"required": ["email", "password"]
}
---
id: release-inventory
name: Release Inventory
version: 1.0.0
summary: |
Command to release a previously held inventory reservation.
owners:
- fulfilment-platform
schemaPath: schema.json
operation:
method: POST
path: /reservations/{reservationId}/release
statusCodes: ['200', '404']
sidebar:
badge: 'POST'
---
import Footer from '@catalog/components/footer.astro';
## Overview
`ReleaseInventory` is handled by the [[service|inventory-service]]. It releases a reservation that is no longer needed — for example when checkout fails after stock was reserved, or an order is cancelled.
## Architecture diagram
## Schema
## Raw Schema:schema.json
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "ReleaseInventory",
"description": "Command to release a previously held inventory reservation",
"type": "object",
"properties": {
"reservationId": { "type": "string", "format": "uuid" },
"reason": {
"type": "string",
"enum": ["CHECKOUT_FAILED", "ORDER_CANCELLED", "EXPIRED"]
}
},
"required": ["reservationId"]
}
---
id: remove-item-from-cart
name: Remove Item From Cart
version: 1.0.0
summary: |
Command to remove an item from a shopping cart.
owners:
- shopping-platform
schemaPath: schema.json
operation:
method: DELETE
path: /carts/{cartId}/items/{productId}
statusCodes: ['200', '404']
sidebar:
badge: 'DELETE'
---
import Footer from '@catalog/components/footer.astro';
## Overview
`RemoveItemFromCart` is handled by the [[service|cart-api]]. It removes an item from the cart (or decreases its quantity) and persists the change to the [[container|cart-database]].
## Architecture diagram
## Schema
## Raw Schema:schema.json
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "RemoveItemFromCart",
"description": "Command to remove an item from a shopping cart",
"type": "object",
"properties": {
"cartId": {
"description": "Unique identifier of the cart",
"type": "string",
"format": "uuid"
},
"productId": {
"description": "Identifier of the product to remove",
"type": "string",
"format": "uuid"
},
"quantity": {
"description": "Number of units to remove. If omitted, removes the item entirely.",
"type": "integer",
"minimum": 1
}
},
"required": ["cartId", "productId"]
}
---
id: reserve-inventory
name: Reserve Inventory
version: 1.0.0
summary: |
Command to reserve stock for the items in a checked-out cart.
owners:
- ordering-platform
schemaPath: schema.json
operation:
method: POST
path: /reservations
statusCodes: ['201', '400', '409']
sidebar:
badge: 'POST'
---
import Footer from '@catalog/components/footer.astro';
## Overview
`ReserveInventory` is sent by the [[service|checkout-orchestrator]] to hold stock for the items in a checked-out cart. A successful reservation guarantees the inventory is available while payment is authorized. If a later checkout step fails, the reservation is released.
## Architecture diagram
## Schema
## Raw Schema:schema.json
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "ReserveInventory",
"description": "Command to reserve stock for the items in a checked-out cart",
"type": "object",
"properties": {
"cartId": {
"description": "Identifier of the cart being checked out",
"type": "string",
"format": "uuid"
},
"customerId": {
"description": "Identifier of the customer checking out",
"type": "string",
"format": "uuid"
},
"items": {
"description": "The items to reserve",
"type": "array",
"items": {
"type": "object",
"properties": {
"productId": {
"type": "string",
"format": "uuid"
},
"quantity": {
"type": "integer",
"minimum": 1
}
},
"required": ["productId", "quantity"]
}
}
},
"required": ["cartId", "items"]
}
---
id: submit-review
name: Submit Review
version: 1.0.0
summary: |
Command issued by a customer to submit a review and rating for a product.
owners:
- reviews-platform
schemaPath: schema.json
badges:
- content: 'Broker:Kafka'
backgroundColor: blue
textColor: blue
icon: BoltIcon
---
import Footer from '@catalog/components/footer.astro';
## Overview
`SubmitReview` is sent to the [[service|review-api]] when a customer submits a review for a product they have purchased. The API validates and stores the review, then publishes [[event|review-submitted]].
## Architecture diagram
## Raw Schema:schema.json
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "SubmitReview",
"type": "object",
"properties": {
"reviewId": { "type": "string", "format": "uuid", "description": "Client-generated id for the review." },
"productId": { "type": "string", "description": "The product being reviewed." },
"customerId": { "type": "string", "description": "The customer submitting the review." },
"rating": { "type": "integer", "minimum": 1, "maximum": 5, "description": "Star rating from 1 to 5." },
"title": { "type": "string", "maxLength": 120 },
"body": { "type": "string", "maxLength": 5000 },
"submittedAt": { "type": "string", "format": "date-time" }
},
"required": ["reviewId", "productId", "customerId", "rating", "body", "submittedAt"]
}
---
id: update-customer
name: Update Customer
version: 1.0.0
summary: |
Command to update an existing customer's profile.
owners:
- customer-platform
schemaPath: schema.json
operation:
method: PATCH
path: /customers/{customerId}
statusCodes: ['200', '400', '404']
sidebar:
badge: 'PATCH'
---
import Footer from '@catalog/components/footer.astro';
## Overview
`UpdateCustomer` is handled by the [[service|customer-api]]. It applies a partial update to an existing customer in the [[container|customer-database]] and, on success, publishes a [[event|customer-updated]] event describing what changed.
## Architecture diagram
## Schema
## Raw Schema:schema.json
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "UpdateCustomer",
"description": "Command to update an existing customer. Only the fields supplied are changed.",
"type": "object",
"properties": {
"customerId": {
"description": "Unique identifier of the customer to update",
"type": "string",
"format": "uuid"
},
"email": {
"description": "New email address",
"type": "string",
"format": "email"
},
"name": {
"description": "New full name",
"type": "string",
"minLength": 1
},
"status": {
"description": "New account status",
"type": "string",
"enum": ["ACTIVE", "SUSPENDED", "CLOSED"]
}
},
"required": ["customerId"]
}
---
id: update-product
name: Update Product
version: 1.0.0
summary: |
Command to update an existing product in the catalog.
owners:
- product-platform
schemaPath: schema.json
operation:
method: PATCH
path: /products/{productId}
statusCodes: ['200', '400', '404']
sidebar:
badge: 'PATCH'
---
import Footer from '@catalog/components/footer.astro';
## Overview
`UpdateProduct` is handled by the [[service|product-api]]. It applies a partial update to an existing product in the [[container|product-database]] and, on success, publishes a [[event|product-updated]] event describing what changed.
## Architecture diagram
## Schema
## Raw Schema:schema.json
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "UpdateProduct",
"description": "Command to update an existing product. Only the fields supplied are changed.",
"type": "object",
"properties": {
"productId": {
"description": "Unique identifier of the product to update",
"type": "string",
"format": "uuid"
},
"name": {
"description": "New display name",
"type": "string",
"minLength": 1
},
"description": {
"description": "New long-form description",
"type": "string"
},
"price": {
"description": "New price in minor units (e.g. cents)",
"type": "integer",
"minimum": 0
},
"currency": {
"description": "ISO 4217 currency code",
"type": "string",
"pattern": "^[A-Z]{3}$"
},
"category": {
"description": "New category",
"type": "string"
},
"status": {
"description": "New lifecycle status",
"type": "string",
"enum": ["DRAFT", "ACTIVE", "ARCHIVED"]
}
},
"required": ["productId"]
}
---
id: vote-review-helpful
name: Vote Review Helpful
version: 1.0.0
summary: |
Command issued by a customer to mark a published review as helpful (or remove their vote).
owners:
- reviews-platform
schemaPath: schema.json
badges:
- content: 'Broker:Kafka'
backgroundColor: blue
textColor: blue
icon: BoltIcon
---
import Footer from '@catalog/components/footer.astro';
## Overview
`VoteReviewHelpful` is sent to the [[service|review-api]] when a customer marks a review as helpful. The API updates the helpful count and publishes [[event|review-helpful-voted]].
## Architecture diagram
## Raw Schema:schema.json
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "VoteReviewHelpful",
"type": "object",
"properties": {
"reviewId": { "type": "string", "format": "uuid" },
"customerId": { "type": "string" },
"vote": { "type": "string", "enum": ["helpful", "remove"], "description": "Add a helpful vote or remove an existing one." },
"votedAt": { "type": "string", "format": "date-time" }
},
"required": ["reviewId", "customerId", "vote", "votedAt"]
}
---
id: get-customer
name: Get Customer
version: 1.0.0
summary: |
Query to fetch a single customer by their identifier.
owners:
- customer-platform
schemaPath: schema.json
operation:
method: GET
path: /customers/{customerId}
statusCodes: ['200', '404']
sidebar:
badge: 'GET'
---
import Footer from '@catalog/components/footer.astro';
## Overview
`GetCustomer` is handled by the [[service|customer-api]]. It returns the current state of a single customer, read directly from the [[container|customer-database]].
## Architecture diagram
## Schema
## Raw Schema:schema.json
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "GetCustomer",
"description": "Query to fetch a single customer by their identifier, and the customer returned",
"type": "object",
"properties": {
"request": {
"description": "Parameters used to look up the customer",
"type": "object",
"properties": {
"customerId": {
"description": "Unique identifier of the customer to fetch",
"type": "string",
"format": "uuid"
}
},
"required": ["customerId"]
},
"response": {
"description": "The customer returned by the query",
"type": "object",
"properties": {
"customerId": {
"type": "string",
"format": "uuid"
},
"email": {
"type": "string",
"format": "email"
},
"name": {
"type": "string"
},
"status": {
"type": "string",
"enum": ["ACTIVE", "SUSPENDED", "CLOSED"]
},
"registeredAt": {
"type": "string",
"format": "date-time"
}
},
"required": ["customerId", "email", "status"]
}
},
"required": ["request", "response"]
}
---
id: get-order
name: Get Order
version: 1.0.0
summary: |
Query to fetch a single order by its identifier.
owners:
- ordering-platform
schemaPath: schema.json
operation:
method: GET
path: /orders/{orderId}
statusCodes: ['200', '404']
sidebar:
badge: 'GET'
---
import Footer from '@catalog/components/footer.astro';
## Overview
`GetOrder` is handled by the [[service|order-service]]. It returns the current state of a single order, read directly from the [[container|order-database]].
## Architecture diagram
## Schema
## Raw Schema:schema.json
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "GetOrder",
"description": "Query to fetch a single order by its identifier, and the order returned",
"type": "object",
"properties": {
"request": {
"description": "Parameters used to look up the order",
"type": "object",
"properties": {
"orderId": {
"description": "Unique identifier of the order to fetch",
"type": "string",
"format": "uuid"
}
},
"required": ["orderId"]
},
"response": {
"description": "The order returned by the query",
"type": "object",
"properties": {
"orderId": {
"type": "string",
"format": "uuid"
},
"customerId": {
"type": "string",
"format": "uuid"
},
"status": {
"type": "string",
"enum": ["CREATED", "COMPLETED", "CANCELLED"]
},
"items": {
"type": "array",
"items": {
"type": "object",
"properties": {
"productId": { "type": "string", "format": "uuid" },
"quantity": { "type": "integer", "minimum": 1 },
"unitPrice": { "type": "integer" }
},
"required": ["productId", "quantity", "unitPrice"]
}
},
"total": {
"type": "integer",
"description": "Order total in minor units (e.g. cents)"
},
"currency": {
"type": "string",
"pattern": "^[A-Z]{3}$"
},
"createdAt": {
"type": "string",
"format": "date-time"
}
},
"required": ["orderId", "customerId", "status", "items", "total", "currency"]
}
},
"required": ["request", "response"]
}
---
id: get-product
name: Get Product
version: 1.0.0
summary: |
Query to fetch a single product by its identifier.
owners:
- product-platform
schemaPath: schema.json
operation:
method: GET
path: /products/{productId}
statusCodes: ['200', '404']
sidebar:
badge: 'GET'
---
import Footer from '@catalog/components/footer.astro';
## Overview
`GetProduct` is handled by the [[service|product-api]]. It returns the current state of a single product, read directly from the [[container|product-database]]. Use the [[system|search-system]] when you need to search across many products instead.
## Architecture diagram
## Schema
## Raw Schema:schema.json
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "GetProduct",
"description": "Query to fetch a single product by its identifier, and the product returned",
"type": "object",
"properties": {
"request": {
"description": "Parameters used to look up the product",
"type": "object",
"properties": {
"productId": {
"description": "Unique identifier of the product to fetch",
"type": "string",
"format": "uuid"
}
},
"required": ["productId"]
},
"response": {
"description": "The product returned by the query",
"type": "object",
"properties": {
"productId": {
"type": "string",
"format": "uuid"
},
"sku": {
"type": "string"
},
"name": {
"type": "string"
},
"description": {
"type": "string"
},
"price": {
"description": "Price in minor units (e.g. cents)",
"type": "integer"
},
"currency": {
"type": "string",
"pattern": "^[A-Z]{3}$"
},
"category": {
"type": "string"
},
"status": {
"type": "string",
"enum": ["DRAFT", "ACTIVE", "ARCHIVED"]
}
},
"required": ["productId", "sku", "name", "price", "currency", "status"]
}
},
"required": ["request", "response"]
}
---
id: get-product-reviews
name: Get Product Reviews
version: 1.0.0
summary: |
Query to fetch the published reviews and aggregate rating for a product.
owners:
- reviews-platform
schemaPath: schema.json
---
import Footer from '@catalog/components/footer.astro';
## Overview
`GetProductReviews` is served by the [[service|review-api]]. It returns the published reviews for a product along with its aggregate rating, read from the [[container|review-database]] and the [[container|rating-cache]].
## Architecture diagram
## Raw Schema:schema.json
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "GetProductReviews",
"type": "object",
"properties": {
"productId": { "type": "string", "description": "The product to fetch reviews for." },
"page": { "type": "integer", "minimum": 1, "default": 1 },
"pageSize": { "type": "integer", "minimum": 1, "maximum": 100, "default": 20 },
"sort": { "type": "string", "enum": ["newest", "highest", "lowest", "most_helpful"], "default": "newest" }
},
"required": ["productId"]
}
---
id: get-stock-level
name: Get Stock Level
version: 1.0.0
summary: |
Query to fetch the current available stock level for a product.
owners:
- fulfilment-platform
schemaPath: schema.json
operation:
method: GET
path: /stock/{productId}
statusCodes: ['200', '404']
sidebar:
badge: 'GET'
---
import Footer from '@catalog/components/footer.astro';
## Overview
`GetStockLevel` is handled by the [[service|inventory-service]]. It returns the current available stock for a product, read directly from the [[container|inventory-database]].
## Architecture diagram
## Schema
## Raw Schema:schema.json
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "GetStockLevel",
"description": "Query to fetch the current available stock level for a product, and the level returned",
"type": "object",
"properties": {
"request": {
"type": "object",
"properties": {
"productId": { "type": "string", "format": "uuid" }
},
"required": ["productId"]
},
"response": {
"type": "object",
"properties": {
"productId": { "type": "string", "format": "uuid" },
"available": { "type": "integer", "minimum": 0 },
"reserved": { "type": "integer", "minimum": 0 }
},
"required": ["productId", "available"]
}
},
"required": ["request", "response"]
}
---
id: search-products
name: Search Products
version: 1.0.0
summary: |
Query to search the catalog for products matching a term, with optional filters and pagination.
owners:
- search-platform
schemaPath: schema.json
operation:
method: GET
path: /search/products
statusCodes: ['200', '400']
sidebar:
badge: 'GET'
---
import Footer from '@catalog/components/footer.astro';
## Overview
`SearchProducts` is handled by the [[service|search-api]]. It runs a full-text search over the [[container|search-index]] and returns a paginated list of matching products. Use this whenever you need to find products across the catalog, rather than fetching a single product by id with [[query|get-product]].
## Architecture diagram
## Schema
## Raw Schema:schema.json
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "SearchProducts",
"description": "Query to search the catalog for products, and the paginated result returned",
"type": "object",
"properties": {
"request": {
"description": "Search parameters",
"type": "object",
"properties": {
"query": {
"description": "Free-text search term",
"type": "string",
"minLength": 1
},
"filters": {
"description": "Optional filters applied to the search",
"type": "object",
"properties": {
"category": {
"type": "string"
},
"status": {
"type": "string",
"enum": ["DRAFT", "ACTIVE", "ARCHIVED"]
},
"minPrice": {
"description": "Minimum price in minor units (e.g. cents)",
"type": "integer",
"minimum": 0
},
"maxPrice": {
"description": "Maximum price in minor units (e.g. cents)",
"type": "integer",
"minimum": 0
}
}
},
"page": {
"description": "1-based page number",
"type": "integer",
"minimum": 1,
"default": 1
},
"pageSize": {
"description": "Number of results per page",
"type": "integer",
"minimum": 1,
"maximum": 100,
"default": 20
}
},
"required": ["query"]
},
"response": {
"description": "Paginated search results",
"type": "object",
"properties": {
"total": {
"description": "Total number of products matching the query",
"type": "integer"
},
"page": {
"type": "integer"
},
"pageSize": {
"type": "integer"
},
"results": {
"type": "array",
"items": {
"type": "object",
"properties": {
"productId": {
"type": "string",
"format": "uuid"
},
"sku": {
"type": "string"
},
"name": {
"type": "string"
},
"category": {
"type": "string"
},
"price": {
"description": "Price in minor units (e.g. cents)",
"type": "integer"
},
"currency": {
"type": "string",
"pattern": "^[A-Z]{3}$"
},
"score": {
"description": "Relevance score for this result",
"type": "number"
}
},
"required": ["productId", "sku", "name"]
}
}
},
"required": ["total", "page", "pageSize", "results"]
}
},
"required": ["request", "response"]
}
---
id: carrier-adapter
version: 1.0.0
name: Carrier Adapter
summary: |
Translates Acme Inc shipment requests into the external carrier's format and sends them to create a shipment.
styles:
icon: /icons/languages/go.svg
owners:
- fulfilment-platform
sends:
- id: create-shipment
version: 1.0.0
repository:
language: Go
url: 'https://github.com/acme/carrier-adapter'
---
import Footer from '@catalog/components/footer.astro';
## Overview
The **Carrier Adapter** is the anti-corruption layer between Acme Inc and its carriers. It takes a shipment request from the [[service|shipping-api]], maps it to the external [[system|carrier]]'s API, and sends a [[command|create-shipment]] to dispatch the parcel.
## Architecture diagram
---
id: carrier-shipping-api
version: 1.0.0
name: Shipping API
summary: |
The carrier's API for creating shipments. Acme Inc's Shipping System calls it to dispatch packed orders.
styles:
icon: /icons/languages/nodejs.svg
owners:
- fulfilment-platform
receives:
- id: create-shipment
version: 1.0.0
repository:
language: External
url: 'https://github.com/acme/carrier-integration'
---
import Footer from '@catalog/components/footer.astro';
## Overview
The **Shipping API** is the carrier's external interface for creating shipments. The [[system|shipping-system]] sends [[command|create-shipment]], and the carrier dispatches the parcel and begins reporting progress through its [[service|carrier-tracking-api]].
## Architecture diagram
---
id: carrier-tracking-api
version: 1.0.0
name: Tracking API
summary: |
The carrier's API for reporting delivery progress. It notifies Acme Inc when a shipment is created, delivered, or fails.
styles:
icon: /icons/languages/nodejs.svg
owners:
- fulfilment-platform
sends:
- id: shipment-created
version: 1.0.0
- id: shipment-delivered
version: 1.0.0
- id: shipment-failed
version: 1.0.0
repository:
language: External
url: 'https://github.com/acme/carrier-integration'
---
import Footer from '@catalog/components/footer.astro';
## Overview
The **Tracking API** is how the carrier reports delivery progress back to Acme Inc. After a shipment is created via the [[service|carrier-shipping-api]], it emits [[event|shipment-created]], then [[event|shipment-delivered]] on success or [[event|shipment-failed]] if delivery cannot be completed.
## Architecture diagram
---
id: cart-api
version: 1.0.0
name: Cart API
summary: |
The public-facing API for shopping carts. Handles commands to add and remove items and to check out, and publishes an event when a cart is checked out.
styles:
icon: /icons/languages/nodejs.svg
owners:
- shopping-platform
receives:
- id: add-item-to-cart
version: 1.0.0
- id: remove-item-from-cart
version: 1.0.0
- id: checkout-cart
version: 1.0.0
sends:
- id: cart-checked-out
version: 1.0.0
- id: calculate-discount
version: 1.0.0
writesTo:
- id: cart-database
readsFrom:
- id: cart-database
repository:
language: TypeScript
url: 'https://github.com/acme/cart-api'
specifications:
- type: openapi
path: openapi.yml
name: Cart API
---
import Footer from '@catalog/components/footer.astro';
## Overview
The **Cart API** is the front door to the Cart System. It validates incoming commands, persists cart contents to the [[container|cart-database]], asks the [[system|promotion-system]] to calculate discounts via [[command|calculate-discount]], and publishes a [[event|cart-checked-out]] event when the customer checks out.
### Responsibilities
| Area | Description |
|------|-------------|
| Cart management | Validates and applies [[command\|add-item-to-cart]], [[command\|remove-item-from-cart]] and [[command\|checkout-cart]]. |
| Discounts | Requests pricing from the Promotion System via [[command\|calculate-discount]]. |
| Event publishing | Emits [[event\|cart-checked-out]] when a cart is checked out. |
| Persistence | Reads from and writes to the [[container\|cart-database]] (system of record). |
## Architecture diagram
## Raw Schema:openapi.yml
openapi: 3.0.3
info:
title: Cart API
version: 1.0.0
description: |
Public-facing API for the Cart System. Customers use it to build a cart —
adding and removing items — and to check out. At checkout the cart is priced
(including discounts from the Promotion System) and a `CartCheckedOut` event
is published.
contact:
name: Shopping Platform
email: shopping-platform@acme.test
servers:
- url: https://api.acme.test
description: Production
tags:
- name: Cart
description: Build and check out a shopping cart.
paths:
/carts/{cartId}/items:
parameters:
- $ref: '#/components/parameters/CartId'
post:
operationId: addItemToCart
summary: Add an item to the cart
tags:
- Cart
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/AddItemRequest'
responses:
'200':
description: The item was added; the updated cart is returned.
content:
application/json:
schema:
$ref: '#/components/schemas/Cart'
'400':
description: The request was invalid.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'404':
description: The cart was not found.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
/carts/{cartId}/items/{productId}:
parameters:
- $ref: '#/components/parameters/CartId'
- name: productId
in: path
required: true
description: Identifier of the product to remove.
schema:
type: string
format: uuid
delete:
operationId: removeItemFromCart
summary: Remove an item from the cart
tags:
- Cart
responses:
'200':
description: The item was removed; the updated cart is returned.
content:
application/json:
schema:
$ref: '#/components/schemas/Cart'
'404':
description: The cart or item was not found.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
/carts/{cartId}/checkout:
parameters:
- $ref: '#/components/parameters/CartId'
post:
operationId: checkoutCart
summary: Check out the cart
description: Prices the cart (including discounts) and, on success, publishes a `CartCheckedOut` event.
tags:
- Cart
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/CheckoutRequest'
responses:
'200':
description: The cart was checked out.
content:
application/json:
schema:
$ref: '#/components/schemas/Cart'
'400':
description: The request was invalid.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'404':
description: The cart was not found.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'409':
description: The cart is empty or already checked out.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
components:
parameters:
CartId:
name: cartId
in: path
required: true
description: Unique identifier of the cart.
schema:
type: string
format: uuid
schemas:
Cart:
type: object
required: [cartId, status, items, currency]
properties:
cartId:
type: string
format: uuid
customerId:
type: string
format: uuid
status:
type: string
enum: [OPEN, CHECKED_OUT, ABANDONED]
items:
type: array
items:
$ref: '#/components/schemas/CartItem'
subtotal:
type: integer
description: Total before discounts, in minor units (e.g. cents).
discount:
type: integer
description: Total discount applied, in minor units (e.g. cents).
total:
type: integer
description: Final total, in minor units (e.g. cents).
currency:
type: string
pattern: '^[A-Z]{3}$'
CartItem:
type: object
required: [productId, quantity, unitPrice]
properties:
productId:
type: string
format: uuid
quantity:
type: integer
minimum: 1
unitPrice:
type: integer
description: Price per unit in minor units (e.g. cents).
AddItemRequest:
type: object
required: [productId, quantity]
properties:
productId:
type: string
format: uuid
quantity:
type: integer
minimum: 1
CheckoutRequest:
type: object
required: [customerId]
properties:
customerId:
type: string
format: uuid
promotionCode:
type: string
Error:
type: object
required: [code, message]
properties:
code:
type: string
message:
type: string
---
id: checkout-api
version: 1.0.0
name: Checkout API
summary: |
The entry point to the Checkout System. Receives the checkout command from the Shopping domain and starts the checkout flow.
styles:
icon: /icons/languages/nodejs.svg
owners:
- ordering-platform
receives:
- id: checkout-cart
version: 1.0.0
repository:
language: TypeScript
url: 'https://github.com/acme/checkout-api'
---
import Footer from '@catalog/components/footer.astro';
## Overview
The **Checkout API** is the front door to the Checkout System. When the [[domain|shopping]] domain checks out a cart, this service receives the [[command|checkout-cart]] command, validates it, and hands the work to the [[service|checkout-orchestrator]] to run the checkout saga.
### Responsibilities
| Area | Description |
|------|-------------|
| Checkout entry | Receives and validates [[command\|checkout-cart]] from the Shopping domain. |
| Orchestration handoff | Starts a checkout saga in the [[service\|checkout-orchestrator]]. |
## Architecture diagram
---
id: checkout-orchestrator
version: 1.0.0
name: Checkout Orchestrator
summary: |
Runs the checkout saga. Reserves inventory, authorizes payment and creates the order, coordinating the steps that turn a checked-out cart into a confirmed order.
styles:
icon: /icons/languages/nodejs.svg
owners:
- ordering-platform
sends:
- id: reserve-inventory
version: 1.0.0
- id: authorize-payment
version: 1.0.0
- id: create-order
version: 1.0.0
repository:
language: TypeScript
url: 'https://github.com/acme/checkout-orchestrator'
---
import Footer from '@catalog/components/footer.astro';
## Overview
The **Checkout Orchestrator** is the brain of the Checkout System. Once the [[service|checkout-api]] hands it a checkout, it runs the checkout saga step by step:
1. **Reserve inventory** — sends [[command|reserve-inventory]] to hold stock for the cart's items.
2. **Authorize payment** — sends [[command|authorize-payment]] to authorize the order total.
3. **Create the order** — sends [[command|create-order]] to the [[system|order-management-system]].
If any step fails, the orchestrator compensates the earlier steps (releasing the reservation, voiding the authorization) so the customer is never left in an inconsistent state.
### Responsibilities
| Area | Description |
|------|-------------|
| Inventory | Reserves stock via [[command\|reserve-inventory]]. |
| Payment | Authorizes the order total via [[command\|authorize-payment]]. |
| Order creation | Creates the order via [[command\|create-order]] against the [[system\|order-management-system]]. |
| Compensation | Rolls back earlier steps if a later step fails. |
## Architecture diagram
---
id: customer-api
version: 1.0.0
name: Customer API
summary: |
The public-facing API for customer profiles. Handles commands to register and update customers, serves customer reads, and publishes customer change events.
styles:
icon: /icons/languages/nodejs.svg
owners:
- customer-platform
receives:
- id: register-customer
version: 1.0.0
- id: update-customer
version: 1.0.0
- id: get-customer
version: 1.0.0
sends:
- id: customer-registered
version: 1.0.0
- id: customer-updated
version: 1.0.0
writesTo:
- id: customer-database
readsFrom:
- id: customer-database
repository:
language: TypeScript
url: 'https://github.com/acme/customer-api'
specifications:
- type: openapi
path: openapi.yml
name: Customer API
---
import Footer from '@catalog/components/footer.astro';
## Overview
The **Customer API** is the front door to the Customer Management System. It validates incoming commands, persists customer data to the [[container|customer-database]], and publishes domain events (CustomerRegistered, CustomerUpdated) so the rest of the business can react to changes.
### Responsibilities
| Area | Description |
|------|-------------|
| Command handling | Validates and applies [[command\|register-customer]] and [[command\|update-customer]]. |
| Reads | Serves [[query\|get-customer]] directly from the customer database. |
| Event publishing | Emits [[event\|customer-registered]] and [[event\|customer-updated]] on every change. |
| Persistence | Reads from and writes to the [[container\|customer-database]] (system of record). |
## Architecture diagram
## Raw Schema:openapi.yml
openapi: 3.0.3
info:
title: Customer API
version: 1.0.0
description: |
Public-facing API for the Customer Management System. It is the entry point
for registering, updating and reading customers. Every change is persisted
to the customer database and published as a customer change event.
contact:
name: Customer Platform
email: customer-platform@acme.test
servers:
- url: https://api.acme.test
description: Production
tags:
- name: Customers
description: Manage and read customer profiles.
paths:
/customers:
post:
operationId: registerCustomer
summary: Register a customer
description: Registers a new customer. On success a `CustomerRegistered` event is published.
tags:
- Customers
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/RegisterCustomerRequest'
responses:
'201':
description: The customer was registered.
content:
application/json:
schema:
$ref: '#/components/schemas/Customer'
'400':
description: The request body was invalid.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'409':
description: A customer with the same email already exists.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
/customers/{customerId}:
parameters:
- name: customerId
in: path
required: true
description: Unique identifier of the customer.
schema:
type: string
format: uuid
get:
operationId: getCustomer
summary: Get a customer
description: Returns the current state of a single customer by their identifier.
tags:
- Customers
responses:
'200':
description: The customer was found.
content:
application/json:
schema:
$ref: '#/components/schemas/Customer'
'404':
description: No customer exists with that identifier.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
patch:
operationId: updateCustomer
summary: Update a customer
description: Applies a partial update to an existing customer. On success a `CustomerUpdated` event is published.
tags:
- Customers
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/UpdateCustomerRequest'
responses:
'200':
description: The customer was updated.
content:
application/json:
schema:
$ref: '#/components/schemas/Customer'
'400':
description: The request body was invalid.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'404':
description: No customer exists with that identifier.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
components:
schemas:
Customer:
type: object
required: [customerId, email, status]
properties:
customerId:
type: string
format: uuid
email:
type: string
format: email
name:
type: string
status:
type: string
enum: [ACTIVE, SUSPENDED, CLOSED]
registeredAt:
type: string
format: date-time
RegisterCustomerRequest:
type: object
required: [email, password]
properties:
email:
type: string
format: email
name:
type: string
minLength: 1
password:
type: string
minLength: 8
UpdateCustomerRequest:
type: object
description: Only the fields supplied are changed.
minProperties: 1
properties:
email:
type: string
format: email
name:
type: string
minLength: 1
status:
type: string
enum: [ACTIVE, SUSPENDED, CLOSED]
Error:
type: object
required: [code, message]
properties:
code:
type: string
message:
type: string
---
id: fraud-api
version: 1.0.0
name: Fraud API
summary: |
External fraud screening API. It consumes payment requests and returns a pass or fail verdict for each.
styles:
icon: /icons/languages/nodejs.svg
owners:
- payments-platform
receives:
- id: payment-requested
version: 1.0.0
sends:
- id: fraud-check-passed
version: 1.0.0
- id: fraud-check-failed
version: 1.0.0
repository:
language: External
url: 'https://github.com/acme/fraud-api'
---
import Footer from '@catalog/components/footer.astro';
## Overview
The **Fraud API** screens payments for fraud. It consumes [[event|payment-requested]] from the [[system|payment-processing-system]] and returns a verdict — [[event|fraud-check-passed]] or [[event|fraud-check-failed]] — which the Payments domain uses to allow or block the charge.
## Architecture diagram
---
id: inventory-service
version: 1.0.0
name: Inventory Service
summary: |
The system of record for stock. Reserves and releases inventory, serves stock-level queries, and publishes events when stock is reserved or unavailable.
styles:
icon: /icons/languages/java.svg
owners:
- fulfilment-platform
receives:
- id: reserve-inventory
version: 1.0.0
- id: release-inventory
version: 1.0.0
- id: get-stock-level
version: 1.0.0
sends:
- id: inventory-reserved
version: 1.0.0
- id: inventory-unavailable
version: 1.0.0
writesTo:
- id: inventory-database
readsFrom:
- id: inventory-database
repository:
language: Java
url: 'https://github.com/acme/inventory-service'
---
import Footer from '@catalog/components/footer.astro';
## Overview
The **Inventory Service** is the heart of the Inventory System. It receives [[command|reserve-inventory]] during checkout and replies with [[event|inventory-reserved]] or [[event|inventory-unavailable]]. It also handles [[command|release-inventory]] and serves [[query|get-stock-level]] reads, all backed by the [[container|inventory-database]].
### Responsibilities
| Area | Description |
|------|-------------|
| Reservations | Handles [[command\|reserve-inventory]] and [[command\|release-inventory]]. |
| Lookups | Serves [[query\|get-stock-level]] from the [[container\|inventory-database]]. |
| Event publishing | Emits [[event\|inventory-reserved]] and [[event\|inventory-unavailable]]. |
## Architecture diagram
---
id: oauth-api
version: 1.0.0
name: OAuth API
summary: |
OAuth-style authentication API for the Identity Provider. Verifies customer credentials and publishes an event when a customer successfully authenticates.
styles:
icon: /icons/languages/nodejs.svg
owners:
- customer-platform
receives:
- id: authenticate-customer
version: 1.0.0
sends:
- id: customer-authenticated
version: 1.0.0
readsFrom:
- id: user-directory
repository:
language: TypeScript
url: 'https://github.com/acme/oauth-api'
---
import Footer from '@catalog/components/footer.astro';
## Overview
The **OAuth API** is the authentication entry point for Acme Inc. It verifies credentials against the [[container|user-directory]] and, on a successful sign-in, publishes a [[event|customer-authenticated]] event so other systems can react.
### Responsibilities
| Area | Description |
|------|-------------|
| Authentication | Handles [[command\|authenticate-customer]] and verifies credentials. |
| Event publishing | Emits [[event\|customer-authenticated]] on a successful sign-in. |
| Credentials | Reads from the [[container\|user-directory]] — the source of truth for credentials. |
## Architecture diagram
---
id: order-service
version: 1.0.0
name: Order Service
summary: |
The system of record for orders. Creates and cancels orders, serves order lookups, and publishes events as orders move through their lifecycle.
styles:
icon: /icons/languages/java.svg
owners:
- ordering-platform
receives:
- id: create-order
version: 1.0.0
- id: cancel-order
version: 1.0.0
- id: get-order
version: 1.0.0
sends:
- id: order-created
version: 1.0.0
- id: order-completed
version: 1.0.0
- id: order-cancelled
version: 1.0.0
writesTo:
- id: order-database
readsFrom:
- id: order-database
repository:
language: Java
url: 'https://github.com/acme/order-service'
specifications:
- type: asyncapi
path: asyncapi.yml
name: Order Service AsyncAPI
---
import Footer from '@catalog/components/footer.astro';
## Overview
The **Order Service** is the heart of the Order Management System. It receives [[command|create-order]] from the [[system|checkout-system]], persists orders to the [[container|order-database]], and serves order lookups via [[query|get-order]]. It also handles [[command|cancel-order]]. As orders move through their lifecycle it publishes [[event|order-created]], [[event|order-completed]] and [[event|order-cancelled]] events.
### Responsibilities
| Area | Description |
|------|-------------|
| Order creation | Handles [[command\|create-order]] from the Checkout System and persists the order. |
| Order cancellation | Handles [[command\|cancel-order]] and compensates downstream where needed. |
| Order lookups | Serves [[query\|get-order]] from the [[container\|order-database]]. |
| Event publishing | Emits [[event\|order-created]], [[event\|order-completed]] and [[event\|order-cancelled]]. |
## Architecture diagram
## Raw Schema:asyncapi.yml
asyncapi: 3.0.0
info:
title: Order Service
version: 1.0.0
description: |
The event-driven interface of the Order Service — the system of record for orders.
The service consumes commands to create and cancel orders, and publishes events as
orders move through their lifecycle (created, completed, cancelled). Query access
(`GetOrder`) is served over the REST API and is not part of this AsyncAPI document.
contact:
name: Ordering Platform
email: ordering-platform@acme.test
defaultContentType: application/json
servers:
production:
host: broker.acme.test:9092
protocol: kafka
description: Production Kafka cluster.
channels:
orderCommands:
address: ordering.commands
title: Order commands
description: Commands the Order Service consumes to create and cancel orders.
messages:
CreateOrder:
$ref: '#/components/messages/CreateOrder'
CancelOrder:
$ref: '#/components/messages/CancelOrder'
orderEvents:
address: ordering.orders
title: Order lifecycle events
description: Events the Order Service publishes as orders move through their lifecycle.
messages:
OrderCreated:
$ref: '#/components/messages/OrderCreated'
OrderCompleted:
$ref: '#/components/messages/OrderCompleted'
OrderCancelled:
$ref: '#/components/messages/OrderCancelled'
operations:
receiveCreateOrder:
action: receive
title: Create Order
summary: Create a new order from a checked-out cart.
channel:
$ref: '#/channels/orderCommands'
messages:
- $ref: '#/channels/orderCommands/messages/CreateOrder'
receiveCancelOrder:
action: receive
title: Cancel Order
summary: Cancel an existing order.
channel:
$ref: '#/channels/orderCommands'
messages:
- $ref: '#/channels/orderCommands/messages/CancelOrder'
publishOrderCreated:
action: send
title: Order Created
summary: Published when a new order has been created.
channel:
$ref: '#/channels/orderEvents'
messages:
- $ref: '#/channels/orderEvents/messages/OrderCreated'
publishOrderCompleted:
action: send
title: Order Completed
summary: Published when an order has been fulfilled and completed.
channel:
$ref: '#/channels/orderEvents'
messages:
- $ref: '#/channels/orderEvents/messages/OrderCompleted'
publishOrderCancelled:
action: send
title: Order Cancelled
summary: Published when an order has been cancelled.
channel:
$ref: '#/channels/orderEvents'
messages:
- $ref: '#/channels/orderEvents/messages/OrderCancelled'
components:
messages:
CreateOrder:
name: CreateOrder
title: Create Order
summary: Command to create a new order from a checked-out cart.
payload:
$ref: '#/components/schemas/CreateOrder'
CancelOrder:
name: CancelOrder
title: Cancel Order
summary: Command to cancel an existing order.
payload:
$ref: '#/components/schemas/CancelOrder'
OrderCreated:
name: OrderCreated
title: Order Created
summary: Published when a new order has been created.
payload:
$ref: '#/components/schemas/OrderCreated'
OrderCompleted:
name: OrderCompleted
title: Order Completed
summary: Published when an order has been fulfilled and completed.
payload:
$ref: '#/components/schemas/OrderCompleted'
OrderCancelled:
name: OrderCancelled
title: Order Cancelled
summary: Published when an order has been cancelled.
payload:
$ref: '#/components/schemas/OrderCancelled'
schemas:
OrderItem:
type: object
required: [productId, quantity, unitPrice]
properties:
productId:
type: string
format: uuid
quantity:
type: integer
minimum: 1
unitPrice:
type: integer
description: Price per unit in minor units (e.g. cents).
CancellationReason:
type: string
enum: [CUSTOMER_REQUESTED, PAYMENT_FAILED, OUT_OF_STOCK, FRAUD]
CreateOrder:
type: object
description: Command to create a new order from a checked-out cart.
required: [cartId, customerId, items, total, currency]
properties:
cartId:
type: string
format: uuid
customerId:
type: string
format: uuid
items:
type: array
items:
$ref: '#/components/schemas/OrderItem'
total:
type: integer
minimum: 0
description: Order total in minor units (e.g. cents).
currency:
type: string
pattern: '^[A-Z]{3}$'
paymentAuthorizationId:
type: string
description: Identifier of the payment authorization for this order.
CancelOrder:
type: object
description: Command to cancel an existing order.
required: [orderId, reason]
properties:
orderId:
type: string
format: uuid
reason:
$ref: '#/components/schemas/CancellationReason'
OrderCreated:
type: object
description: Published when a new order has been created.
required: [orderId, customerId, total, currency, createdAt]
properties:
orderId:
type: string
format: uuid
customerId:
type: string
format: uuid
total:
type: integer
description: Order total in minor units (e.g. cents).
currency:
type: string
pattern: '^[A-Z]{3}$'
createdAt:
type: string
format: date-time
OrderCompleted:
type: object
description: Published when an order has been fulfilled and completed.
required: [orderId, customerId, completedAt]
properties:
orderId:
type: string
format: uuid
customerId:
type: string
format: uuid
completedAt:
type: string
format: date-time
OrderCancelled:
type: object
description: Published when an order has been cancelled.
required: [orderId, reason, cancelledAt]
properties:
orderId:
type: string
format: uuid
customerId:
type: string
format: uuid
reason:
$ref: '#/components/schemas/CancellationReason'
cancelledAt:
type: string
format: date-time
---
id: payment-api
version: 1.0.0
name: Payment API
summary: |
Receives payment authorization requests from the Ordering domain and records the payment intent, kicking off the charge against the payment processor.
styles:
icon: /icons/languages/nodejs.svg
owners:
- payments-platform
receives:
- id: authorize-payment
version: 1.0.0
writesTo:
- id: payment-database
readsFrom:
- id: payment-database
repository:
language: TypeScript
url: 'https://github.com/acme/payment-api'
---
import Footer from '@catalog/components/footer.astro';
## Overview
The **Payment API** is the entry point to the Payment Processing System. It receives [[command|authorize-payment]] from the Ordering domain, records the payment intent in the [[container|payment-database]], and leaves the [[service|payment-worker]] to drive the charge against [[system|stripe]].
### Responsibilities
| Area | Description |
|------|-------------|
| Authorization | Receives and validates [[command\|authorize-payment]]. |
| Persistence | Records payment intent in the [[container\|payment-database]]. |
## Architecture diagram
---
id: payment-worker
version: 1.0.0
name: Payment Worker
summary: |
Drives charges and refunds against the external payment processor and records the outcomes. It requests payments and refunds, and consumes the success/failure events Stripe returns.
styles:
icon: /icons/languages/go.svg
owners:
- payments-platform
receives:
- id: payment-succeeded
version: 1.0.0
- id: payment-failed
version: 1.0.0
sends:
- id: payment-requested
version: 1.0.0
- id: refund-requested
version: 1.0.0
writesTo:
- id: payment-database
readsFrom:
- id: payment-database
repository:
language: Go
url: 'https://github.com/acme/payment-worker'
---
import Footer from '@catalog/components/footer.astro';
## Overview
The **Payment Worker** drives money movement. It requests charges from the external [[system|stripe]] via [[event|payment-requested]] and refunds via [[event|refund-requested]], then consumes the [[event|payment-succeeded]] and [[event|payment-failed]] events Stripe returns and records the outcome in the [[container|payment-database]].
### Responsibilities
| Area | Description |
|------|-------------|
| Charging | Requests charges via [[event\|payment-requested]]. |
| Refunds | Requests refunds via [[event\|refund-requested]]. |
| Outcomes | Consumes [[event\|payment-succeeded]] / [[event\|payment-failed]] and records them. |
| Persistence | Reads from and writes to the [[container\|payment-database]]. |
## Architecture diagram
---
id: picking-worker
version: 1.0.0
name: Picking Worker
summary: |
Works through picking jobs on the warehouse floor and signals when an order has been picked and packed.
styles:
icon: /icons/languages/go.svg
owners:
- fulfilment-platform
sends:
- id: order-packed
version: 1.0.0
readsFrom:
- id: warehouse-database
writesTo:
- id: warehouse-database
repository:
language: Go
url: 'https://github.com/acme/picking-worker'
---
import Footer from '@catalog/components/footer.astro';
## Overview
The **Picking Worker** processes picking jobs created by the [[service|warehouse-service]]. As warehouse staff pick and pack each order, the worker updates the job in the [[container|warehouse-database]] and publishes [[event|order-packed]] when the order is complete.
## Architecture diagram
---
id: product-api
version: 1.0.0
name: Product API
summary: |
The public-facing API for the product catalog. Handles commands to create, update and delete products, serves product reads, and is the entry point into the Product Catalog System.
styles:
icon: /icons/languages/nodejs.svg
owners:
- product-platform
receives:
- id: create-product
version: 1.0.0
- id: update-product
version: 1.0.0
- id: delete-product
version: 1.0.0
- id: get-product
version: 1.0.0
writesTo:
- id: product-database
readsFrom:
- id: product-database
repository:
language: TypeScript
url: 'https://github.com/acme/product-api'
specifications:
- type: openapi
path: openapi.yml
name: Product API
---
import Footer from '@catalog/components/footer.astro';
## Overview
The **Product API** is the front door to the Product Catalog System. It validates incoming commands, persists product data to the [[container|product-database]], and records every change to the outbox. The [[service|product-search-publisher]] then turns those changes into the domain events the rest of the business consumes.
### Responsibilities
| Area | Description |
|------|-------------|
| Command handling | Validates and applies [[command\|create-product]], [[command\|update-product]] and [[command\|delete-product]]. |
| Reads | Serves [[query\|get-product]] directly from the product database. |
| Change capture | Records every product change to the outbox in the [[container\|product-database]] for the [[service\|product-search-publisher]] to publish. |
| Persistence | Reads from and writes to the [[container\|product-database]] (system of record). |
## Architecture diagram
## Raw Schema:openapi.yml
openapi: 3.0.3
info:
title: Product API
version: 1.0.0
description: |
Public-facing API for the Product Catalog System. It is the entry point for
creating, updating, deleting and reading products. Every change is persisted
to the product database and recorded in the outbox so product change events
can be published to the rest of the business.
contact:
name: Product Platform
email: product-platform@acme.test
servers:
- url: https://api.acme.test
description: Production
tags:
- name: Products
description: Manage and read products in the catalog.
paths:
/products:
post:
operationId: createProduct
summary: Create a product
description: Adds a new product to the catalog. On success a `ProductCreated` event is published.
tags:
- Products
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/CreateProductRequest'
responses:
'201':
description: The product was created.
content:
application/json:
schema:
$ref: '#/components/schemas/Product'
'400':
description: The request body was invalid.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'409':
description: A product with the same SKU already exists.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
/products/{productId}:
parameters:
- $ref: '#/components/parameters/ProductId'
get:
operationId: getProduct
summary: Get a product
description: Returns the current state of a single product by its identifier.
tags:
- Products
responses:
'200':
description: The product was found.
content:
application/json:
schema:
$ref: '#/components/schemas/Product'
'404':
description: No product exists with that identifier.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
patch:
operationId: updateProduct
summary: Update a product
description: Applies a partial update to an existing product. On success a `ProductUpdated` event is published.
tags:
- Products
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/UpdateProductRequest'
responses:
'200':
description: The product was updated.
content:
application/json:
schema:
$ref: '#/components/schemas/Product'
'400':
description: The request body was invalid.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'404':
description: No product exists with that identifier.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
delete:
operationId: deleteProduct
summary: Delete a product
description: Removes a product from the catalog. On success a `ProductDeleted` event is published.
tags:
- Products
parameters:
- name: reason
in: query
required: false
description: Optional reason the product is being removed.
schema:
type: string
enum: [DISCONTINUED, DUPLICATE, MERCHANT_REQUEST, OTHER]
responses:
'204':
description: The product was deleted.
'404':
description: No product exists with that identifier.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
components:
parameters:
ProductId:
name: productId
in: path
required: true
description: Unique identifier of the product.
schema:
type: string
format: uuid
schemas:
Product:
type: object
required: [productId, sku, name, price, currency, status]
properties:
productId:
type: string
format: uuid
sku:
type: string
description: Stock keeping unit.
name:
type: string
description:
type: string
price:
type: integer
description: Price in minor units (e.g. cents).
minimum: 0
currency:
type: string
pattern: '^[A-Z]{3}$'
category:
type: string
status:
type: string
enum: [DRAFT, ACTIVE, ARCHIVED]
CreateProductRequest:
type: object
required: [sku, name, price, currency]
properties:
sku:
type: string
description: Stock keeping unit — must be unique.
name:
type: string
minLength: 1
description:
type: string
price:
type: integer
description: Price in minor units (e.g. cents).
minimum: 0
currency:
type: string
pattern: '^[A-Z]{3}$'
category:
type: string
status:
type: string
description: Initial lifecycle status — defaults to DRAFT.
enum: [DRAFT, ACTIVE, ARCHIVED]
UpdateProductRequest:
type: object
description: Only the fields supplied are changed.
minProperties: 1
properties:
name:
type: string
minLength: 1
description:
type: string
price:
type: integer
description: Price in minor units (e.g. cents).
minimum: 0
currency:
type: string
pattern: '^[A-Z]{3}$'
category:
type: string
status:
type: string
enum: [DRAFT, ACTIVE, ARCHIVED]
Error:
type: object
required: [code, message]
properties:
code:
type: string
message:
type: string
---
id: product-search-publisher
version: 1.0.0
name: Product Search Publisher
summary: |
Reads product changes from the product database (outbox) and reliably publishes product-created, product-updated and product-deleted events for the Search System to consume.
styles:
icon: /icons/languages/go.svg
owners:
- product-platform
readsFrom:
- id: product-database
sends:
- id: product-created
version: 1.0.0
- id: product-updated
version: 1.0.0
- id: product-deleted
version: 1.0.0
repository:
language: Go
url: 'https://github.com/acme/product-search-publisher'
---
import Footer from '@catalog/components/footer.astro';
## Overview
The **Product Search Publisher** is the bridge between the Product Catalog System and the rest of the business. It uses the [transactional outbox pattern](https://microservices.io/patterns/data/transactional-outbox.html): the [[service|product-api]] records every product change in the [[container|product-database]], and this service reliably reads those changes and publishes them as [[event|product-created]], [[event|product-updated]] and [[event|product-deleted]] events.
This guarantees that product changes are never lost and are delivered to the [[system|search-system]] in order.
### Responsibilities
| Area | Description |
|------|-------------|
| Outbox polling | Reads unpublished product changes from the [[container\|product-database]]. |
| Reliable publishing | Publishes [[event\|product-created]], [[event\|product-updated]] and [[event\|product-deleted]] with at-least-once delivery. |
| Ordering | Preserves per-product ordering of change events. |
## Architecture diagram
---
id: product-worker
version: 1.0.0
name: Product Worker
summary: |
Background worker that handles long-running and asynchronous catalog work off the request path, such as enrichment, image processing and bulk imports.
styles:
icon: /icons/languages/go.svg
owners:
- product-platform
readsFrom:
- id: product-database
writesTo:
- id: product-database
repository:
language: Go
url: 'https://github.com/acme/product-worker'
---
import Footer from '@catalog/components/footer.astro';
## Overview
The **Product Worker** keeps the [[service|product-api]] fast by taking slow or asynchronous work off the request path. It reads from and writes back to the [[container|product-database]], handling jobs like data enrichment, image processing and bulk catalog imports.
### Responsibilities
| Area | Description |
|------|-------------|
| Enrichment | Augments product records with derived data after they are created or updated. |
| Media | Processes and optimises product images asynchronously. |
| Bulk imports | Ingests large product feeds without blocking the API. |
| Persistence | Reads from and writes to the [[container\|product-database]]. |
## Architecture diagram
---
id: promotion-service
version: 1.0.0
name: Promotion Service
summary: |
Evaluates promotion rules and calculates the discount that applies to a cart. Receives discount requests and publishes the calculated result.
styles:
icon: /icons/languages/go.svg
owners:
- shopping-platform
receives:
- id: calculate-discount
version: 1.0.0
sends:
- id: discount-calculated
version: 1.0.0
readsFrom:
- id: promotion-database
repository:
language: Go
url: 'https://github.com/acme/promotion-service'
---
import Footer from '@catalog/components/footer.astro';
## Overview
The **Promotion Service** is the heart of the Promotion System. It receives [[command|calculate-discount]] requests from the [[system|cart-system]], evaluates the applicable rules from the [[container|promotion-database]], and publishes a [[event|discount-calculated]] event with the result.
### Responsibilities
| Area | Description |
|------|-------------|
| Discount calculation | Handles [[command\|calculate-discount]] and evaluates promotion rules. |
| Rules | Reads promotion and discount rules from the [[container\|promotion-database]]. |
| Event publishing | Emits [[event\|discount-calculated]] with the calculated result. |
## Architecture diagram
---
id: rating-aggregator
version: 1.0.0
name: Rating Aggregator
summary: |
Keeps each product's aggregate star rating up to date as reviews are published, and serves it fast from a cache.
styles:
icon: /icons/languages/go.svg
owners:
- reviews-platform
receives:
- id: review-published
version: 1.0.0
sends:
- id: rating-updated
version: 1.0.0
writesTo:
- id: rating-cache
readsFrom:
- id: review-database
- id: rating-cache
repository:
language: Go
url: 'https://github.com/acme/rating-aggregator'
---
import Footer from '@catalog/components/footer.astro';
## Overview
The **Rating Aggregator** consumes [[event|review-published]] and recomputes the affected product's aggregate rating (average score and review count). It writes the result to the [[container|rating-cache]] for fast reads and publishes [[event|rating-updated]] so other domains can stay in sync.
### Responsibilities
| Area | Description |
|------|-------------|
| Aggregation | Recomputes average rating and review count per product. |
| Caching | Writes aggregate ratings to the [[container\|rating-cache]]. |
| Eventing | Publishes [[event\|rating-updated]] on every change. |
## Architecture diagram
---
id: review-api
version: 1.0.0
name: Review API
summary: |
The public-facing API for product reviews. Accepts review submissions, serves published reviews, and is the entry point into the Reviews & Ratings domain.
styles:
icon: /icons/languages/nodejs.svg
owners:
- reviews-platform
receives:
- id: submit-review
version: 1.0.0
- id: flag-review
version: 1.0.0
- id: vote-review-helpful
version: 1.0.0
- id: get-product-reviews
version: 1.0.0
sends:
- id: review-submitted
version: 1.0.0
- id: review-flagged
version: 1.0.0
- id: review-helpful-voted
version: 1.0.0
writesTo:
- id: review-database
readsFrom:
- id: review-database
- id: rating-cache
repository:
language: TypeScript
url: 'https://github.com/acme/review-api'
---
import Footer from '@catalog/components/footer.astro';
## Overview
The **Review API** is the front door to the Reviews & Ratings domain. It validates incoming [[command|submit-review]] commands, persists reviews to the [[container|review-database]], and publishes [[event|review-submitted]]. It also serves [[query|get-product-reviews]], reading published reviews from the [[container|review-database]] and aggregate ratings from the [[container|rating-cache]].
### Responsibilities
| Area | Description |
|------|-------------|
| Command handling | Validates and applies [[command\|submit-review]]. |
| Reads | Serves [[query\|get-product-reviews]] from the review database and rating cache. |
| Eventing | Publishes [[event\|review-submitted]] for moderation. |
| Persistence | Writes to the [[container\|review-database]]; reads from the [[container\|review-database]] and [[container\|rating-cache]]. |
## Architecture diagram
---
id: review-moderation-worker
version: 1.0.0
name: Review Moderation Worker
summary: |
Asynchronous worker that screens submitted reviews for spam, abuse and policy violations, then publishes or rejects them.
styles:
icon: /icons/languages/nodejs.svg
owners:
- reviews-platform
receives:
- id: review-submitted
version: 1.0.0
- id: review-flagged
version: 1.0.0
sends:
- id: review-published
version: 1.0.0
- id: review-rejected
version: 1.0.0
writesTo:
- id: review-database
readsFrom:
- id: review-database
repository:
language: TypeScript
url: 'https://github.com/acme/review-moderation-worker'
---
import Footer from '@catalog/components/footer.astro';
## Overview
The **Review Moderation Worker** consumes [[event|review-submitted]] (and [[event|review-flagged]] for already-published reviews), screens each review (automated checks plus thresholds for manual review), and records the outcome on the [[container|review-database]]. It then publishes either [[event|review-published]] or [[event|review-rejected]].
### Responsibilities
| Area | Description |
|------|-------------|
| Moderation | Screens reviews for spam, abuse and policy violations. |
| Outcome | Publishes [[event\|review-published]] or [[event\|review-rejected]]. |
| Persistence | Records the moderation decision on the [[container\|review-database]]. |
## Architecture diagram
---
id: search-api
version: 1.0.0
name: Search API
summary: |
Public-facing API that serves fast, relevant product search to the rest of the business, reading from the search index.
styles:
icon: /icons/languages/nodejs.svg
owners:
- search-platform
receives:
- id: search-products
version: 1.0.0
readsFrom:
- id: search-index
repository:
language: TypeScript
url: 'https://github.com/acme/search-api'
specifications:
- type: openapi
path: openapi.yml
name: Search API
---
import Footer from '@catalog/components/footer.astro';
## Overview
The **Search API** is the front door to the Search System. It answers [[query|search-products]] queries by reading from the [[container|search-index]], which is kept current by the [[service|search-indexer]]. Other teams use this API so they never have to query the catalog database directly.
### Responsibilities
| Area | Description |
|------|-------------|
| Search | Serves [[query\|search-products]] with full-text matching, filtering and pagination. |
| Reads | Queries the [[container\|search-index]] — never the catalog database. |
## Architecture diagram
## Raw Schema:openapi.yml
openapi: 3.0.3
info:
title: Search API
version: 1.0.0
description: |
Public-facing API for the Search System. Serves fast, relevant product
search by reading from the search index, which is kept in sync with the
product catalog.
contact:
name: Search Platform
email: search-platform@acme.test
servers:
- url: https://api.acme.test
description: Production
paths:
/search/products:
get:
operationId: searchProducts
summary: Search the catalog for products
description: |
Runs a full-text search over the product index and returns a paginated
list of matching products. Supports optional filters and pagination.
tags:
- Search
parameters:
- name: query
in: query
required: true
description: Free-text search term.
schema:
type: string
minLength: 1
example: wireless headphones
- name: category
in: query
required: false
description: Restrict results to a single category.
schema:
type: string
example: audio
- name: status
in: query
required: false
description: Restrict results to products with this lifecycle status.
schema:
type: string
enum: [DRAFT, ACTIVE, ARCHIVED]
- name: minPrice
in: query
required: false
description: Minimum price in minor units (e.g. cents).
schema:
type: integer
minimum: 0
- name: maxPrice
in: query
required: false
description: Maximum price in minor units (e.g. cents).
schema:
type: integer
minimum: 0
- name: page
in: query
required: false
description: 1-based page number.
schema:
type: integer
minimum: 1
default: 1
- name: pageSize
in: query
required: false
description: Number of results per page.
schema:
type: integer
minimum: 1
maximum: 100
default: 20
responses:
'200':
description: A paginated list of matching products.
content:
application/json:
schema:
$ref: '#/components/schemas/SearchResults'
'400':
description: The request was invalid (e.g. a missing or empty query).
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
components:
schemas:
SearchResults:
type: object
required: [total, page, pageSize, results]
properties:
total:
type: integer
description: Total number of products matching the query.
page:
type: integer
pageSize:
type: integer
results:
type: array
items:
$ref: '#/components/schemas/ProductSearchResult'
ProductSearchResult:
type: object
required: [productId, sku, name]
properties:
productId:
type: string
format: uuid
sku:
type: string
name:
type: string
category:
type: string
price:
type: integer
description: Price in minor units (e.g. cents).
currency:
type: string
pattern: '^[A-Z]{3}$'
score:
type: number
description: Relevance score for this result.
Error:
type: object
required: [code, message]
properties:
code:
type: string
message:
type: string
---
id: search-indexer
version: 1.0.0
name: Search Indexer
summary: |
Consumes product change events from the Product Catalog System and keeps the search index up to date so products are discoverable.
styles:
icon: /icons/languages/go.svg
owners:
- search-platform
receives:
- id: product-created
version: 1.0.0
- id: product-updated
version: 1.0.0
- id: product-deleted
version: 1.0.0
writesTo:
- id: search-index
repository:
language: Go
url: 'https://github.com/acme/search-indexer'
---
import Footer from '@catalog/components/footer.astro';
## Overview
The **Search Indexer** is how the Search System stays in sync with the catalog. It subscribes to [[event|product-created]], [[event|product-updated]] and [[event|product-deleted]] events published by the [[system|product-catalog-system]] and applies each change to the [[container|search-index]].
### Responsibilities
| Event | Action |
|-------|--------|
| [[event\|product-created]] | Add the new product to the [[container\|search-index]]. |
| [[event\|product-updated]] | Re-index the changed product. |
| [[event\|product-deleted]] | Remove the product from the index. |
## Architecture diagram
---
id: shipping-api
version: 1.0.0
name: Shipping API
summary: |
Receives ready-for-shipping orders, selects a carrier, and kicks off shipment creation.
styles:
icon: /icons/languages/nodejs.svg
owners:
- fulfilment-platform
receives:
- id: order-ready-for-shipping
version: 1.0.0
repository:
language: TypeScript
url: 'https://github.com/acme/shipping-api'
---
import Footer from '@catalog/components/footer.astro';
## Overview
The **Shipping API** is the entry point to the Shipping System. It consumes [[event|order-ready-for-shipping]] from the [[system|warehouse-system]], selects an appropriate carrier, and hands off to the [[service|carrier-adapter]] to create the shipment.
## Architecture diagram
---
id: stripe-payments-api
version: 1.0.0
name: Payments API
summary: |
Stripe's API for charging cards and issuing refunds. Acme Inc's Payment Processing System calls it to request payments and refunds.
styles:
icon: /icons/payments/stripe.svg
owners:
- payments-platform
receives:
- id: payment-requested
version: 1.0.0
- id: refund-requested
version: 1.0.0
repository:
language: External
url: 'https://github.com/stripe/stripe-node'
---
import Footer from '@catalog/components/footer.astro';
## Overview
The **Payments API** is Stripe's external interface for charging cards and issuing refunds. The [[system|payment-processing-system]] sends [[event|payment-requested]] and [[event|refund-requested]], and Stripe processes them and reports the outcome back through its [[service|stripe-webhook-endpoint]].
## Architecture diagram
---
id: stripe-webhook-endpoint
version: 1.0.0
name: Webhook Endpoint
summary: |
Stripe's webhook delivery for payment and refund outcomes. It notifies Acme Inc whether a charge succeeded or failed, and when a refund is processed.
styles:
icon: /icons/payments/stripe.svg
owners:
- payments-platform
sends:
- id: payment-succeeded
version: 1.0.0
- id: payment-failed
version: 1.0.0
- id: refund-processed
version: 1.0.0
repository:
language: External
url: 'https://github.com/stripe/stripe-node'
---
import Footer from '@catalog/components/footer.astro';
## Overview
The **Webhook Endpoint** is how Stripe reports outcomes back to Acme Inc. After processing a request from the [[service|stripe-payments-api]], it delivers [[event|payment-succeeded]], [[event|payment-failed]] or [[event|refund-processed]] to the [[system|payment-processing-system]].
## Architecture diagram
---
id: warehouse-service
version: 1.0.0
name: Warehouse Service
summary: |
Orchestrates picking and packing in the warehouse. It reacts to completed orders, creates picking jobs, and signals when an order is ready to ship.
styles:
icon: /icons/languages/java.svg
owners:
- fulfilment-platform
receives:
- id: order-completed
version: 1.0.0
sends:
- id: order-ready-for-shipping
version: 1.0.0
writesTo:
- id: warehouse-database
readsFrom:
- id: warehouse-database
repository:
language: Java
url: 'https://github.com/acme/warehouse-service'
---
import Footer from '@catalog/components/footer.astro';
## Overview
The **Warehouse Service** runs warehousing. When the Ordering domain publishes [[event|order-completed]], it creates a picking job in the [[container|warehouse-database]] for the [[service|picking-worker]] to work through. Once the order is packed it publishes [[event|order-ready-for-shipping]] for the [[system|shipping-system]].
## Architecture diagram
---
id: catalog
name: Catalog
version: 1.0.0
summary: |
The Catalog domain owns everything about products — how they are created, maintained and made discoverable across Acme Inc. It is the source of truth for product data and powers product search across the business.
owners:
- product-platform
systems:
- id: product-catalog-system
version: 1.0.0
- id: search-system
version: 1.0.0
entities:
- id: product
version: 1.0.0
- id: product-variant
version: 1.0.0
- id: category
version: 1.0.0
- id: search-document
version: 1.0.0
badges:
- content: Core domain
backgroundColor: blue
textColor: blue
icon: RectangleGroupIcon
- content: Business Critical
backgroundColor: red
textColor: red
icon: ShieldCheckIcon
---
## Overview
The **Catalog** domain is responsible for the lifecycle of every product Acme Inc sells, and for making those products discoverable. It is split into two internal systems that work together:
### How the systems work together
The **Product Catalog System** is the authoritative source of product data. Whenever a product is created, updated or deleted it publishes a domain event. The **Search System** subscribes to those events, keeps its search index in sync, and exposes a search API so other teams never have to query the catalog database directly.
The diagram below shows the domain's systems, how they relate, and the people who interact with them.
## Component map
These are the components that are part of this domain (parts of the systems in this domain)
---
id: customer
name: Customer
version: 1.0.0
summary: |
The Customer domain owns who our customers are — how they register, how their profile is maintained, and how they are authenticated across Acme Inc. It is the source of truth for customer identity and profile data.
owners:
- customer-platform
systems:
- id: customer-management-system
version: 1.0.0
- id: identity-provider
version: 1.0.0
entities:
- id: customer-profile
version: 1.0.0
- id: customer-account
version: 1.0.0
- id: authentication-session
version: 1.0.0
- id: customer-address
version: 1.0.0
badges:
- content: Core domain
backgroundColor: blue
textColor: blue
icon: RectangleGroupIcon
- content: Business Critical
backgroundColor: red
textColor: red
icon: ShieldCheckIcon
---
## Overview
The **Customer** domain is responsible for the lifecycle of every customer account at Acme Inc — registration, profile updates, and authentication. It is split into two systems:
### How the systems work together
The **Customer Management System** owns customer profile data — it accepts registration and update commands and publishes events when customers change. The **Identity Provider** handles authentication: it verifies credentials and emits an event when a customer successfully authenticates, which the rest of the business can react to.
## System Diagram
The systems in this domain, how they relate, and the people who interact with them.
## Resource Diagram
The components that make up this domain.
---
id: fulfilment
name: Fulfilment
version: 1.0.0
summary: |
The Fulfilment domain gets a confirmed order to the customer. It reserves stock, picks and packs orders in the warehouse, and hands them to carriers for delivery.
owners:
- fulfilment-platform
systems:
- id: inventory-system
version: 1.0.0
- id: warehouse-system
version: 1.0.0
- id: shipping-system
version: 1.0.0
- id: carrier
version: 1.0.0
entities:
- id: stock-item
version: 1.0.0
- id: inventory-reservation
version: 1.0.0
- id: warehouse-pick
version: 1.0.0
- id: shipment
version: 1.0.0
badges:
- content: Core domain
backgroundColor: blue
textColor: blue
icon: RectangleGroupIcon
- content: Business Critical
backgroundColor: red
textColor: red
icon: ShieldCheckIcon
---
## Overview
The **Fulfilment** domain is responsible for the physical side of an order — making sure stock is available, picking and packing it, and shipping it to the customer. It owns three internal systems and integrates with external carriers:
### How the systems work together
When an order is completed, the **Warehouse System** picks and packs it, having relied on the **Inventory System** to reserve stock earlier in checkout. Once packed, the **Shipping System** creates a shipment with an external **Carrier**, which delivers it to the customer and reports progress back.
## System Diagram
The systems in this domain, how they relate, and the people who interact with them.
## Resource Diagram
The components that make up this domain.
---
id: ordering
name: Ordering
version: 1.0.0
summary: |
The Ordering domain turns a checked-out cart into a confirmed order. It orchestrates checkout — reserving inventory, authorizing payment and creating the order — and owns the lifecycle of every order.
owners:
- ordering-platform
systems:
- id: checkout-system
version: 1.0.0
- id: order-management-system
version: 1.0.0
flows:
- id: place-an-order
version: 1.0.0
entities:
- id: checkout-session
version: 1.0.0
- id: order
version: 1.0.0
- id: order-line
version: 1.0.0
- id: order-status-history
version: 1.0.0
badges:
- content: Core domain
backgroundColor: blue
textColor: blue
icon: RectangleGroupIcon
- content: Business Critical
backgroundColor: red
textColor: red
icon: ShieldCheckIcon
---
## Overview
The **Ordering** domain is responsible for everything that happens once a customer commits to buy — from the moment their cart is checked out to a confirmed, fulfilled order. It is split into two systems:
### How the systems work together
When the [[domain|shopping]] domain checks out a cart, the **Checkout System** takes over. It orchestrates the steps needed to place an order — reserving inventory, authorizing payment, and finally asking the **Order Management System** to create the order. The Order Management System then owns that order for the rest of its life, publishing events as it is created, completed or cancelled.
## System Diagram
The systems in this domain, how they relate, and the people who interact with them.
## Resource Diagram
The components that make up this domain.
---
id: payments
name: Payments
version: 1.0.0
summary: |
The Payments domain takes payment for orders and processes refunds. It orchestrates authorization and capture through an external payment processor, and screens payments for fraud.
owners:
- payments-platform
systems:
- id: payment-processing-system
version: 1.0.0
- id: stripe
version: 1.0.0
- id: fraud-detection
version: 1.0.0
entities:
- id: payment
version: 1.0.0
- id: payment-authorization
version: 1.0.0
- id: refund
version: 1.0.0
- id: fraud-check
version: 1.0.0
badges:
- content: Core domain
backgroundColor: blue
textColor: blue
icon: RectangleGroupIcon
- content: Business Critical
backgroundColor: red
textColor: red
icon: ShieldCheckIcon
---
## Overview
The **Payments** domain is responsible for moving money. It authorizes and captures payment for orders, issues refunds, and screens payments for fraud. It owns one internal system and integrates with two external providers:
### How the systems work together
The **Payment Processing System** is the internal orchestrator. When the Ordering domain authorizes a payment, it requests payment via the external **Stripe** system and, in parallel, asks **Fraud Detection** to screen the payment. Stripe reports back whether the payment succeeded or failed, and the Payment Processing System records the outcome.
## System Diagram
The systems in this domain, how they relate, and the people who interact with them.
---
id: reviews
name: Reviews & Ratings
version: 1.0.0
summary: |
The Reviews & Ratings domain owns customer feedback on products — how reviews are submitted, moderated, published and aggregated into the star ratings shown across the storefront.
owners:
- reviews-platform
services:
- id: review-api
version: 1.0.0
- id: review-moderation-worker
version: 1.0.0
- id: rating-aggregator
version: 1.0.0
entities:
- id: review
version: 1.0.0
- id: moderation-decision
version: 1.0.0
- id: rating-summary
version: 1.0.0
- id: review-vote
version: 1.0.0
- id: review-flag
version: 1.0.0
flows:
- id: review-submission
version: 1.0.0
receives:
- id: submit-review
version: 1.0.0
- id: flag-review
version: 1.0.0
- id: vote-review-helpful
version: 1.0.0
- id: get-product-reviews
version: 1.0.0
sends:
- id: review-submitted
version: 1.0.0
- id: review-published
version: 1.0.0
- id: review-rejected
version: 1.0.0
- id: review-flagged
version: 1.0.0
- id: review-helpful-voted
version: 1.0.0
- id: rating-updated
version: 1.0.0
specifications:
- type: openapi
path: openapi.yml
name: Review API
- type: asyncapi
path: asyncapi.yml
name: Reviews Eventing
badges:
- content: Supporting domain
backgroundColor: blue
textColor: blue
icon: RectangleGroupIcon
---
## Overview
The **Reviews & Ratings** domain is responsible for everything to do with customer feedback on products: accepting reviews, moderating them for quality and abuse, publishing the approved ones, and aggregating them into the star ratings shown across the storefront.
Unlike most other domains in the catalog, Reviews & Ratings is modelled **without systems** — its services, data stores and flows hang directly off the domain.
### What's inside
| Component | Type | Responsibility |
|-----------|------|----------------|
| [[service\|review-api]] | Service | Accepts review submissions and serves product reviews. |
| [[service\|review-moderation-worker]] | Service | Screens submitted reviews and publishes or rejects them. |
| [[service\|rating-aggregator]] | Service | Keeps each product's aggregate rating in sync as reviews are published. |
| [[container\|review-database]] | Data Store | System of record for reviews and their moderation state. |
| [[container\|rating-cache]] | Data Store | Fast read store for aggregate product ratings. |
| [[entity\|review]] | Entity | The core review aggregate. |
The diagram below shows the services, data stores and messages that make up this domain.
## How it works
1. A customer submits a review via the [[service\|review-api]], which stores it and publishes [[event\|review-submitted]].
2. The [[service\|review-moderation-worker]] screens the review and publishes either [[event\|review-published]] or [[event\|review-rejected]].
3. The [[service\|rating-aggregator]] consumes [[event\|review-published]] and updates the product's aggregate rating, publishing [[event\|rating-updated]].
Once a review is live, customers can interact with it: [[command\|vote-review-helpful]] updates its helpful count (publishing [[event\|review-helpful-voted]]), and [[command\|flag-review]] reports it for re-moderation (publishing [[event\|review-flagged]], which the [[service\|review-moderation-worker]] re-screens).
## Raw Schema:openapi.yml
openapi: 3.0.3
info:
title: Review API
version: 1.0.0
description: |
Public-facing API for the Reviews & Ratings domain. It is the entry point for
submitting reviews, flagging reviews, voting reviews helpful, and reading the
published reviews and aggregate rating for a product.
contact:
name: Reviews Platform
email: reviews-platform@acme.test
servers:
- url: https://api.acme.test
description: Production
tags:
- name: Reviews
description: Submit, read and interact with product reviews.
paths:
/products/{productId}/reviews:
get:
operationId: getProductReviews
summary: Get product reviews
description: Returns the published reviews and aggregate rating for a product.
tags:
- Reviews
parameters:
- name: productId
in: path
required: true
schema:
type: string
- name: page
in: query
schema:
type: integer
minimum: 1
default: 1
- name: pageSize
in: query
schema:
type: integer
minimum: 1
maximum: 100
default: 20
- name: sort
in: query
schema:
type: string
enum: [newest, highest, lowest, most_helpful]
default: newest
responses:
'200':
description: The published reviews and aggregate rating for the product.
content:
application/json:
schema:
$ref: '#/components/schemas/ProductReviews'
post:
operationId: submitReview
summary: Submit a review
description: Submits a review for a product. On success a `ReviewSubmitted` event is published and the review awaits moderation.
tags:
- Reviews
parameters:
- name: productId
in: path
required: true
schema:
type: string
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/SubmitReviewRequest'
responses:
'202':
description: The review was accepted and is awaiting moderation.
content:
application/json:
schema:
$ref: '#/components/schemas/Review'
'400':
description: The request was invalid.
/reviews/{reviewId}/flags:
post:
operationId: flagReview
summary: Flag a review
description: Flags a published review for re-moderation. On success a `ReviewFlagged` event is published.
tags:
- Reviews
parameters:
- name: reviewId
in: path
required: true
schema:
type: string
format: uuid
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/FlagReviewRequest'
responses:
'202':
description: The flag was recorded.
/reviews/{reviewId}/helpful:
post:
operationId: voteReviewHelpful
summary: Vote a review helpful
description: Marks a review as helpful (or removes the vote). On success a `ReviewHelpfulVoted` event is published.
tags:
- Reviews
parameters:
- name: reviewId
in: path
required: true
schema:
type: string
format: uuid
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/VoteReviewHelpfulRequest'
responses:
'200':
description: The helpful count was updated.
components:
schemas:
Review:
type: object
properties:
reviewId:
type: string
format: uuid
productId:
type: string
customerId:
type: string
rating:
type: integer
minimum: 1
maximum: 5
title:
type: string
body:
type: string
status:
type: string
enum: [submitted, published, rejected]
helpfulCount:
type: integer
minimum: 0
submittedAt:
type: string
format: date-time
ProductReviews:
type: object
properties:
productId:
type: string
averageRating:
type: number
minimum: 0
maximum: 5
reviewCount:
type: integer
minimum: 0
reviews:
type: array
items:
$ref: '#/components/schemas/Review'
SubmitReviewRequest:
type: object
required: [customerId, rating, body]
properties:
customerId:
type: string
rating:
type: integer
minimum: 1
maximum: 5
title:
type: string
body:
type: string
FlagReviewRequest:
type: object
required: [flaggedBy, reason]
properties:
flaggedBy:
type: string
reason:
type: string
enum: [spam, abuse, off_topic, inappropriate, other]
notes:
type: string
VoteReviewHelpfulRequest:
type: object
required: [customerId, vote]
properties:
customerId:
type: string
vote:
type: string
enum: [helpful, remove]
## Raw Schema:asyncapi.yml
asyncapi: 3.0.0
info:
title: Review Moderation Worker
version: 1.0.0
description: |
The event-driven interface of the Review Moderation Worker.
The worker consumes submitted and flagged reviews, screens them for spam, abuse
and policy violations, and publishes the outcome (published or rejected).
contact:
name: Reviews Platform
email: reviews-platform@acme.test
defaultContentType: application/json
servers:
production:
host: broker.acme.test:9092
protocol: kafka
description: Production Kafka cluster.
channels:
reviewIntake:
address: reviews.intake
title: Reviews to moderate
description: Reviews that need screening — newly submitted or flagged for re-moderation.
messages:
ReviewSubmitted:
$ref: '#/components/messages/ReviewSubmitted'
ReviewFlagged:
$ref: '#/components/messages/ReviewFlagged'
reviewOutcomes:
address: reviews.outcomes
title: Moderation outcomes
description: The decisions the worker publishes after screening a review.
messages:
ReviewPublished:
$ref: '#/components/messages/ReviewPublished'
ReviewRejected:
$ref: '#/components/messages/ReviewRejected'
operations:
receiveReviewSubmitted:
action: receive
title: Review Submitted
summary: Screen a newly submitted review.
channel:
$ref: '#/channels/reviewIntake'
messages:
- $ref: '#/channels/reviewIntake/messages/ReviewSubmitted'
receiveReviewFlagged:
action: receive
title: Review Flagged
summary: Re-screen a previously published review that has been flagged.
channel:
$ref: '#/channels/reviewIntake'
messages:
- $ref: '#/channels/reviewIntake/messages/ReviewFlagged'
publishReviewPublished:
action: send
title: Review Published
summary: Published when a review passes moderation.
channel:
$ref: '#/channels/reviewOutcomes'
messages:
- $ref: '#/channels/reviewOutcomes/messages/ReviewPublished'
publishReviewRejected:
action: send
title: Review Rejected
summary: Published when a review fails moderation.
channel:
$ref: '#/channels/reviewOutcomes'
messages:
- $ref: '#/channels/reviewOutcomes/messages/ReviewRejected'
components:
messages:
ReviewSubmitted:
name: ReviewSubmitted
title: Review Submitted
summary: A customer submitted a review; it awaits moderation.
payload:
$ref: '#/components/schemas/ReviewSubmitted'
ReviewFlagged:
name: ReviewFlagged
title: Review Flagged
summary: A published review was flagged and needs re-screening.
payload:
$ref: '#/components/schemas/ReviewFlagged'
ReviewPublished:
name: ReviewPublished
title: Review Published
summary: A review passed moderation and is visible on the storefront.
payload:
$ref: '#/components/schemas/ReviewPublished'
ReviewRejected:
name: ReviewRejected
title: Review Rejected
summary: A review failed moderation and will not be shown.
payload:
$ref: '#/components/schemas/ReviewRejected'
schemas:
ReviewSubmitted:
type: object
properties:
reviewId:
type: string
format: uuid
productId:
type: string
customerId:
type: string
rating:
type: integer
minimum: 1
maximum: 5
title:
type: string
body:
type: string
submittedAt:
type: string
format: date-time
required: [reviewId, productId, customerId, rating, submittedAt]
ReviewFlagged:
type: object
properties:
reviewId:
type: string
format: uuid
productId:
type: string
reason:
type: string
enum: [spam, abuse, off_topic, inappropriate, other]
flagCount:
type: integer
minimum: 1
flaggedAt:
type: string
format: date-time
required: [reviewId, productId, reason, flaggedAt]
ReviewPublished:
type: object
properties:
reviewId:
type: string
format: uuid
productId:
type: string
customerId:
type: string
rating:
type: integer
minimum: 1
maximum: 5
publishedAt:
type: string
format: date-time
required: [reviewId, productId, rating, publishedAt]
ReviewRejected:
type: object
properties:
reviewId:
type: string
format: uuid
productId:
type: string
reason:
type: string
enum: [spam, abuse, off_topic, policy_violation]
rejectedAt:
type: string
format: date-time
required: [reviewId, productId, reason, rejectedAt]
---
id: shopping
name: Shopping
version: 1.0.0
summary: |
The Shopping domain owns the customer's path to purchase — building a cart, applying promotions, and checking out. It coordinates the cart and the discounts that apply to it.
owners:
- shopping-platform
systems:
- id: cart-system
version: 1.0.0
- id: promotion-system
version: 1.0.0
entities:
- id: cart
version: 1.0.0
- id: cart-item
version: 1.0.0
- id: promotion
version: 1.0.0
- id: discount
version: 1.0.0
badges:
- content: Core domain
backgroundColor: blue
textColor: blue
icon: RectangleGroupIcon
- content: Business Critical
backgroundColor: red
textColor: red
icon: ShieldCheckIcon
---
## Overview
The **Shopping** domain is responsible for everything between browsing and buying — the shopping cart and the promotions applied to it. It is split into two systems:
### How the systems work together
The **Cart System** owns the customer's cart and the checkout flow. When pricing a cart, it asks the **Promotion System** to calculate the discounts that apply. When the customer checks out, the Cart System publishes an event the rest of the business reacts to.
## System Diagram
The systems in this domain, how they relate, and the people who interact with them.
## Resource Diagram
The components that make up this domain.
---
id: customer-platform
name: Customer Platform
summary: Owns the Customer domain — customer profiles and authentication across Acme Inc.
members:
- dboyne
email: customer-platform@acme.test
slackDirectMessageUrl: https://acme.slack.com/channels/customer-platform
---
## Overview
The **Customer Platform** team owns the [[domain|customer]] domain. They are responsible for how customers register, how their profiles are maintained, and how they authenticate.
## Responsibilities
- **Customer Management System** — registering, updating and reading customer profiles, and publishing customer change events.
- **Identity Provider** — authenticating customers and owning credentials in the user directory.
---
id: fulfilment-platform
name: Fulfilment Platform
summary: Owns the Fulfilment domain — reserving stock, picking and packing orders, and shipping them to customers.
members:
- dboyne
email: fulfilment-platform@acme.test
slackDirectMessageUrl: https://acme.slack.com/channels/fulfilment-platform
---
## Overview
The **Fulfilment Platform** team owns the [[domain|fulfilment]] domain. They are responsible for inventory, warehousing and shipping — everything that gets a confirmed order physically to the customer.
## Responsibilities
- **Inventory System** — tracking and reserving stock.
- **Warehouse System** — picking and packing orders.
- **Shipping System** — handing packed orders to carriers.
- Integration with external **Carriers** for delivery.
---
id: ordering-platform
name: Ordering Platform
summary: Owns the Ordering domain — turning a checked-out cart into a confirmed order.
members:
- dboyne
email: ordering-platform@acme.test
slackDirectMessageUrl: https://acme.slack.com/channels/ordering-platform
---
## Overview
The **Ordering Platform** team owns the [[domain|ordering]] domain. They are responsible for the checkout flow that turns a checked-out cart into a confirmed order, and for the lifecycle of orders once they exist.
## Responsibilities
- **Checkout System** — orchestrating checkout: reserving inventory, authorizing payment and creating the order.
- **Order Management System** — the system of record for orders and their lifecycle.
---
id: payments-platform
name: Payments Platform
summary: Owns the Payments domain — authorizing payments, processing refunds, and integrating with external payment and fraud providers.
members:
- dboyne
email: payments-platform@acme.test
slackDirectMessageUrl: https://acme.slack.com/channels/payments-platform
---
## Overview
The **Payments Platform** team owns the [[domain|payments]] domain. They are responsible for taking payment for orders, processing refunds, and integrating with the external payment processor and fraud provider.
## Responsibilities
- **Payment Processing System** — orchestrating authorization, capture and refunds.
- Integrations with **Stripe** (payment processing) and **Fraud Detection** (fraud screening).
---
id: product-platform
name: Product Platform
summary: Owns the Product Catalog System — the source of truth for product data at Acme Inc.
members:
- dboyne
email: product-platform@acme.test
slackDirectMessageUrl: https://acme.slack.com/channels/product-platform
---
## Overview
The **Product Platform** team owns the [[system|product-catalog-system]]. They are responsible for how products are created, maintained and stored, and for reliably publishing product change events to the rest of the business.
## Responsibilities
- **Product API** — the public-facing API for creating, updating, deleting and reading products.
- **Product Worker** — asynchronous catalog processing (enrichment, media, bulk imports).
- **Product Search Publisher** — reliable, ordered delivery of product change events.
- **Product Database** — the PostgreSQL system of record for all product data.
---
id: reviews-platform
name: Reviews Platform
summary: Owns the Reviews & Ratings domain — how customers review products and how those reviews are moderated, published and aggregated into ratings.
members:
- dboyne
email: reviews-platform@acme.test
slackDirectMessageUrl: https://acme.slack.com/channels/reviews-platform
---
## Overview
The **Reviews Platform** team owns the [[domain|reviews]] domain. They are responsible for collecting customer reviews, moderating them, publishing the approved ones, and turning ratings into the aggregate scores shown across the storefront.
## Responsibilities
- **Review API** — accepts review submissions and serves product reviews.
- **Review Moderation Worker** — screens submitted reviews and decides whether to publish or reject them.
- **Rating Aggregator** — keeps each product's aggregate rating up to date as reviews are published.
- **Review Database** — the system of record for reviews and their moderation state.
---
id: search-platform
name: Search Platform
summary: Owns the Search System — keeps the catalog discoverable through fast, relevant product search.
members:
- dboyne
email: search-platform@acme.test
slackDirectMessageUrl: https://acme.slack.com/channels/search-platform
---
## Overview
The **Search Platform** team owns the [[system|search-system]]. They consume product change events, keep the search index in sync, and serve product search to the rest of Acme Inc.
## Responsibilities
- **Search API** — the public-facing API that serves product search queries.
- **Search Indexer** — consumes product change events and keeps the index current.
- **Search Index** — the search-optimised, rebuildable read model of the catalog.
---
id: shopping-platform
name: Shopping Platform
summary: Owns the Shopping domain — the cart and the promotions applied to it.
members:
- dboyne
email: shopping-platform@acme.test
slackDirectMessageUrl: https://acme.slack.com/channels/shopping-platform
---
## Overview
The **Shopping Platform** team owns the [[domain|shopping]] domain. They are responsible for the shopping cart, the checkout flow, and the promotions and discounts applied to a cart.
## Responsibilities
- **Cart System** — building, pricing and checking out shopping carts.
- **Promotion System** — evaluating promotion rules and calculating discounts.
---
id: dboyne
name: David Boyne
avatarUrl: "https://pbs.twimg.com/profile_images/1262283153563140096/DYRDqKg6_400x400.png"
role: Lead developer
email: test@test.com
slackDirectMessageUrl: https://yourteam.slack.com/channels/boyney123
msTeamsDirectMessageUrl: https://teams.microsoft.com/l/chat/0/0?users=test@test.com
---
Hello! I'm David Boyne, the Tech Lead of an amazing team called Full Stackers. With a passion for building robust and scalable systems, I specialize in designing and implementing event-driven architectures that power modern, responsive applications.
### About Me
With over a decade of experience in the tech industry, I have honed my skills in full-stack development, cloud computing, and distributed systems. My journey has taken me through various roles, from software engineer to architect, and now as a tech lead, I am committed to driving innovation and excellence within my team.
### What I Do
At Full Stackers, we focus on creating seamless and efficient event-driven architectures that enhance the performance and scalability of our applications. My role involves:
- **Architecture Design**: Crafting scalable and resilient system architectures using event-driven paradigms.
- **Team Leadership**: Guiding a talented team of developers, fostering a collaborative and innovative environment.
- **Code Reviews & Mentorship**: Ensuring code quality and sharing knowledge to help the team grow.
- **Stakeholder Collaboration**: Working closely with other teams and stakeholders to align our technical solutions with business goals.
- **Continuous Improvement**: Advocating for best practices in software development, deployment, and monitoring.
I am passionate about leveraging the power of events to build systems that are not only highly responsive but also easier to maintain and extend. In an ever-evolving tech landscape, I strive to stay ahead of the curve, continuously learning and adapting to new technologies and methodologies.
Feel free to connect with me to discuss all things tech, event-driven architectures, or to exchange ideas on building better software systems!
---
*David Boyne*
*Tech Lead, Full Stackers*
---
id: authentication-session
name: Authentication Session
version: 1.0.0
identifier: sessionId
summary: A successful customer authentication session.
owners:
- customer-platform
properties:
- name: sessionId
type: UUID
required: true
description: Unique authentication session identifier.
- name: accountId
type: UUID
required: true
description: Account authenticated in the session.
references: customer-account
relationType: belongsTo
referencesIdentifier: accountId
- name: authenticatedAt
type: datetime
required: true
description: Time authentication succeeded.
- name: expiresAt
type: datetime
required: true
description: Time the session expires.
---
## Overview
Authentication Session represents successful login behavior emitted by [[event|customer-authenticated]].
---
id: cart
name: Cart
version: 1.0.0
identifier: cartId
aggregateRoot: true
summary: The customer's active collection of items before an order exists.
owners:
- shopping-platform
properties:
- name: cartId
type: UUID
required: true
description: Unique cart identifier.
- name: customerId
type: UUID
required: false
description: Customer that owns the cart, if authenticated.
references: customer-profile
relationType: belongsTo
referencesIdentifier: customerId
- name: status
type: string
required: true
description: Current cart state.
enum:
- active
- checked-out
- abandoned
- name: updatedAt
type: datetime
required: true
description: Time the cart last changed.
---
## Overview
Cart is the Shopping domain aggregate. It accepts item changes and emits [[event|cart-checked-out]] when the customer commits to buy.
---
id: cart-item
name: Cart Item
version: 1.0.0
identifier: cartItemId
summary: A product variant and quantity inside a cart.
owners:
- shopping-platform
properties:
- name: cartItemId
type: UUID
required: true
description: Unique cart item identifier.
- name: cartId
type: UUID
required: true
description: Cart this item belongs to.
references: cart
relationType: belongsTo
referencesIdentifier: cartId
- name: productId
type: UUID
required: true
description: Product selected by the customer.
references: product
relationType: references
referencesIdentifier: productId
- name: quantity
type: integer
required: true
description: Quantity requested.
---
## Overview
Cart Item records the customer's intent to buy a product variant before checkout. It is owned by [[entity|cart]].
---
id: category
name: Category
version: 1.0.0
identifier: categoryId
aggregateRoot: true
summary: A merchandising grouping used to organize products for discovery.
owners:
- product-platform
properties:
- name: categoryId
type: UUID
required: true
description: Unique category identifier.
- name: slug
type: string
required: true
description: Stable URL-safe category key.
- name: displayName
type: string
required: true
description: Customer-facing category name.
- name: parentCategoryId
type: UUID
required: false
description: Parent category for hierarchy navigation.
references: category
relationType: belongsTo
referencesIdentifier: categoryId
---
## Overview
Category defines how products are grouped for browsing. It is owned by the Catalog domain and projected into the Search System for discovery.
---
id: checkout-session
name: Checkout Session
version: 1.0.0
identifier: checkoutSessionId
aggregateRoot: true
summary: The orchestration state for turning a checked-out cart into an order.
owners:
- ordering-platform
properties:
- name: checkoutSessionId
type: UUID
required: true
description: Unique checkout session identifier.
- name: cartId
type: UUID
required: true
description: Cart being checked out.
references: cart
relationType: startsFrom
referencesIdentifier: cartId
- name: status
type: string
required: true
description: Current checkout state.
- name: startedAt
type: datetime
required: true
description: Time checkout orchestration started.
---
## Overview
Checkout Session tracks the saga managed by [[service|checkout-orchestrator]] across inventory reservation, payment authorization and order creation.
---
id: customer-account
name: Customer Account
version: 1.0.0
identifier: accountId
aggregateRoot: true
summary: The identity account used to authenticate a customer.
owners:
- customer-platform
properties:
- name: accountId
type: UUID
required: true
description: Unique account identifier.
- name: customerId
type: UUID
required: true
description: Customer profile linked to this account.
references: customer-profile
relationType: belongsTo
referencesIdentifier: customerId
- name: provider
type: string
required: true
description: Identity provider name.
- name: status
type: string
required: true
description: Account lifecycle state.
---
## Overview
Customer Account belongs to the Identity Provider boundary and should not be queried directly by order, payment or review services.
---
id: customer-address
name: Customer Address
version: 1.0.0
identifier: addressId
summary: A saved address attached to a customer profile.
owners:
- customer-platform
properties:
- name: addressId
type: UUID
required: true
description: Unique address identifier.
- name: customerId
type: UUID
required: true
description: Customer who owns the address.
references: customer-profile
relationType: belongsTo
referencesIdentifier: customerId
- name: countryCode
type: string
required: true
description: ISO country code.
- name: postalCode
type: string
required: true
description: Postal or ZIP code.
---
## Overview
Customer Address supports checkout and fulfilment while remaining owned by the Customer domain.
---
id: customer-profile
name: Customer Profile
version: 1.0.0
identifier: customerId
aggregateRoot: true
summary: The customer details Acme uses for commerce interactions.
owners:
- customer-platform
properties:
- name: customerId
type: UUID
required: true
description: Unique customer identifier.
- name: email
type: string
required: true
description: Customer email address.
- name: displayName
type: string
required: false
description: Preferred customer display name.
- name: status
type: string
required: true
description: Customer profile state.
---
## Overview
Customer Profile is owned by [[system|customer-management-system]] and is separate from authentication credentials.
---
id: discount
name: Discount
version: 1.0.0
identifier: discountId
summary: The calculated benefit applied to a cart or cart item.
owners:
- shopping-platform
properties:
- name: discountId
type: UUID
required: true
description: Unique discount identifier.
- name: promotionId
type: UUID
required: false
description: Promotion that produced the discount.
references: promotion
relationType: derivedFrom
referencesIdentifier: promotionId
- name: amount
type: decimal
required: true
description: Monetary value of the discount.
- name: reason
type: string
required: true
description: Human-readable explanation for the discount.
---
## Overview
Discount is a calculated result from [[command|calculate-discount]]. It is separate from cart persistence so promotion logic can evolve independently.
---
id: fraud-check
name: Fraud Check
version: 1.0.0
identifier: fraudCheckId
summary: Fraud screening result associated with a payment attempt.
owners:
- payments-platform
properties:
- name: fraudCheckId
type: UUID
required: true
description: Unique fraud check identifier.
- name: paymentId
type: UUID
required: true
description: Payment attempt being screened.
references: payment
relationType: screens
referencesIdentifier: paymentId
- name: result
type: string
required: true
description: Screening result.
enum:
- passed
- failed
- review
- name: checkedAt
type: datetime
required: true
description: Time screening completed.
---
## Overview
Fraud Check documents the screening outcome from [[system|fraud-detection]] so payment decisions are auditable.
---
id: inventory-reservation
name: Inventory Reservation
version: 1.0.0
identifier: reservationId
aggregateRoot: true
summary: Stock held for a checkout or order before fulfilment.
owners:
- fulfilment-platform
properties:
- name: reservationId
type: UUID
required: true
description: Unique reservation identifier.
- name: orderId
type: UUID
required: false
description: Order associated with the reservation once created.
references: order
relationType: reservedFor
referencesIdentifier: orderId
- name: productId
type: UUID
required: true
description: Product being reserved.
references: product
relationType: reserves
referencesIdentifier: productId
- name: expiresAt
type: datetime
required: true
description: Time the reservation expires if not committed.
---
## Overview
Inventory Reservation is created during checkout by [[command|reserve-inventory]] and released if the saga fails.
---
id: moderation-decision
name: Moderation Decision
version: 1.0.0
identifier: moderationDecisionId
summary: The outcome of reviewing submitted customer feedback.
owners:
- reviews-platform
properties:
- name: moderationDecisionId
type: UUID
required: true
description: Unique moderation decision identifier.
- name: reviewId
type: UUID
required: true
description: Review being moderated.
references: review
relationType: decides
referencesIdentifier: reviewId
- name: outcome
type: string
required: true
description: Moderation result.
enum:
- published
- rejected
- name: decidedAt
type: datetime
required: true
description: Time the decision was made.
---
## Overview
Moderation Decision records why a review became published or rejected and supports audit of [[service|review-moderation-worker]] behavior.
---
id: order
name: Order
version: 1.0.0
identifier: orderId
aggregateRoot: true
summary: The durable customer order created after successful checkout.
owners:
- ordering-platform
properties:
- name: orderId
type: UUID
required: true
description: Unique order identifier.
- name: customerId
type: UUID
required: true
description: Customer who placed the order.
references: customer-profile
relationType: belongsTo
referencesIdentifier: customerId
- name: status
type: string
required: true
description: Current order lifecycle state.
- name: totalAmount
type: decimal
required: true
description: Total order value at creation.
---
## Overview
Order is the main aggregate in [[system|order-management-system]]. It emits order lifecycle events used by Fulfilment and support workflows.
---
id: order-line
name: Order Line
version: 1.0.0
identifier: orderLineId
summary: A purchased product and quantity within an order.
owners:
- ordering-platform
properties:
- name: orderLineId
type: UUID
required: true
description: Unique order line identifier.
- name: orderId
type: UUID
required: true
description: Order this line belongs to.
references: order
relationType: belongsTo
referencesIdentifier: orderId
- name: productId
type: UUID
required: true
description: Product purchased.
references: product
relationType: references
referencesIdentifier: productId
- name: quantity
type: integer
required: true
description: Quantity purchased.
---
## Overview
Order Line snapshots the products bought at checkout. It should not replace the Catalog domain's authoritative product data.
---
id: order-status-history
name: Order Status History
version: 1.0.0
identifier: orderStatusHistoryId
summary: Audit history of order lifecycle state changes.
owners:
- ordering-platform
properties:
- name: orderStatusHistoryId
type: UUID
required: true
description: Unique status history record.
- name: orderId
type: UUID
required: true
description: Order whose status changed.
references: order
relationType: belongsTo
referencesIdentifier: orderId
- name: status
type: string
required: true
description: New order status.
- name: changedAt
type: datetime
required: true
description: Time the status changed.
---
## Overview
Order Status History provides an audit trail for customer support, fulfilment exceptions and order lifecycle debugging.
---
id: payment
name: Payment
version: 1.0.0
identifier: paymentId
aggregateRoot: true
summary: Acme's internal record of payment intent and outcome for an order.
owners:
- payments-platform
properties:
- name: paymentId
type: UUID
required: true
description: Unique payment identifier.
- name: orderId
type: UUID
required: true
description: Order being paid for.
references: order
relationType: paysFor
referencesIdentifier: orderId
- name: amount
type: decimal
required: true
description: Amount requested.
- name: status
type: string
required: true
description: Payment lifecycle status.
---
## Overview
Payment is the Payments domain aggregate. It records Acme's view of payment state regardless of external provider retries or webhook order.
---
id: payment-authorization
name: Payment Authorization
version: 1.0.0
identifier: authorizationId
summary: Approval from a payment provider to reserve funds for an order.
owners:
- payments-platform
properties:
- name: authorizationId
type: UUID
required: true
description: Unique authorization identifier.
- name: paymentId
type: UUID
required: true
description: Payment this authorization belongs to.
references: payment
relationType: belongsTo
referencesIdentifier: paymentId
- name: providerReference
type: string
required: true
description: External payment provider reference.
- name: authorizedAt
type: datetime
required: true
description: Time authorization was granted.
---
## Overview
Payment Authorization captures the result of [[command|authorize-payment]] and links Acme payment state to provider state.
---
id: product
name: Product
version: 1.0.0
identifier: productId
aggregateRoot: true
summary: The sellable item Acme manages in the product catalog.
owners:
- product-platform
properties:
- name: productId
type: UUID
required: true
description: Unique product identifier.
- name: sku
type: string
required: true
description: Primary merchandising SKU.
- name: name
type: string
required: true
description: Customer-facing product name.
- name: status
type: string
required: true
description: Product publication state.
enum:
- draft
- active
- archived
---
## Overview
The Product is the Catalog domain's core aggregate. It is created and maintained by [[service|product-api]] and published to downstream consumers through product events.
---
id: product-variant
name: Product Variant
version: 1.0.0
identifier: variantId
summary: A purchasable variation of a product, such as size or color.
owners:
- product-platform
properties:
- name: variantId
type: UUID
required: true
description: Unique variant identifier.
- name: productId
type: UUID
required: true
description: Product this variant belongs to.
references: product
relationType: belongsTo
referencesIdentifier: productId
- name: sku
type: string
required: true
description: Variant-level SKU.
- name: attributes
type: object
required: true
description: Variant dimensions such as size, color or material.
---
## Overview
Product Variant captures the concrete option a customer can buy. It belongs to a [[entity|product]] and is indexed into search when product data changes.
---
id: promotion
name: Promotion
version: 1.0.0
identifier: promotionId
aggregateRoot: true
summary: A commercial offer evaluated against a cart.
owners:
- shopping-platform
properties:
- name: promotionId
type: UUID
required: true
description: Unique promotion identifier.
- name: code
type: string
required: false
description: Optional customer-entered promotion code.
- name: categoryId
type: UUID
required: false
description: Category the promotion applies to when scoped.
references: category
relationType: appliesTo
referencesIdentifier: categoryId
- name: status
type: string
required: true
description: Promotion lifecycle state.
- name: startsAt
type: datetime
required: true
description: When the promotion becomes active.
---
## Overview
Promotion is owned by the Promotion System and is evaluated when Shopping calculates discounts for a cart.
---
id: rating-summary
name: Rating Summary
version: 1.0.0
identifier: productId
summary: Aggregated review statistics for a product.
owners:
- reviews-platform
properties:
- name: productId
type: UUID
required: true
description: Product being summarized.
references: product
relationType: summarizes
referencesIdentifier: productId
- name: averageRating
type: decimal
required: true
description: Average published rating.
- name: reviewCount
type: integer
required: true
description: Number of published reviews.
- name: updatedAt
type: datetime
required: true
description: Time the summary was recalculated.
---
## Overview
Rating Summary is the read model maintained by [[service|rating-aggregator]] and stored in [[container|rating-cache]].
---
id: refund
name: Refund
version: 1.0.0
identifier: refundId
aggregateRoot: true
summary: A request to return money to a customer after payment.
owners:
- payments-platform
properties:
- name: refundId
type: UUID
required: true
description: Unique refund identifier.
- name: paymentId
type: UUID
required: true
description: Payment being refunded.
references: payment
relationType: refunds
referencesIdentifier: paymentId
- name: amount
type: decimal
required: true
description: Refund amount.
- name: status
type: string
required: true
description: Refund lifecycle state.
---
## Overview
Refund is owned by Payments and records refund requests and provider outcomes such as [[event|refund-processed]].
---
id: review
name: Review
version: 1.0.0
identifier: reviewId
aggregateRoot: true
summary: A customer's review and rating of a product, including its moderation lifecycle.
owners:
- reviews-platform
properties:
- name: reviewId
type: UUID
required: true
description: Unique identifier for the review.
- name: productId
type: string
required: true
description: The product being reviewed.
references: product
relationType: reviews
referencesIdentifier: productId
- name: customerId
type: string
required: true
description: The customer who wrote the review.
references: customer-profile
relationType: writtenBy
referencesIdentifier: customerId
- name: rating
type: integer
required: true
description: Star rating from 1 to 5.
- name: title
type: string
required: false
description: Short headline for the review.
- name: body
type: string
required: true
description: The review text.
- name: status
type: string
required: true
description: Lifecycle status of the review.
enum:
- submitted
- published
- rejected
- name: submittedAt
type: datetime
required: true
description: When the review was submitted.
---
## Overview
The **Review** is the core aggregate of the Reviews & Ratings domain. It captures a customer's rating and written feedback for a product, along with the moderation `status` that controls whether it is visible on the storefront.
A review moves through three states:
1. **submitted** — stored by the [[service|review-api]], awaiting moderation.
2. **published** — passed moderation and visible (the [[service|rating-aggregator]] folds it into the product's rating).
3. **rejected** — failed moderation and never shown, but kept for audit.
---
id: review-flag
name: Review Flag
version: 1.0.0
identifier: flagId
summary: A customer report that a review may violate policy.
owners:
- reviews-platform
properties:
- name: flagId
type: UUID
required: true
description: Unique review flag identifier.
- name: reviewId
type: UUID
required: true
description: Review being reported.
references: review
relationType: flags
referencesIdentifier: reviewId
- name: reason
type: string
required: true
description: Reason selected by the customer.
- name: flaggedAt
type: datetime
required: true
description: Time the review was flagged.
---
## Overview
Review Flag captures [[command|flag-review]] interactions and can send a published review back through moderation.
---
id: review-vote
name: Review Vote
version: 1.0.0
identifier: voteId
summary: A customer's helpfulness vote on a product review.
owners:
- reviews-platform
properties:
- name: voteId
type: UUID
required: true
description: Unique review vote identifier.
- name: reviewId
type: UUID
required: true
description: Review being voted on.
references: review
relationType: votesOn
referencesIdentifier: reviewId
- name: customerId
type: UUID
required: true
description: Customer who voted.
references: customer-profile
relationType: submittedBy
referencesIdentifier: customerId
- name: votedAt
type: datetime
required: true
description: Time the vote was submitted.
---
## Overview
Review Vote captures [[command|vote-review-helpful]] interactions and contributes to review helpfulness ranking.
---
id: search-document
name: Search Document
version: 1.0.0
identifier: documentId
summary: The denormalized representation of product data indexed by Search.
owners:
- search-platform
properties:
- name: documentId
type: string
required: true
description: Search index document identifier.
- name: productId
type: UUID
required: true
description: Product represented by the document.
references: product
relationType: represents
referencesIdentifier: productId
- name: searchableText
type: string
required: true
description: Text used for matching and ranking.
- name: indexedAt
type: datetime
required: true
description: Time the document was last indexed.
---
## Overview
Search Document is the read model maintained by [[system|search-system]]. It is eventually consistent with the Product Catalog System.
---
id: shipment
name: Shipment
version: 1.0.0
identifier: shipmentId
aggregateRoot: true
summary: A carrier delivery for a packed customer order.
owners:
- fulfilment-platform
properties:
- name: shipmentId
type: UUID
required: true
description: Unique shipment identifier.
- name: orderId
type: UUID
required: true
description: Order being shipped.
references: order
relationType: ships
referencesIdentifier: orderId
- name: carrierReference
type: string
required: false
description: External carrier tracking reference.
- name: status
type: string
required: true
description: Shipment delivery status.
---
## Overview
Shipment is created by the Shipping System and updated from carrier events such as [[event|shipment-created]] and [[event|shipment-delivered]].
---
id: stock-item
name: Stock Item
version: 1.0.0
identifier: stockItemId
aggregateRoot: true
summary: The inventory record for a product variant at a location.
owners:
- fulfilment-platform
properties:
- name: stockItemId
type: UUID
required: true
description: Unique stock item identifier.
- name: productId
type: UUID
required: true
description: Product held in stock.
references: product
relationType: stocks
referencesIdentifier: productId
- name: locationId
type: string
required: true
description: Warehouse or fulfilment location.
- name: availableQuantity
type: integer
required: true
description: Quantity available to reserve.
---
## Overview
Stock Item is the Inventory System's view of available stock for a product at a fulfilment location.
---
id: warehouse-pick
name: Warehouse Pick
version: 1.0.0
identifier: pickId
summary: A warehouse task to pick items for a completed order.
owners:
- fulfilment-platform
properties:
- name: pickId
type: UUID
required: true
description: Unique warehouse pick identifier.
- name: orderId
type: UUID
required: true
description: Order being picked.
references: order
relationType: fulfils
referencesIdentifier: orderId
- name: assignedTo
type: string
required: false
description: Warehouse worker or automation lane assigned.
- name: status
type: string
required: true
description: Pick task status.
---
## Overview
Warehouse Pick represents the operational task handled by the Warehouse System before an order can be packed and shipped.
---
id: cart-database
name: Cart Database
version: 1.0.0
summary: PostgreSQL database that is the system of record for shopping carts and their items.
container_type: database
technology: postgres@16
authoritative: true
access_mode: readWrite
purpose: System of record for shopping carts
classification: internal
retention: 90d
residency: eu-west-1
styles:
icon: /icons/database/postgresql.svg
---
### What is this?
The **Cart Database** is the authoritative store for shopping carts at Acme Inc. The [[service|cart-api]] reads from and writes to it as customers add, remove and check out items.
### What does it store?
- **Carts** — one row per cart: id, customer, status and timestamps.
- **Cart Items** — one row per item in a cart: product, quantity and unit price.
### Schema
### Retention
Carts are transient. Abandoned carts are pruned after **90 days** (see frontmatter). A checked-out cart's contents live on in the [[event|cart-checked-out]] event and downstream order records.
---
id: customer-database
name: Customer Database
version: 1.0.0
summary: PostgreSQL database that is the system of record for all customer profile data.
container_type: database
technology: postgres@16
authoritative: true
access_mode: readWrite
purpose: System of record for customer profiles
classification: confidential
retention: indefinite
residency: eu-west-1
styles:
icon: /icons/database/postgresql.svg
---
### What is this?
The **Customer Database** is the authoritative store for every customer profile at Acme Inc. The [[service|customer-api]] reads from and writes to it. It stores profile data only — credentials and authentication live in the [[system|identity-provider]]'s [[container|user-directory]], not here.
### What does it store?
- **Customers** — one row per customer: id, email, name and account status.
### Schema
### Access patterns
- The [[service|customer-api]] is the only writer on the request path.
- No credentials or passwords are stored here — only profile data. Authentication is owned by the [[system|identity-provider]].
### Classification
Customer profile data is **confidential**. Access is role-based and least-privilege; PII handling follows Acme's data policies.
---
id: inventory-database
name: Inventory Database
version: 1.0.0
summary: PostgreSQL database that is the system of record for stock levels and reservations.
container_type: database
technology: postgres@16
authoritative: true
access_mode: readWrite
purpose: System of record for stock levels and reservations
classification: internal
retention: 3y
residency: eu-west-1
styles:
icon: /icons/database/postgresql.svg
---
### What is this?
The **Inventory Database** is the authoritative store for stock levels at Acme Inc. The [[service|inventory-service]] reads from and writes to it as stock is reserved and released.
### What does it store?
- **Stock** — one row per product: available quantity and reserved quantity.
- **Reservations** — one row per reservation: id, order, items and status.
### Schema
---
id: order-database
name: Order Database
version: 1.0.0
summary: PostgreSQL database that is the system of record for orders and their items.
container_type: database
technology: postgres@16
authoritative: true
access_mode: readWrite
purpose: System of record for orders
classification: confidential
retention: 7y
residency: eu-west-1
styles:
icon: /icons/database/postgresql.svg
---
### What is this?
The **Order Database** is the authoritative store for orders at Acme Inc. The [[service|order-service]] reads from and writes to it as orders are created, cancelled and completed.
### What does it store?
- **Orders** — one row per order: id, customer, status, total and timestamps.
- **Order Items** — one row per item in an order: product, quantity and unit price.
### Schema
### Retention
Orders are financial records and are retained for **7 years** (see frontmatter) to meet accounting and audit requirements.
---
id: payment-database
name: Payment Database
version: 1.0.0
summary: PostgreSQL database that is the system of record for payments and refunds.
container_type: database
technology: postgres@16
authoritative: true
access_mode: readWrite
purpose: System of record for payments and refunds
classification: confidential
retention: 7y
residency: eu-west-1
styles:
icon: /icons/database/postgresql.svg
---
### What is this?
The **Payment Database** is the authoritative store for payments and refunds at Acme Inc. The [[service|payment-api]] and [[service|payment-worker]] read from and write to it as payments are authorized, charged and refunded.
### What does it store?
- **Payments** — one row per payment: id, order, amount, status and timestamps.
- **Refunds** — one row per refund: id, payment, amount, status and timestamps.
### Schema
### Retention
Payments and refunds are financial records and are retained for **7 years** (see frontmatter) to meet accounting and audit requirements.
---
id: product-database
name: Product Database
version: 1.0.0
summary: PostgreSQL database that is the system of record for all product data.
container_type: database
technology: postgres@16
authoritative: true
access_mode: readWrite
purpose: System of record for products, plus the change outbox used to publish events
classification: internal
retention: indefinite
residency: eu-west-1
styles:
icon: /icons/database/postgresql.svg
---
### What is this?
The **Product Database** is the authoritative store for every product in the catalog. The [[service|product-api]] reads from and writes to it, and the [[service|product-worker]] uses it for asynchronous enrichment. It also holds the **outbox** table that the [[service|product-search-publisher]] reads to publish product change events.
### What does it store?
- **Products** — one row per product: SKU, name, description, price, currency, category and lifecycle status.
- **Outbox** — one row per product change, used to reliably publish [[event|product-created]], [[event|product-updated]] and [[event|product-deleted]] events.
### Schema
### Access patterns
- The [[service|product-api]] is the only writer to the `products` table on the request path.
- The [[service|product-search-publisher]] is a read-only consumer of the `outbox` table.
- The [[service|product-worker]] reads and writes for asynchronous enrichment jobs.
### Why an outbox?
Writing the product change and the event in the **same transaction** guarantees we never persist a change without an event, or publish an event for a change that rolled back. The publisher reads the outbox and emits events with at-least-once delivery.
---
id: promotion-database
name: Promotion Database
version: 1.0.0
summary: PostgreSQL store of promotion and discount rules.
container_type: database
technology: postgres@16
authoritative: true
access_mode: readWrite
purpose: System of record for promotion and discount rules
classification: internal
retention: indefinite
residency: eu-west-1
styles:
icon: /icons/database/postgresql.svg
---
### What is this?
The **Promotion Database** holds the promotion and discount rules that the [[service|promotion-service]] evaluates when pricing a cart. It is the source of truth for what promotions exist, who they apply to, and when they are valid.
### What does it store?
- **Promotions** — one row per promotion: code, type (percentage / fixed amount), value, and validity window.
- **Eligibility rules** — the conditions under which a promotion applies (minimum spend, customer segment, etc.).
### Schema
### Access patterns
- The [[service|promotion-service]] reads rules when handling [[command|calculate-discount]].
- Rules are managed by the promotions team and change infrequently relative to read volume.
---
id: rating-cache
name: Rating Cache
version: 1.0.0
summary: Redis cache that serves each product's aggregate star rating with low latency.
container_type: cache
technology: redis@7
authoritative: false
access_mode: readWrite
purpose: Fast read store for aggregate product ratings
classification: internal
retention: transient
residency: eu-west-1
---
### What is this?
The **Rating Cache** holds the aggregate rating (average score and review count) for each product. It is a derived read model — never a source of truth — so it can be rebuilt at any time by replaying published reviews.
### What does it store?
- **Aggregate rating** — one entry per product: average rating, review count and last-updated timestamp.
### Access patterns
- The [[service|rating-aggregator]] writes the aggregate rating whenever a review is published.
- The [[service|review-api]] reads it to serve [[query|get-product-reviews]].
---
id: review-database
name: Review Database
version: 1.0.0
summary: PostgreSQL database that is the system of record for reviews and their moderation state.
container_type: database
technology: postgres@16
authoritative: true
access_mode: readWrite
purpose: System of record for reviews, ratings and moderation decisions
classification: internal
retention: indefinite
residency: eu-west-1
styles:
icon: /icons/database/postgresql.svg
---
### What is this?
The **Review Database** is the authoritative store for every review in the Reviews & Ratings domain. The [[service|review-api]] writes new reviews to it, and the [[service|review-moderation-worker]] records each moderation decision against the stored review.
### What does it store?
- **Reviews** — one row per review: product, customer, rating, title, body and lifecycle status (`submitted`, `published`, `rejected`).
- **Moderation decisions** — the outcome and reason for each moderated review, kept for audit.
### Access patterns
- The [[service|review-api]] writes new reviews and reads published reviews.
- The [[service|review-moderation-worker]] reads submitted reviews and writes moderation outcomes.
- The [[service|rating-aggregator]] reads published reviews to recompute aggregates.
---
id: search-index
name: Search Index
version: 1.0.0
summary: The denormalised, search-optimised index of products that powers product search.
container_type: searchIndex
technology: opensearch@2
authoritative: false
access_mode: readWrite
purpose: Serve fast, relevant product search
classification: internal
retention: rebuildable
residency: eu-west-1
styles:
icon: /icons/analytics/clickhouse.svg
---
### What is this?
The **Search Index** is a denormalised, search-optimised copy of the catalog. It is **not** a source of truth — it can be rebuilt at any time by replaying product events from the [[system|product-catalog-system]]. The [[service|search-indexer]] keeps it up to date, and the [[service|search-api]] reads from it to answer [[query|search-products]] queries.
### What does it store?
One document per product, optimised for search:
- Searchable text — name and description, analysed for full-text matching.
- Filterable fields — category, status, price, currency.
- A relevance signal used to rank results.
### Why is it not authoritative?
The system of record is the [[container|product-database]]. The index is a derived read model: if it is ever lost or corrupted, we rebuild it by replaying [[event|product-created]], [[event|product-updated]] and [[event|product-deleted]] events. This keeps search fast without coupling other teams to the catalog database.
### Operational notes
- **Rebuildable**: a full reindex is a supported, routine operation.
- **Eventually consistent**: changes appear in search shortly after the [[service|search-indexer]] processes the corresponding event.
---
id: user-directory
name: User Directory
version: 1.0.0
summary: The directory of customer credentials and identities — the source of truth for authentication.
container_type: database
technology: postgres@16
authoritative: true
access_mode: readWrite
purpose: System of record for credentials and login identities
classification: regulated
retention: indefinite
residency: eu-west-1
styles:
icon: /icons/database/postgresql.svg
---
### What is this?
The **User Directory** is the authoritative store for customer credentials and login identities. The [[service|oauth-api]] reads from it to verify sign-in attempts. It holds **only** authentication data — customer profile data lives separately in the [[system|customer-management-system]]'s [[container|customer-database]].
### What does it store?
- **Identities** — one record per customer: the login email and a securely hashed credential.
- **Login metadata** — last login time, multi-factor settings, lockout state.
### Why is it separate from the customer profile?
Keeping credentials in a dedicated, **regulated**-classification store isolates the most sensitive data from general profile data. Authentication is owned by the Identity Provider; the Customer Management System never sees raw credentials.
### Security
- Credentials are stored only as salted, hashed values — never in plaintext.
- Access is tightly restricted to the [[service|oauth-api]] under least-privilege roles.
---
id: warehouse-database
name: Warehouse Database
version: 1.0.0
summary: PostgreSQL database that stores picking jobs and their status.
container_type: database
technology: postgres@16
authoritative: true
access_mode: readWrite
purpose: System of record for picking and packing jobs
classification: internal
retention: 1y
residency: eu-west-1
styles:
icon: /icons/database/postgresql.svg
---
### What is this?
The **Warehouse Database** stores the picking and packing jobs for the warehouse. The [[service|warehouse-service]] creates jobs and the [[service|picking-worker]] updates them as orders are picked.
### What does it store?
- **Picking Jobs** — one row per order being fulfilled: order, status and timestamps.
- **Picking Job Items** — the items to pick for each job.
### Schema
---
id: checkout-saga
name: Checkout Saga
version: 1.0.0
summary: |
How the Checkout Orchestrator turns a checked-out cart into an order — reserving inventory, authorizing payment and creating the order, with compensation when a step fails.
owners:
- ordering-platform
steps:
- id: cart_checked_out
title: Cart Checked Out
message:
id: cart-checked-out
version: 1.0.0
next_step:
id: checkout_api
label: Receive checkout
- id: checkout_api
title: Checkout API
service:
id: checkout-api
version: 1.0.0
next_step:
id: orchestrator
label: Start saga
- id: orchestrator
title: Checkout Orchestrator
service:
id: checkout-orchestrator
version: 1.0.0
next_step:
id: reserve_inventory
label: Step 1 — reserve inventory
- id: reserve_inventory
title: Reserve Inventory
message:
id: reserve-inventory
version: 1.0.0
next_steps:
- id: authorize_payment
label: Reserved
- id: compensate_release
label: Out of stock
- id: authorize_payment
title: Authorize Payment
message:
id: authorize-payment
version: 1.0.0
next_steps:
- id: create_order
label: Authorized
- id: compensate_release
label: Declined
- id: create_order
title: Create Order
message:
id: create-order
version: 1.0.0
next_step:
id: saga_complete
label: Order created
- id: saga_complete
title: Saga complete
custom:
title: Saga complete
color: green
icon: CheckCircleIcon
type: Outcome
summary: Inventory reserved, payment authorized and order created. The saga succeeds.
- id: compensate_release
title: Compensate
custom:
title: Compensate and abort
color: red
icon: ArrowUturnLeftIcon
type: Compensation
summary: A step failed. The orchestrator releases any reservation and voids any authorization, then aborts the saga without creating an order.
properties:
actions: 'release reservation, void authorization'
---
## Overview
The **Checkout Saga** is the heart of the [[system|checkout-system]]. It coordinates the steps that turn a checked-out cart into a confirmed order. Each step has a compensating action so a failure never leaves the customer in an inconsistent state.
## Steps
1. **Reserve inventory** — [[command|reserve-inventory]] holds stock for the cart's items.
2. **Authorize payment** — [[command|authorize-payment]] places a hold on the order total.
3. **Create order** — [[command|create-order]] persists the order in the [[system|order-management-system]].
If reservation or authorization fails, the orchestrator **compensates** — releasing the reservation and voiding the authorization — and aborts without creating an order.
---
id: order-cancellation
name: Order Cancellation
version: 1.0.0
summary: |
How an order is cancelled — whether requested by the customer or triggered by a failure — and the events that tell the rest of the business to unwind it.
owners:
- ordering-platform
steps:
- id: cancellation_trigger
title: Cancellation requested
actor:
name: Shopper or System
summary: A customer asks to cancel, or a downstream failure (payment, inventory) forces a cancellation.
next_step:
id: cancel_order_command
label: Cancel order
- id: cancel_order_command
title: Cancel Order
message:
id: cancel-order
version: 1.0.0
next_step:
id: order_service
label: Handle cancellation
- id: order_service
title: Order Service
service:
id: order-service
version: 1.0.0
next_steps:
- id: eligibility_check
label: Check eligibility
- id: not_cancellable
label: Already completed
- id: eligibility_check
title: Cancellation policy check
custom:
title: Cancellation policy
color: blue
icon: ClipboardDocumentCheckIcon
type: Policy
summary: An order can only be cancelled before it is completed. Completed orders must go through returns instead.
properties:
rule: 'status must be CREATED'
next_step:
id: order_database
label: Mark cancelled
- id: order_database
title: Order Database
container:
id: order-database
next_step:
id: order_cancelled
label: Persist + publish
- id: order_cancelled
title: Order Cancelled
message:
id: order-cancelled
version: 1.0.0
next_step:
id: downstream_unwind
label: Unwind downstream
- id: downstream_unwind
title: Downstream unwind
custom:
title: Release and refund
color: orange
icon: ArrowUturnLeftIcon
type: Compensation
summary: Consumers of OrderCancelled release reserved inventory, void or refund the payment, and stop fulfilment.
properties:
consumers: 'inventory, payment, fulfilment'
- id: not_cancellable
title: Cannot cancel
custom:
title: Cannot cancel
color: red
icon: ExclamationTriangleIcon
type: Exception
summary: The order has already been completed and cannot be cancelled. The customer is directed to the returns process.
properties:
next_action: 'start a return'
---
## Overview
**Order Cancellation** documents how the [[system|order-management-system]] cancels an order. Cancellation can be requested by a shopper or forced by a downstream failure during checkout. Only orders that have not yet completed can be cancelled.
## How it works
1. A [[command|cancel-order]] command reaches the [[service|order-service]].
2. The service checks the cancellation policy — only `CREATED` orders are cancellable.
3. If eligible, the order is marked cancelled in the [[container|order-database]] and [[event|order-cancelled]] is published.
4. Downstream consumers react to [[event|order-cancelled]] to release inventory, refund payment and stop fulfilment.
5. If the order is already completed, cancellation is rejected and the customer is sent to the returns process.
---
id: place-an-order
name: Place an Order
version: 1.0.0
summary: |
The end-to-end journey from a customer checking out their cart to a confirmed order — spanning the Shopping and Ordering domains, including the checkout saga and its failure path.
owners:
- ordering-platform
steps:
- id: shopper_checks_out
title: Shopper checks out
actor:
name: Shopper
summary: The customer confirms their cart and starts checkout.
next_step:
id: checkout_cart_command
label: Check out cart
- id: checkout_cart_command
title: Checkout Cart
message:
id: checkout-cart
version: 1.0.0
next_step:
id: cart_api
label: Price and finalise cart
- id: cart_api
title: Cart API
service:
id: cart-api
version: 1.0.0
next_step:
id: cart_checked_out
label: Publish checkout
- id: cart_checked_out
title: Cart Checked Out
message:
id: cart-checked-out
version: 1.0.0
next_step:
id: checkout_api
label: Start checkout flow
- id: checkout_api
title: Checkout API
service:
id: checkout-api
version: 1.0.0
next_step:
id: checkout_orchestrator
label: Run checkout saga
- id: checkout_orchestrator
title: Checkout Orchestrator
service:
id: checkout-orchestrator
version: 1.0.0
next_steps:
- id: reserve_inventory
label: Reserve inventory
- id: authorize_payment
label: Authorize payment
- id: reserve_inventory
title: Reserve Inventory
message:
id: reserve-inventory
version: 1.0.0
next_step:
id: authorize_payment
label: Inventory held
- id: authorize_payment
title: Authorize Payment
message:
id: authorize-payment
version: 1.0.0
next_steps:
- id: create_order
label: Payment authorized
- id: checkout_failed
label: Authorization declined
- id: create_order
title: Create Order
message:
id: create-order
version: 1.0.0
next_step:
id: order_service
label: Persist order
- id: order_service
title: Order Service
service:
id: order-service
version: 1.0.0
next_step:
id: order_created
label: Publish order created
- id: order_created
title: Order Created
message:
id: order-created
version: 1.0.0
next_step:
id: order_confirmed
label: Confirm to customer
- id: order_confirmed
title: Order confirmed
custom:
title: Order confirmed
color: green
icon: CheckCircleIcon
type: Outcome
summary: The customer's order is placed and confirmed. Fulfilment begins.
properties:
happy_path: 'true'
- id: checkout_failed
title: Checkout failed
custom:
title: Checkout failed
color: red
icon: ExclamationTriangleIcon
type: Exception
summary: A checkout step failed (e.g. payment declined). The orchestrator compensates earlier steps and cancels the order.
properties:
common_causes: 'payment declined, out of stock'
next_action: 'release reservation, void authorization, cancel order'
next_step:
id: order_cancelled
label: Cancel order
- id: order_cancelled
title: Order Cancelled
message:
id: order-cancelled
version: 1.0.0
---
## Overview
**Place an Order** is the headline business flow at Acme Inc. It begins in the [[domain|shopping]] domain, when a shopper checks out their cart, and finishes in the [[domain|ordering]] domain, with a confirmed order — or a compensated, cancelled one if a step fails.
## How it works
1. The shopper checks out — the [[service|cart-api]] prices the cart and publishes [[event|cart-checked-out]].
2. The [[service|checkout-api]] picks this up and hands it to the [[service|checkout-orchestrator]].
3. The orchestrator runs the saga: [[command|reserve-inventory]] then [[command|authorize-payment]].
4. On success it sends [[command|create-order]] to the [[service|order-service]], which publishes [[event|order-created]].
5. If any step fails, the orchestrator compensates the earlier steps and the order is cancelled via [[event|order-cancelled]].
---
id: product-search-indexing
name: Product Search Indexing
version: 1.0.0
summary: |
How a change to a product in the catalog reliably flows into the search index — via the outbox, product events and the indexer — so search stays in sync without coupling to the catalog database.
owners:
- search-platform
steps:
- id: merchant_edits_product
title: Merchant edits a product
actor:
name: Merchant
summary: A merchant creates or updates a product in the catalog.
next_step:
id: product_api
label: Apply change
- id: product_api
title: Product API
service:
id: product-api
version: 1.0.0
next_step:
id: product_database
label: Write change + outbox row
- id: product_database
title: Product Database
container:
id: product-database
next_step:
id: outbox_note
label: Outbox row committed
- id: outbox_note
title: Outbox pattern
custom:
title: Transactional outbox
color: blue
icon: InboxStackIcon
type: Pattern
summary: The product change and an outbox row are written in the same transaction, so the event can never be lost or out of sync with the data.
properties:
guarantee: 'change and event are atomic'
next_step:
id: product_search_publisher
label: Drain outbox
- id: product_search_publisher
title: Product Search Publisher
service:
id: product-search-publisher
version: 1.0.0
next_steps:
- id: product_created
label: Created
- id: product_updated
label: Updated
- id: product_deleted
label: Deleted
- id: product_created
title: Product Created
message:
id: product-created
version: 1.0.0
next_step:
id: search_indexer
label: Index product
- id: product_updated
title: Product Updated
message:
id: product-updated
version: 1.0.0
next_step:
id: search_indexer
label: Re-index product
- id: product_deleted
title: Product Deleted
message:
id: product-deleted
version: 1.0.0
next_step:
id: search_indexer
label: Remove from index
- id: search_indexer
title: Search Indexer
service:
id: search-indexer
version: 1.0.0
next_step:
id: search_index
label: Apply to index
- id: search_index
title: Search Index
container:
id: search-index
next_step:
id: searchable
label: Available to search
- id: searchable
title: Product is searchable
custom:
title: Product is searchable
color: green
icon: MagnifyingGlassIcon
type: Outcome
summary: The change is reflected in the search index and immediately available to customers via the Search API.
properties:
read_model: 'derived, rebuildable from events'
---
## Overview
**Product Search Indexing** documents how the [[system|search-system]] keeps its index in sync with the catalog. The search index is a derived read model — never a source of truth — so it can be rebuilt at any time by replaying product events.
## How it works
1. A merchant changes a product via the [[service|product-api]], which writes the change and an outbox row to the [[container|product-database]] in one transaction.
2. The [[service|product-search-publisher]] reliably drains the outbox and publishes [[event|product-created]], [[event|product-updated]] or [[event|product-deleted]].
3. The [[service|search-indexer]] consumes those events and applies them to the [[container|search-index]].
4. The change is now searchable via the Search API — with no direct coupling between search and the catalog database.
---
id: review-submission
name: Review Submission
version: 1.0.0
summary: |
How a customer's product review travels from submission, through moderation, to being published and folded into the product's aggregate rating.
owners:
- reviews-platform
steps:
- id: customer_submits
title: Customer submits a review
actor:
name: Customer
summary: A customer writes a review and rating for a product they purchased.
next_step:
id: review_api
label: Submit review
- id: review_api
title: Review API
service:
id: review-api
version: 1.0.0
next_step:
id: review_database
label: Store review
- id: review_database
title: Review Database
container:
id: review-database
next_step:
id: review_submitted
label: Review stored
- id: review_submitted
title: Review Submitted
message:
id: review-submitted
version: 1.0.0
next_step:
id: moderation_worker
label: Screen review
- id: moderation_worker
title: Review Moderation Worker
service:
id: review-moderation-worker
version: 1.0.0
next_steps:
- id: review_published
label: Approved
- id: review_rejected
label: Rejected
- id: review_published
title: Review Published
message:
id: review-published
version: 1.0.0
next_step:
id: rating_aggregator
label: Update rating
- id: review_rejected
title: Review Rejected
message:
id: review-rejected
version: 1.0.0
next_step:
id: rejected_outcome
label: Not shown
- id: rating_aggregator
title: Rating Aggregator
service:
id: rating-aggregator
version: 1.0.0
next_step:
id: rating_cache
label: Write aggregate
- id: rating_cache
title: Rating Cache
container:
id: rating-cache
next_step:
id: published_outcome
label: Visible on storefront
- id: published_outcome
title: Review is live
custom:
title: Review is live
color: green
icon: StarIcon
type: Outcome
summary: The review is published and the product's aggregate rating is updated and served from the cache.
- id: rejected_outcome
title: Review rejected
custom:
title: Review rejected
color: red
icon: NoSymbolIcon
type: Outcome
summary: The review failed moderation. It is kept for audit but never shown on the storefront.
---
## Overview
**Review Submission** documents the journey of a customer review from submission through moderation to publication. A review is only ever folded into a product's rating once it has been approved.
## How it works
1. A customer submits a review via the [[service|review-api]], which stores it in the [[container|review-database]] and publishes [[event|review-submitted]].
2. The [[service|review-moderation-worker]] screens the review and publishes either [[event|review-published]] or [[event|review-rejected]].
3. On approval, the [[service|rating-aggregator]] updates the product's aggregate rating in the [[container|rating-cache]] and the review goes live.
---
dictionary:
- id: Cart
name: Cart
summary: "A customer's in-progress collection of items they intend to buy."
description: |
The cart is the central concept of the Shopping domain. It is owned by the Cart System, which
is the source of truth for cart contents. A cart has a status (OPEN, CHECKED_OUT or ABANDONED),
a customer, a currency, and a set of cart items. Carts are transient — abandoned carts are
pruned after a retention window.
icon: ShoppingCart
- id: Cart Item
name: Cart Item
summary: "A single product line within a cart: a product, a quantity and a unit price."
icon: ListOrdered
- id: Checkout
name: Checkout
summary: "The act of finalising a cart — pricing it and committing to purchase."
description: |
At checkout the Cart System prices the cart (including any discounts from the Promotion System)
and, on success, publishes a CartCheckedOut event that the rest of the business reacts to —
creating an order, taking payment and beginning fulfilment.
icon: CreditCard
- id: Promotion
name: Promotion
summary: "A rule that reduces the price of a cart, such as a percentage off or a fixed amount."
description: |
Promotions are owned by the Promotion System. Each promotion has a code, a type (PERCENTAGE or
FIXED_AMOUNT), a value, a validity window, and eligibility rules (e.g. minimum spend or customer
segment) that determine when it applies.
icon: Tag
- id: Discount
name: Discount
summary: "The actual amount taken off a specific cart after evaluating the applicable promotions."
description: |
A discount is the calculated result of applying promotions to a cart. The Cart System asks the
Promotion System to calculate it; the Promotion System evaluates the rules and returns the
discount, also publishing a DiscountCalculated event.
icon: Percent
- id: Subtotal
name: Subtotal
summary: "The total value of a cart's items before any discounts are applied."
icon: Calculator
- id: Promotion Code
name: Promotion Code
summary: "A code a customer enters at checkout to apply a specific promotion."
icon: Ticket
---
---
dictionary:
- id: Customer
name: Customer
summary: "A person with an account at Acme Inc, identified by a unique customer id and email."
description: |
The customer is the central concept of the Customer domain. Their profile is owned by the
Customer Management System, which is the source of truth for who a customer is. A customer has:
- A unique customer id and a unique email
- A display name
- An account status (ACTIVE, SUSPENDED or CLOSED)
A customer's profile data is kept deliberately separate from their credentials, which live in
the Identity Provider.
icon: User
- id: Identity
name: Identity
summary: "The credentials and login information used to prove a customer is who they say they are."
description: |
An identity is distinct from a customer profile. It lives in the Identity Provider's user
directory and holds the login email and a securely hashed credential. Keeping identity separate
from profile data isolates the most sensitive information.
icon: Fingerprint
- id: Authentication
name: Authentication
summary: "Verifying that a sign-in attempt belongs to a real customer."
description: |
Authentication is owned by the Identity Provider. It verifies credentials against the user
directory and, on success, issues an access token and publishes a CustomerAuthenticated event.
icon: LockKeyhole
- id: Credential
name: Credential
summary: "A secret (such as a password) a customer uses to authenticate. Never stored in plain text."
icon: KeyRound
- id: Account Status
name: Account Status
summary: "Where a customer account sits: ACTIVE, SUSPENDED or CLOSED."
description: |
- ACTIVE — the account is in good standing and can be used.
- SUSPENDED — temporarily blocked (e.g. for review).
- CLOSED — permanently deactivated.
icon: Workflow
- id: User Directory
name: User Directory
summary: "The authoritative store of customer credentials and login identities."
icon: Users
---
---
dictionary:
- id: Fulfilment
name: Fulfilment
summary: "Everything that gets a confirmed order physically to the customer — stock, packing and shipping."
icon: PackageCheck
- id: Stock
name: Stock
summary: "The quantity of a product physically available to sell."
description: |
Stock is owned by the Inventory System. Each product has an available quantity and a reserved
quantity. Stock is the source of truth for whether an order can be fulfilled.
icon: Boxes
- id: Reservation
name: Reservation
summary: "A temporary hold on stock for a specific order, taken during checkout."
description: |
A reservation guarantees stock is set aside for an order while payment is taken. It is held,
then either consumed when the order ships or released if checkout fails.
icon: BookmarkCheck
- id: Picking
name: Picking
summary: "Collecting an order's items from the warehouse shelves."
icon: Hand
- id: Packing
name: Packing
summary: "Boxing up a picked order into one or more parcels ready for shipping."
icon: Package
- id: Shipment
name: Shipment
summary: "A packed order handed to a carrier for delivery, tracked from dispatch to delivery."
description: |
A shipment is created with an external carrier once an order is packed. Its lifecycle —
created, delivered or failed — is reported back by the carrier.
icon: Truck
- id: Carrier
name: Carrier
summary: "The external delivery company that transports shipments to customers."
icon: Globe
- id: Tracking Number
name: Tracking Number
summary: "A code from the carrier that lets the customer follow a shipment's progress."
icon: ScanBarcode
---
---
dictionary:
- id: Order
name: Order
summary: "A confirmed intent to purchase, created from a checked-out cart and owned for its whole lifecycle."
description: |
The order is the central concept of the Ordering domain. It is owned by the Order Management
System, which is the source of truth for orders. An order has:
- A unique order id and the customer it belongs to
- A set of order items (product, quantity and unit price)
- A total and currency
- A status (CREATED, COMPLETED or CANCELLED)
An order is immutable in its essentials once created — its lifecycle is expressed through events,
not by editing it in place.
icon: ClipboardList
- id: Checkout
name: Checkout
summary: "The flow that turns a checked-out cart into a confirmed order."
description: |
Checkout is owned by the Checkout System. It is the orchestration that runs after the Shopping
domain checks out a cart — reserving inventory, authorizing payment and creating the order.
icon: CreditCard
- id: Saga
name: Saga
summary: "A multi-step process with compensating actions, used to coordinate checkout across systems."
description: |
The Checkout Orchestrator runs checkout as a saga: a sequence of steps (reserve inventory,
authorize payment, create order) where each step has a compensating action that undoes it if a
later step fails. This keeps the customer consistent without distributed transactions.
icon: Workflow
- id: Reservation
name: Reservation
summary: "A temporary hold on stock for the items in a cart, taken during checkout."
icon: PackageCheck
- id: Authorization
name: Authorization
summary: "A hold placed on a customer's payment method for the order total, captured when the order is created."
icon: ShieldCheck
- id: Order Item
name: Order Item
summary: "A single product line within an order: a product, a quantity and the price paid per unit."
icon: ListOrdered
- id: Order Status
name: Order Status
summary: "Where an order sits in its life: CREATED, COMPLETED or CANCELLED."
description: |
- CREATED — the order exists and is being fulfilled.
- COMPLETED — the order has been fully fulfilled.
- CANCELLED — the order was cancelled before completion.
icon: Workflow
---
---
dictionary:
- id: Product
name: Product
summary: "A single item Acme Inc sells, with a name, price, category and lifecycle status."
description: |
A product is the central concept of the Catalog domain. It is owned and maintained by the
Product Catalog System, which is the source of truth for all product data. A product carries:
- A unique product id and a unique SKU
- Display name, description and category
- Price (in minor units) and currency
- A lifecycle status (DRAFT, ACTIVE or ARCHIVED)
Every change to a product publishes a domain event so the rest of the business — including
search — can react.
icon: Package
- id: SKU
name: SKU
summary: "Stock Keeping Unit — the unique, human-meaningful code that identifies a product."
description: |
A SKU uniquely identifies a product in the catalog and must be unique across all products.
Unlike the internal product id (a UUID), the SKU is the code teams and merchants use day to day.
icon: Tag
- id: Catalog
name: Catalog
summary: "The complete, authoritative collection of products Acme Inc offers."
icon: BookOpen
- id: Search Index
name: Search Index
summary: "A denormalised, search-optimised copy of the catalog that powers product search."
description: |
The search index is a derived read model, not a source of truth. It is kept in sync by the
Search System consuming product change events, and can be rebuilt at any time by replaying
those events. It exists to serve fast, relevant search without coupling consumers to the
catalog database.
icon: Search
- id: Lifecycle Status
name: Lifecycle Status
summary: "Where a product sits in its life: DRAFT, ACTIVE or ARCHIVED."
description: |
- DRAFT — being prepared, not yet visible to customers.
- ACTIVE — live and discoverable.
- ARCHIVED — withdrawn from sale but retained for history.
icon: Workflow
- id: Outbox
name: Outbox
summary: "A table where product changes are recorded in the same transaction, then published as events."
description: |
The outbox is how the Product Catalog System guarantees that a product change and its event
are never out of sync. The Product API writes the change and an outbox row in one transaction;
the Product Search Publisher reliably drains the outbox to the broker.
icon: Mail
---
---
dictionary:
- id: Payment
name: Payment
summary: "A charge taken from a customer to pay for an order."
description: |
A payment is the central concept of the Payments domain. It is owned by the Payment Processing
System, which records every payment's status (REQUESTED, SUCCEEDED or FAILED). The actual money
movement happens at the external payment processor.
icon: CreditCard
- id: Authorization
name: Authorization
summary: "A hold placed on a customer's payment method, confirming funds are available before capture."
icon: ShieldCheck
- id: Capture
name: Capture
summary: "Taking the held funds from an authorized payment — turning an authorization into an actual charge."
icon: Banknote
- id: Refund
name: Refund
summary: "Returning money to a customer for a previous payment, in full or in part."
icon: Undo2
- id: Payment Processor
name: Payment Processor
summary: "The external provider (Stripe) that charges cards and issues refunds on Acme Inc's behalf."
description: |
The payment processor is a third party. Acme Inc never stores raw card details — it delegates
the actual charge and refund to the processor and reacts to the outcomes it reports back.
icon: Building2
- id: Fraud Screening
name: Fraud Screening
summary: "Checking a payment for signs of fraud before allowing the charge to proceed."
description: |
Fraud screening is performed by an external Fraud Detection provider. It returns a verdict —
passed or failed — that determines whether a payment is allowed or blocked.
icon: ShieldAlert
- id: Webhook
name: Webhook
summary: "A callback the payment processor sends to report the outcome of a charge or refund."
icon: Webhook
---
---
title: Catalog and search
summary: How product data is owned by the Product Catalog System and projected into Search for customer discovery.
owners:
- product-platform
badges:
- content: Domain guide
backgroundColor: blue
textColor: blue
---
[[domain|catalog]] owns the product information that customers browse and buy. It is split into two systems with different consistency needs.
## System context map
## Product Catalog System
[[system|product-catalog-system]] is the source of truth. [[service|product-api]] handles product commands and reads from [[container|product-database]]. Product changes are captured through an outbox and published by [[service|product-search-publisher]].
Key contracts:
- [[command|create-product]]
- [[command|update-product]]
- [[command|delete-product]]
- [[query|get-product]]
- [[event|product-created]]
- [[event|product-updated]]
- [[event|product-deleted]]
## Search System
[[system|search-system]] serves product discovery through [[service|search-api]] and [[query|search-products]]. It maintains [[container|search-index]] from product events.
The Search System should be treated as eventually consistent with the Product Catalog System. If a merchandiser updates a product, the product database is immediately authoritative; search visibility follows after indexing.
## Decision context
The product catalog has several architecture decisions documented directly on the system:
- [[adr|adr-001-use-transactional-outbox]]
- [[adr|adr-002-postgres-as-system-of-record]]
- [[adr|adr-003-offload-async-work-to-worker]]
These decisions explain why product events are published asynchronously and why Postgres remains the system of record.
---
title: Shopping and promotions
summary: How carts, checkout intent and discount calculation are modelled in the Shopping domain.
owners:
- shopping-platform
badges:
- content: Domain guide
backgroundColor: blue
textColor: blue
---
[[domain|shopping]] owns the customer's active path to purchase before an order exists. The core state is the cart, not the order.
## System context map
## Cart System
[[system|cart-system]] owns cart state in [[container|cart-database]]. [[service|cart-api]] handles:
- [[command|add-item-to-cart]]
- [[command|remove-item-from-cart]]
- [[command|checkout-cart]]
When a cart is checked out, it publishes [[event|cart-checked-out]]. That event is the handoff from Shopping to Ordering.
## Promotion System
[[system|promotion-system]] owns promotion rules in [[container|promotion-database]]. It handles [[command|calculate-discount]] and publishes [[event|discount-calculated]].
Discount calculation is deliberately separate from cart persistence. The Cart System owns what the customer is buying; the Promotion System owns how discounts are evaluated.
## Boundary with Ordering
Shopping does not create orders. Once [[event|cart-checked-out]] is published, [[system|checkout-system]] takes responsibility for coordinating inventory, payment and order creation.
This boundary keeps cart behavior and order lifecycle behavior independent. It also gives checkout a clear recovery point if inventory or payment fails.
---
title: Ordering and checkout
summary: How the Ordering domain coordinates checkout and owns the order lifecycle.
owners:
- ordering-platform
badges:
- content: Domain guide
backgroundColor: red
textColor: red
---
[[domain|ordering]] is the core revenue domain. It turns a checked-out cart into a durable order and owns that order through completion or cancellation.
## System context map
## Checkout System
[[system|checkout-system]] owns orchestration. [[service|checkout-api]] receives checkout intent, and [[service|checkout-orchestrator]] runs the [[flow|checkout-saga]].
The saga coordinates:
1. [[command|reserve-inventory]]
2. [[command|authorize-payment]]
3. [[command|create-order]]
If a step fails, the orchestrator compensates rather than leaving partial work behind.
## Order Management System
[[system|order-management-system]] owns order state in [[container|order-database]]. [[service|order-service]] handles [[command|create-order]], [[command|cancel-order]] and [[query|get-order]].
It publishes:
- [[event|order-created]]
- [[event|order-completed]]
- [[event|order-cancelled]]
## Operating guidance
Do not add payment or inventory state directly to orders unless it is a snapshot needed for audit or customer support. The owning systems remain [[system|payment-processing-system]] and [[system|inventory-system]].
When checkout behavior changes, update the [[flow|place-an-order]] and [[flow|checkout-saga]] pages as well as the command schemas.
Review a proposed Ordering domain change for Acme Inc. Identify whether it changes checkout orchestration, order state, payment
or inventory boundaries, customer-visible status, command schemas, event schemas or downstream fulfilment behavior. Return the
affected catalog resources and the teams that should review the change.
---
title: Payments and fraud
summary: How payment authorization, Stripe integration, refunds and fraud screening are represented in the Payments domain.
owners:
- payments-platform
badges:
- content: Domain guide
backgroundColor: red
textColor: red
---
[[domain|payments]] owns payment intent and payment outcomes. It integrates with external providers but keeps Acme's internal payment state in [[container|payment-database]].
## System context map
## Payment Processing System
[[system|payment-processing-system]] is composed of [[service|payment-api]] and [[service|payment-worker]].
[[service|payment-api]] receives [[command|authorize-payment]] from checkout and records the intent. [[service|payment-worker]] drives the external charge/refund process and records outcomes.
Important events:
- [[event|payment-requested]]
- [[event|payment-succeeded]]
- [[event|payment-failed]]
- [[event|refund-requested]]
## External providers
[[system|stripe]] is the external payment processor. It reports outcomes through [[service|stripe-webhook-endpoint]] events such as [[event|payment-succeeded]], [[event|payment-failed]] and [[event|refund-processed]].
[[system|fraud-detection]] screens payment attempts and reports [[event|fraud-check-passed]] or [[event|fraud-check-failed]].
## Failure handling
Payments cross external boundaries, so every step should be durable and retryable. Do not assume webhook delivery order. Payment state transitions should be idempotent and traceable through the payment database.
---
title: Fulfilment and shipping
summary: How stock reservation, warehouse packing and carrier handoff work after an order is completed.
owners:
- fulfilment-platform
badges:
- content: Domain guide
backgroundColor: blue
textColor: blue
---
[[domain|fulfilment]] gets confirmed orders to customers. It owns the operational handoff from stock reservation through warehouse work and carrier delivery.
## System context map
## Inventory System
[[system|inventory-system]] owns [[container|inventory-database]]. [[service|inventory-service]] handles [[command|reserve-inventory]], [[command|release-inventory]] and [[query|get-stock-level]].
It publishes [[event|inventory-reserved]] or [[event|inventory-unavailable]] during checkout.
## Warehouse System
[[system|warehouse-system]] owns picking and packing in [[container|warehouse-database]]. [[service|warehouse-service]] reacts to [[event|order-completed]] and publishes [[event|order-ready-for-shipping]].
[[service|picking-worker]] handles packing work and publishes [[event|order-packed]].
## Shipping System and Carrier
[[system|shipping-system]] creates shipments through [[command|create-shipment]]. [[system|carrier]] is the external delivery provider and reports [[event|shipment-created]], [[event|shipment-delivered]] or [[event|shipment-failed]].
## Boundary with Ordering
Ordering decides that an order exists. Fulfilment decides whether and how it can be delivered. Keep these lifecycles separate so cancellation, refunds and shipment exceptions can be handled independently.
---
title: Customer and identity
summary: How customer profiles and authentication are separated across Customer Management and Identity Provider systems.
owners:
- customer-platform
badges:
- content: Domain guide
backgroundColor: blue
textColor: blue
---
[[domain|customer]] owns customer profile data and customer authentication. The catalog separates profile management from identity management so customer details and credentials have different operational boundaries.
## System context map
## Customer Management System
[[system|customer-management-system]] owns [[container|customer-database]]. [[service|customer-api]] handles:
- [[command|register-customer]]
- [[command|update-customer]]
- [[query|get-customer]]
It publishes [[event|customer-registered]] and [[event|customer-updated]] so other capabilities can react to profile changes.
## Identity Provider
[[system|identity-provider]] owns authentication state in [[container|user-directory]]. [[service|oauth-api]] handles [[command|authenticate-customer]] and emits [[event|customer-authenticated]].
## Integration guidance
Services that need customer profile details should use [[query|get-customer]] or consume customer events where a local read model is appropriate. Services that need authentication should integrate with the identity boundary, not the profile database.
This split prevents order, review and payment systems from accidentally depending on credential storage.
---
title: Reviews and ratings
summary: How the Reviews domain accepts, moderates, publishes and aggregates product feedback.
owners:
- reviews-platform
badges:
- content: Domain guide
backgroundColor: purple
textColor: purple
---
[[domain|reviews]] owns customer feedback on products. Unlike the other domains, it is modelled directly with services and data stores rather than nested systems.
## Domain map
## Services
[[service|review-api]] accepts review commands and serves product reviews. It writes to [[container|review-database]] and reads aggregate data from [[container|rating-cache]].
[[service|review-moderation-worker]] consumes [[event|review-submitted]] and publishes either [[event|review-published]] or [[event|review-rejected]].
[[service|rating-aggregator]] reacts to published reviews and updates the product rating model, publishing [[event|rating-updated]].
## Core entity
[[entity|review]] is the central aggregate. It moves from submitted to moderated to published or rejected.
## Customer interactions
Customers can submit, flag and vote on reviews:
- [[command|submit-review]]
- [[command|flag-review]]
- [[command|vote-review-helpful]]
- [[query|get-product-reviews]]
## Product impact
Reviews influence product discovery and conversion, but they do not own product data. Product identity remains in [[domain|catalog]], while review state remains in Reviews.
---
title: Place an order
summary: The end-to-end customer purchase journey from cart checkout to confirmed order and downstream fulfilment.
owners:
- ordering-platform
badges:
- content: Flow
backgroundColor: orange
textColor: orange
---
[[flow|place-an-order]] is the highest-value customer journey in the catalog. It spans [[domain|shopping]], [[domain|ordering]], [[domain|payments]] and [[domain|fulfilment]].
## Flow map
## Happy path
1. The customer checks out through [[service|cart-api]] using [[command|checkout-cart]].
2. [[service|cart-api]] publishes [[event|cart-checked-out]].
3. [[service|checkout-api]] and [[service|checkout-orchestrator]] start checkout orchestration.
4. [[service|checkout-orchestrator]] reserves inventory with [[command|reserve-inventory]].
5. It authorizes payment with [[command|authorize-payment]].
6. It creates the order with [[command|create-order]].
7. [[service|order-service]] publishes [[event|order-created]] and eventually [[event|order-completed]].
8. Fulfilment consumes completed orders and prepares shipment.
## Important boundaries
The flow crosses several ownership boundaries. Shopping owns the cart, Ordering owns the order, Payments owns payment outcome, and Fulfilment owns stock and shipping. Each handoff is a contract boundary.
## Failure points
The two most important failure points are inventory and payment. If [[command|reserve-inventory]] or [[command|authorize-payment]] fails, checkout must compensate and avoid creating an order.
Review the Acme place-an-order flow and identify the operational impact of a checkout change. Focus on cart checkout,
inventory reservation, payment authorization, order creation, fulfilment handoff, compensation behavior and teams that
need to review the change. Return a concise impact checklist with risks and required catalog updates.
Use [[flow|checkout-saga]] for the detailed orchestration view.
---
title: Checkout saga
summary: The orchestration pattern used by checkout to coordinate inventory reservation, payment authorization and order creation.
owners:
- ordering-platform
badges:
- content: Flow
backgroundColor: orange
textColor: orange
---
[[flow|checkout-saga]] is the detailed orchestration inside [[system|checkout-system]]. It exists because checkout cannot be a single local transaction: inventory, payment and order state are owned by different systems.
## Flow map
## Saga steps
| Step | Contract | Owner |
|------|----------|-------|
| Reserve inventory | [[command\|reserve-inventory]] | [[system\|inventory-system]] |
| Authorize payment | [[command\|authorize-payment]] | [[system\|payment-processing-system]] |
| Create order | [[command\|create-order]] | [[system\|order-management-system]] |
## Success condition
Checkout succeeds only when inventory is reserved, payment is authorized and an order is created. The durable outcome is an order in [[container|order-database]] and subsequent [[event|order-created]] publication.
## Compensation
If inventory is unavailable or payment is declined, checkout should not create an order. The orchestrator should release any previous reservation or void any authorization as needed.
## Change guidance
Adding a checkout step means updating:
- the flow definition,
- the orchestrator implementation,
- the command/event contracts,
- failure and compensation behavior,
- customer-facing status semantics.
Review this checkout saga change as a senior distributed systems engineer. Check whether every step has a clear owner,
success condition, failure condition, retry policy, compensation action and customer-visible status. Call out any
missing contracts or catalog pages that should be updated before release.
---
title: Product search indexing
summary: How product catalog changes are projected into the Search System for customer-facing search.
owners:
- search-platform
badges:
- content: Flow
backgroundColor: orange
textColor: orange
---
[[flow|product-search-indexing]] keeps product search aligned with catalog changes. It is intentionally asynchronous: product writes should not wait for search indexing to complete.
## Flow map
## Producers
[[system|product-catalog-system]] owns product data. Product changes are represented by:
- [[event|product-created]]
- [[event|product-updated]]
- [[event|product-deleted]]
These events are published by services inside the Product Catalog System, including [[service|product-search-publisher]].
## Consumers
[[system|search-system]] consumes product change events and updates [[container|search-index]]. [[service|search-api]] then serves [[query|search-products]] against that index.
## Consistency model
The product database is immediately authoritative. The search index is eventually consistent. User interfaces should tolerate a short delay between product update and search result update.
## Operational signals
Watch for indexing lag, failed event handling and search query errors. A stale search index affects product discovery even when product writes are healthy.
---
title: Review submission
summary: How product reviews are submitted, moderated, published and aggregated into ratings.
owners:
- reviews-platform
badges:
- content: Flow
backgroundColor: orange
textColor: orange
---
[[flow|review-submission]] captures the lifecycle of customer product feedback.
## Flow map
## Flow stages
1. A customer submits a review through [[service|review-api]] using [[command|submit-review]].
2. [[service|review-api]] stores the review in [[container|review-database]] and publishes [[event|review-submitted]].
3. [[service|review-moderation-worker]] evaluates the review.
4. The worker publishes [[event|review-published]] or [[event|review-rejected]].
5. [[service|rating-aggregator]] consumes published reviews and updates [[container|rating-cache]].
6. [[service|review-api]] serves [[query|get-product-reviews]] for storefront reads.
## Moderation boundary
Moderation is asynchronous so submission remains responsive and moderation rules can evolve independently.
## Rating boundary
Ratings are a read model. [[container|rating-cache]] is optimised for product pages, while [[container|review-database]] remains the durable review store.
## Follow-up interactions
After publication, customers can use [[command|vote-review-helpful]] or [[command|flag-review]]. These interactions publish [[event|review-helpful-voted]] and [[event|review-flagged]].
---
title: Team ownership
summary: Which platform teams own the major Acme Inc domains and systems documented in the default catalog.
owners:
- dboyne
badges:
- content: Operations
backgroundColor: gray
textColor: gray
---
Ownership in the default catalog is modelled with team resources. The owning team is responsible for contract changes, service reliability and documentation freshness for its resources.
## Teams by capability
| Team | Owns |
|------|------|
| [[team\|product-platform]] | [[domain\|catalog]], [[system\|product-catalog-system]] and product APIs/workers. |
| [[team\|search-platform]] | [[system\|search-system]], search indexing and search query contracts. |
| [[team\|shopping-platform]] | [[domain\|shopping]], [[system\|cart-system]] and [[system\|promotion-system]]. |
| [[team\|ordering-platform]] | [[domain\|ordering]], [[system\|checkout-system]] and [[system\|order-management-system]]. |
| [[team\|payments-platform]] | [[domain\|payments]] and [[system\|payment-processing-system]]. |
| [[team\|fulfilment-platform]] | [[domain\|fulfilment]], inventory, warehouse and shipping systems. |
| [[team\|customer-platform]] | [[domain\|customer]], customer profile and identity systems. |
| [[team\|reviews-platform]] | [[domain\|reviews]], review moderation and rating aggregation. |
## Ownership rules
The owner listed on the producing resource owns the contract. Consumers can request changes, but producers decide versioning and rollout.
When a flow spans multiple teams, the team owning the orchestrator is responsible for keeping the flow page current. For checkout, that is [[team|ordering-platform]].
## Documentation expectations
Every resource page should explain responsibility, owners and major contracts. These custom docs should explain cross-resource narratives that do not belong to one resource.
---
title: Change management
summary: How to safely change contracts, schemas, systems and cross-domain flows in the Acme Inc catalog.
owners:
- dboyne
badges:
- content: Operations
backgroundColor: gray
textColor: gray
---
Changes should start with ownership and blast radius. A small service implementation change may not affect the catalog. A schema or flow change usually does.
## Contract changes
Before changing a command, event or query:
1. Identify the producer and all consumers.
2. Check whether the change is backward compatible.
3. Update the schema and resource summary.
4. Update affected flow pages.
5. Coordinate rollout with consumer owners.
High-risk contracts include [[event|cart-checked-out]], [[command|reserve-inventory]], [[command|authorize-payment]], [[command|create-order]], [[event|order-created]] and [[event|review-published]].
## System changes
When a system adds a service or data store, update the system page and any domain page that lists that system. If the change alters ownership of data, update the data ownership page too.
## Flow changes
For flows such as [[flow|place-an-order]], [[flow|checkout-saga]], [[flow|product-search-indexing]] and [[flow|review-submission]], update the diagram and the narrative together. A diagram without the operating rules is not enough for on-call or onboarding.
## Decision records
Use ADRs when a decision changes a long-lived pattern. The Product Catalog System already documents key decisions such as [[adr|adr-001-use-transactional-outbox]], [[adr|adr-002-postgres-as-system-of-record]] and [[adr|adr-003-offload-async-work-to-worker]].
---
title: Governance model
summary: The operating model Acme teams use to keep domain ownership, catalog quality and cross-team decisions clear.
owners:
- platform-governance
badges:
- content: Standard
backgroundColor: gray
textColor: gray
---
Governance at Acme is lightweight but explicit. Teams own the catalog entries for their domains, systems, services, messages and flows, while the Platform Governance group maintains the standards that keep those entries consistent.
## Ownership rules
Every production resource must have:
- a clear owning team,
- a business capability or system boundary,
- documented upstream and downstream dependencies,
- a current version where the resource has versioned contracts,
- enough context for another team to assess impact without asking in chat first.
Domain teams own business meaning. Platform teams own shared tooling and catalog hygiene. Integration decisions are shared when a change crosses domain boundaries.
## Governance forums
| Forum | Cadence | Purpose |
|-------|---------|---------|
| Architecture review | Weekly | Review cross-domain changes, new systems and integration risks. |
| Contract review | On demand | Review breaking command, query and event changes before implementation. |
| Operations review | Weekly | Review incidents, SLO misses and catalog gaps found during support. |
| Catalog health review | Monthly | Remove stale resources and improve ownership metadata. |
## Decision records
Use ADRs when the decision changes a system boundary, persistence model, integration pattern or team operating model. The Catalog domain shows the expected level of detail with [[adr|adr-001-use-transactional-outbox]], [[adr|adr-002-postgres-as-system-of-record]] and [[adr|adr-003-offload-async-work-to-worker]].
Review this catalog area for governance gaps. Check for missing owners, unclear domain boundaries, undocumented
dependencies, stale decision records, unreviewed cross-domain contracts and missing operational notes. Return the gaps as
a prioritized checklist with suggested updates to EventCatalog pages.
## Escalation path
If two teams disagree on a contract or boundary, the owning domain proposes the default path, affected consuming teams document the impact, and the architecture review makes the final call.
---
title: Contract standards
summary: The rules Acme teams follow when defining, versioning and changing commands, events and queries.
owners:
- platform-governance
badges:
- content: Standard
backgroundColor: orange
textColor: orange
---
Commands, events and queries are the public language between Acme systems. A contract is not ready until it is understandable by a team that does not own the implementation.
## Contract types
| Type | Meaning | Example |
|------|---------|---------|
| Command | A request for an owner to do work. | [[command\|reserve-inventory]], [[command\|authorize-payment]], [[command\|create-order]] |
| Event | A fact that already happened. | [[event\|order-created]], [[event\|payment-succeeded]], [[event\|inventory-reserved]] |
| Query | A read contract owned by one capability. | [[query\|get-order]], [[query\|search-products]], [[query\|get-product-reviews]] |
## Required fields
Every contract page should document:
- business purpose,
- producer or handler,
- consumers where known,
- schema or payload reference,
- version and compatibility policy,
- failure semantics for commands and queries,
- replay and ordering assumptions for events.
## Versioning rules
Additive fields are allowed when consumers can ignore them. Removing fields, changing meaning, tightening validation or changing delivery semantics is breaking and requires a new version or a migration plan.
Use deprecation before removal. Keep the old contract documented until all consumers have moved.
## Review checklist
Before changing a contract, teams must identify all known consumers, confirm whether the change is additive or breaking, update flow pages that depend on the contract, and add an ADR when the change introduces a new integration pattern.
Review a proposed command, event or query contract change for Acme Inc. Decide whether it is additive or breaking, list
known consumer risks, identify missing schema or payload details, and suggest a migration plan if the change is not
backward compatible. Include the catalog pages that need updates.
---
title: Event design standards
summary: How Acme teams name, publish, consume and operate business events across the commerce platform.
owners:
- platform-governance
badges:
- content: Standard
backgroundColor: blue
textColor: blue
---
Events represent business facts, not instructions. The publishing team owns the meaning of the event and the state transition that produced it.
## Naming
Event names should be past tense and business-readable:
- [[event|cart-checked-out]]
- [[event|order-created]]
- [[event|payment-succeeded]]
- [[event|review-published]]
Avoid names that describe infrastructure actions, implementation classes or subscriber intent.
## Publishing
Publish events from the system that owns the state change. For product changes, [[system|product-catalog-system]] publishes product events because [[container|product-database]] is authoritative. For order lifecycle changes, [[system|order-management-system]] publishes order events because [[container|order-database]] is authoritative.
Use an outbox or equivalent durable handoff for events that represent committed business state.
## Consumption
Consumers must be idempotent. Delivery can be retried, delayed or observed out of order across independent streams. Consumers should store processed event identifiers when duplicate handling would otherwise create side effects.
## Event payloads
Payloads should carry enough information for consumers to decide whether they care, but not a full copy of another domain's private data model. Include stable identifiers, timestamps and business status fields. Keep sensitive customer and payment data out of broad event payloads.
Review this event design against Acme's event standards. Check that the event name is a past-tense business fact, the
publisher owns the state change, the payload avoids private data models, consumers can process it idempotently, and the
related flow documentation is updated. Return specific recommendations.
## Flow impact
When an event is added to a critical journey, update the related flow page. Checkout-related event changes should be reflected in [[flow|place-an-order]] or [[flow|checkout-saga]].
---
title: Operational readiness
summary: The launch and support standards Acme applies before a system or contract is considered production-ready.
owners:
- platform-governance
badges:
- content: Standard
backgroundColor: green
textColor: green
---
A system is production-ready when another team can understand ownership, dependencies and failure behavior from the catalog before an incident starts.
## Required catalog coverage
Before production launch, each system must document:
- owning team and escalation path,
- services and containers,
- commands, queries and events,
- critical flows that include the system,
- external dependencies,
- operational dashboards or runbooks where available,
- known failure modes and recovery expectations.
## Critical system map
Checkout is the reference standard for operational coverage because it crosses Shopping, Ordering, Payments and Fulfilment.
## Launch gates
| Gate | Required evidence |
|------|-------------------|
| Ownership | Team and escalation path are present in the catalog. |
| Contracts | Public commands, events and queries have schemas or payload notes. |
| Observability | Error, latency and throughput signals exist for customer-facing paths. |
| Recovery | Retry, compensation or manual recovery behavior is documented. |
| Dependencies | Upstream and downstream systems are linked in the catalog. |
Review this system for production readiness at Acme Inc. Check ownership, escalation, contracts, observability,
dependency mapping, failure modes, recovery behavior and customer impact. Return launch blockers, follow-up tasks and
catalog pages that should be updated before release.
## Incident updates
After an incident, update the catalog when the incident reveals a missing dependency, stale owner, unclear contract, undocumented failure mode or misleading flow.
---
title: Review and change workflow
summary: The standard workflow Acme teams use to make catalog-backed architecture and integration changes.
owners:
- platform-governance
badges:
- content: Standard
backgroundColor: purple
textColor: purple
---
Catalog updates should land with the system change they describe. The catalog is part of the delivery artifact, not an after-the-fact diagram store.
## Change categories
| Change | Required review |
|--------|-----------------|
| Local service implementation only | Owning team review. |
| New command, event or query | Owning team plus known consumers. |
| Breaking contract change | Contract review and migration plan. |
| New system or external dependency | Architecture review. |
| Critical flow behavior change | Owning teams for every domain in the flow. |
## Standard workflow
Update the affected domain, system or flow page with the business reason for the change.
Add or revise command, event and query pages before consumers integrate with them.
Check system maps and flow pages for upstream and downstream dependencies.
Add an ADR when the change affects ownership, persistence, integration style or operational recovery.
After release, confirm the catalog matches the deployed behavior and remove stale notes.
Create a review checklist for a proposed Acme architecture change. Include affected domains, systems, services,
commands, events, queries, flows, owners, operational risks, decision records and release follow-up. Keep the output
practical enough to paste into a pull request description.
## Flow review
For checkout changes, review both the customer journey and the internal saga before implementation.
---
title: Architecture overview
summary: How Acme Inc's commerce platform is organised across domains, systems, services, messages, data stores and teams.
owners:
- dboyne
badges:
- content: Overview
backgroundColor: blue
textColor: blue
---
Acme Inc runs a commerce platform that takes a customer from product discovery through cart, checkout, payment, fulfilment, delivery and post-purchase feedback. The catalog is organised around business capabilities rather than deployment topology.
The main business domains are [[domain|catalog]], [[domain|shopping]], [[domain|ordering]], [[domain|payments]], [[domain|fulfilment]], [[domain|customer]] and [[domain|reviews]]. Each domain owns the services, messages and data stores that support its business language.
## Core checkout map
The checkout capability is the best compact view of how Acme's platform is connected. It shows the orchestration boundary between cart checkout, inventory reservation, payment authorization and durable order creation.
## Platform shape
| Area | Primary capability | Core systems |
|------|--------------------|--------------|
| [[domain\|catalog]] | Product data and search | [[system\|product-catalog-system]], [[system\|search-system]] |
| [[domain\|shopping]] | Cart and promotions | [[system\|cart-system]], [[system\|promotion-system]] |
| [[domain\|ordering]] | Checkout and order lifecycle | [[system\|checkout-system]], [[system\|order-management-system]] |
| [[domain\|payments]] | Payment authorization, capture and refunds | [[system\|payment-processing-system]], [[system\|stripe]], [[system\|fraud-detection]] |
| [[domain\|fulfilment]] | Stock, warehouse and shipment | [[system\|inventory-system]], [[system\|warehouse-system]], [[system\|shipping-system]], [[system\|carrier]] |
| [[domain\|customer]] | Customer profile and authentication | [[system\|customer-management-system]], [[system\|identity-provider]] |
| [[domain\|reviews]] | Product feedback and ratings | [[service\|review-api]], [[service\|review-moderation-worker]], [[service\|rating-aggregator]] |
## Architectural style
The platform is event-driven where state changes matter to another capability. Commands are used to request work from an owning capability, queries are used for explicit read access, and events announce facts that have already happened.
The most important chain is the order journey:
1. [[service|cart-api]] publishes [[event|cart-checked-out]].
2. [[service|checkout-orchestrator]] coordinates [[command|reserve-inventory]], [[command|authorize-payment]] and [[command|create-order]].
3. [[service|order-service]] publishes [[event|order-created]] and [[event|order-completed]].
4. [[service|warehouse-service]] reacts to completed orders and publishes [[event|order-ready-for-shipping]].
5. Shipment and carrier events track delivery progress.
## Reading the catalog
Use resource pages when you need the authoritative contract for a single component. Use these custom docs when you need the operating narrative: why a capability exists, how systems collaborate, and where ownership boundaries sit.
Start with the domain pages when orienting around business capability. Start with flow pages when diagnosing an end-to-end customer journey.
---
title: Domain map
summary: The bounded contexts in the Acme Inc catalog and how their responsibilities connect across the commerce journey.
owners:
- dboyne
badges:
- content: Architecture
backgroundColor: purple
textColor: purple
---
The domain map shows where business language changes. A cart, an order, a payment and a shipment are different concepts with different owners, lifecycles and consistency rules.
## Core domains
[[domain|shopping]], [[domain|ordering]], [[domain|payments]] and [[domain|fulfilment]] form the core purchase path. A failure in any of these domains can block revenue or customer delivery, so their contracts should be reviewed together when changing checkout behavior.
| Domain | Owns | Publishes or handles |
|--------|------|----------------------|
| [[domain\|shopping]] | Cart contents, checkout intent and discounts | [[command\|checkout-cart]], [[event\|cart-checked-out]], [[command\|calculate-discount]] |
| [[domain\|ordering]] | Checkout orchestration and order state | [[command\|reserve-inventory]], [[command\|authorize-payment]], [[command\|create-order]], [[event\|order-created]] |
| [[domain\|payments]] | Payment intent, payment outcome and refunds | [[event\|payment-requested]], [[event\|payment-succeeded]], [[event\|payment-failed]], [[event\|refund-requested]] |
| [[domain\|fulfilment]] | Stock reservation, warehouse packing and shipping | [[event\|inventory-reserved]], [[event\|order-ready-for-shipping]], [[command\|create-shipment]] |
## Supporting domains
[[domain|catalog]], [[domain|customer]] and [[domain|reviews]] support the buying experience. They are still product-critical, but their change cadence and runtime failure modes are different from checkout orchestration.
Catalog and Search keep product data discoverable. Customer and Identity keep profiles and authentication separate from order state. Reviews and Ratings feed product trust signals back into the storefront.
## Integration boundaries
External systems are modelled explicitly so ownership and failure handling are visible. [[system|stripe]], [[system|fraud-detection]] and [[system|carrier]] are outside Acme's control. Internal services should treat these integrations as unreliable boundaries and persist enough state to retry safely.
## Change guidance
When a change crosses a domain boundary, update both sides of the contract. For example, changing checkout payloads requires reviewing [[event|cart-checked-out]], the [[flow|checkout-saga]], and any commands sent by [[service|checkout-orchestrator]].
---
title: Systems map
summary: The system-level view of Acme Inc's commerce platform and the responsibilities of each major system.
owners:
- dboyne
badges:
- content: Systems
backgroundColor: gray
textColor: gray
---
Systems group services and data stores around a stable business capability. They are the best unit for understanding runtime ownership, operational dashboards and integration boundaries.
## Checkout and payment maps
The checkout and payment systems are the highest-coupling parts of the platform. Use these maps when assessing checkout changes, payment incident impact or ownership questions across Ordering and Payments.
## Internal systems
| System | Domain | Role |
|--------|--------|------|
| [[system\|product-catalog-system]] | [[domain\|catalog]] | Source of truth for product data and product change events. |
| [[system\|search-system]] | [[domain\|catalog]] | Maintains a search index and serves product search queries. |
| [[system\|cart-system]] | [[domain\|shopping]] | Owns carts and emits checkout intent. |
| [[system\|promotion-system]] | [[domain\|shopping]] | Calculates discounts for carts. |
| [[system\|checkout-system]] | [[domain\|ordering]] | Coordinates checkout as a saga. |
| [[system\|order-management-system]] | [[domain\|ordering]] | Owns order state and order lifecycle events. |
| [[system\|payment-processing-system]] | [[domain\|payments]] | Records payment intent and drives payment/refund processing. |
| [[system\|inventory-system]] | [[domain\|fulfilment]] | Owns stock and reservations. |
| [[system\|warehouse-system]] | [[domain\|fulfilment]] | Picks and packs completed orders. |
| [[system\|shipping-system]] | [[domain\|fulfilment]] | Creates shipments and tracks delivery handoff. |
| [[system\|customer-management-system]] | [[domain\|customer]] | Owns customer profile data. |
| [[system\|identity-provider]] | [[domain\|customer]] | Authenticates customers and manages user credentials. |
## External systems
The catalog also documents external dependencies:
- [[system|stripe]] processes charges and refunds.
- [[system|fraud-detection]] screens payments.
- [[system|carrier]] creates and tracks shipments.
## Why systems matter
Services can change implementation technology, but system responsibilities should stay stable. For example, [[service|payment-api]] and [[service|payment-worker]] can evolve independently, but both remain inside [[system|payment-processing-system]] and share the same payment data ownership boundary.
Use system pages for impact analysis when a change affects multiple services or a shared data store.
---
title: Data ownership
summary: The source-of-truth data stores in the default catalog and the rules for reading and writing business state.
owners:
- dboyne
badges:
- content: Data
backgroundColor: green
textColor: green
---
Every durable business concept has an owning system and a source-of-truth store. Other systems should depend on published contracts instead of reaching into another system's data store.
## Source-of-truth stores
| Data store | Owner | Business data |
|------------|-------|---------------|
| [[container\|product-database]] | [[system\|product-catalog-system]] | Products, product attributes and catalog change outbox. |
| [[container\|search-index]] | [[system\|search-system]] | Search-optimised product documents. |
| [[container\|cart-database]] | [[system\|cart-system]] | Active shopping carts and checkout state. |
| [[container\|promotion-database]] | [[system\|promotion-system]] | Promotion rules and discount configuration. |
| [[container\|order-database]] | [[system\|order-management-system]] | Orders and order lifecycle state. |
| [[container\|payment-database]] | [[system\|payment-processing-system]] | Payment intents, charge outcomes and refunds. |
| [[container\|inventory-database]] | [[system\|inventory-system]] | Stock levels and reservations. |
| [[container\|warehouse-database]] | [[system\|warehouse-system]] | Picking and packing work. |
| [[container\|customer-database]] | [[system\|customer-management-system]] | Customer profiles. |
| [[container\|review-database]] | [[domain\|reviews]] | Reviews and moderation state. |
| [[container\|rating-cache]] | [[domain\|reviews]] | Product rating read model. |
## Read model pattern
[[system|search-system]] and [[container|rating-cache]] are read models. They do not own the original facts. They rebuild their state from events such as [[event|product-created]], [[event|product-updated]], [[event|review-published]] and [[event|rating-updated]].
## Write rule
Only the owning system writes its source-of-truth store. Cross-system updates should be commands or events. For example, checkout asks fulfilment to reserve stock with [[command|reserve-inventory]] rather than writing [[container|inventory-database]] directly.
## Consistency rule
User-facing flows should make the consistency model explicit. Checkout needs coordinated confirmation across inventory, payment and order creation, so it uses the [[flow|checkout-saga]]. Search indexing can lag product writes, so it uses asynchronous product events.
---
title: Eventing model
summary: How commands, events and queries are used across Acme Inc's event-driven commerce platform.
owners:
- dboyne
badges:
- content: Contracts
backgroundColor: orange
textColor: orange
---
The catalog separates messages by intent.
- **Commands** ask another capability to do something.
- **Events** announce that something has already happened.
- **Queries** request information without changing state.
## Commands
Commands are named in the imperative and should have one clear handler. Examples:
- [[command|checkout-cart]] asks [[service|cart-api]] to check out a cart.
- [[command|reserve-inventory]] asks [[service|inventory-service]] to hold stock.
- [[command|authorize-payment]] asks [[service|payment-api]] to authorize payment.
- [[command|create-order]] asks [[service|order-service]] to create an order.
- [[command|submit-review]] asks [[service|review-api]] to accept a product review.
## Events
Events are facts and should be safe for multiple consumers. Examples:
- [[event|cart-checked-out]] starts the checkout process.
- [[event|order-created]] signals that an order exists.
- [[event|payment-succeeded]] and [[event|payment-failed]] report external processor outcomes.
- [[event|order-ready-for-shipping]] hands fulfilment to shipping.
- [[event|review-published]] updates review read models and product trust signals.
## Queries
Queries are explicit read contracts. Examples include [[query|get-product]], [[query|search-products]], [[query|get-order]], [[query|get-customer]], [[query|get-stock-level]] and [[query|get-product-reviews]].
## Versioning expectations
Backward-compatible additions are preferred. Removing fields or changing semantics requires a versioned contract and a migration plan. For customer-critical flows, review the flow page and all participating messages before changing a schema.
## Failure expectations
Consumers should be idempotent. Producers should publish facts after durable state changes. Long-running processes should persist their progress, especially [[flow|checkout-saga]], payment processing, search indexing and review moderation.