Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/microservices-patterns/ftgo-application/llms.txt

Use this file to discover all available pages before exploring further.

The Order History Service is the FTGO application’s CQRS read-side view for order history. Rather than querying the Order Service’s write-side MySQL database, it consumes domain events from the Order Service and materializes a denormalized, consumer-queryable view in Amazon DynamoDB. This makes it possible to efficiently list all orders for a given consumer without putting load on the transactional order database. This page covers the service’s purpose, domain model, REST API, event subscriptions, and DynamoDB schema.

Responsibilities

  • Subscribe to OrderCreatedEvent, OrderAuthorized, OrderCancelled, and OrderRejected events from the Order Service
  • Maintain a DynamoDB-backed view of each order including consumer ID, status, restaurant info, line items, and order total
  • Support efficient per-consumer order history queries using DynamoDB’s partition key model
  • Provide a REST API for the API Gateway to retrieve a consumer’s order history or look up a single order
  • Track event source metadata (SourceEvent) to ensure idempotent event processing
The Order History Service is a read-only CQRS projection — it never writes to the Order Service’s database and does not expose any mutation endpoints. All state derives from domain events.

Domain Model

Order (DynamoDB projection)

The Order class represents a denormalized row in DynamoDB — not a JPA entity. It is populated from event payloads and stored in DynamoDB by OrderHistoryDaoDynamoDb.
FieldTypeSource
orderIdStringDomainEventEnvelope.getAggregateId()
consumerIdStringOrderCreatedEvent.orderDetails.consumerId
statusOrderStateUpdated on each state-change event
lineItemsList<OrderLineItem>OrderCreatedEvent.orderDetails.lineItems
orderTotalMoneyOrderCreatedEvent.orderDetails.orderTotal
restaurantIdlongOrderCreatedEvent.orderDetails.restaurantId
restaurantNameStringOrderCreatedEvent.restaurantName
creationDateDateTimeSet at projection time (Joda-Time DateTime.now())

OrderHistory

OrderHistory is a simple wrapper returned by OrderHistoryDao.findOrderHistory():
FieldTypeDescription
ordersList<Order>The matched orders for the consumer
startKeyOptional<String>DynamoDB pagination key for the next page of results

OrderHistoryDao

OrderHistoryDao is the data access interface with the following operations:
MethodDescription
addOrder(Order, Optional<SourceEvent>)Insert a new order projection; idempotent via SourceEvent check
findOrderHistory(consumerId, filter)Query orders for a consumer with optional filters
findOrder(orderId)Look up a single order by ID
updateOrderState(orderId, newState, eventSource)Update the order’s status field
noteTicketPreparationStarted(orderId)Mark that kitchen preparation has begun
noteTicketPreparationCompleted(orderId)Mark that the order is ready for pickup
notePickedUp(orderId, eventSource)Mark that the courier has collected the order
updateLocation(orderId, location)Update the courier’s current location for the delivery
noteDelivered(orderId)Mark the order as delivered
SourceEvent carries the source aggregate type, aggregate ID, and event ID. It is used by the DynamoDB implementation to prevent duplicate event processing via a conditional write expression.

REST API

The service listens on port 8086. All endpoints are under the /orders path.
MethodPathQuery paramsDescription
GET/ordersconsumerId (required)List all orders for the given consumer. Returns order ID, status, restaurant ID, and restaurant name for each.
GET/orders/{orderId}Retrieve a single order projection. Returns 404 if not found.

List orders response body

{
  "orders": [
    {
      "orderId": "1",
      "status": "APPROVED",
      "restaurantId": 2,
      "restaurantName": "Ajisen Ramen"
    }
  ],
  "startKey": null
}
The startKey field is populated when DynamoDB returns a pagination token. Pass it as a filter in the next request to retrieve subsequent pages.

Get order response body

{
  "orderId": "1",
  "status": "APPROVED",
  "restaurantId": 2,
  "restaurantName": "Ajisen Ramen"
}

Messaging

Events consumed

The service subscribes to the net.chrisrichardson.ftgo.orderservice.domain.Order aggregate channel via DomainEventHandlersBuilder:
EventHandlerEffect
OrderCreatedEventhandleOrderCreated()Calls orderHistoryDao.addOrder() with the full projection
OrderAuthorizedhandleOrderAuthorized()Calls updateOrderState(..., APPROVED, ...)
OrderCancelledhandleOrderCancelled()Calls updateOrderState(..., CANCELLED, ...)
OrderRejectedhandleOrderRejected()Calls updateOrderState(..., REJECTED, ...)
A DeliveryPickedUp handler exists in the source (handleDeliveryPickedUp) but is currently commented out, pending a common event abstraction.

Commands handled / published

The Order History Service does not handle saga commands and does not publish any domain events. It is purely a consumer.

Database

The Order History Service uses Amazon DynamoDB instead of MySQL. This is a deliberate architectural choice: DynamoDB’s partition-key model enables efficient per-consumer queries without requiring a full table scan.
DynamoDB attributeDescription
Partition keyconsumerId — enables fast findOrderHistory queries
Sort key / secondary indexorderId — enables findOrder single-item lookups
statusCurrent OrderState string
lineItemsSerialized list of order line items
orderTotalSerialized Money value
restaurantId / restaurantNameDenormalized from OrderCreatedEvent
creationDateISO-formatted timestamp
The SourceEvent metadata (aggregate type, aggregate ID, event ID) is stored alongside each item to support idempotent writes via DynamoDB conditional expressions.
When running the FTGO application locally with docker-compose, DynamoDB is emulated by the dynamodblocal container (port 8000). Tables are initialized automatically by the dynamodblocal-init container at startup.

Build docs developers (and LLMs) love