Skip to content

Orders Domain

The orders domain provides order lifecycle management for TypeScript backends. It handles order placement, state machine transitions (pending, confirmed, processing, shipped, delivered, canceled, refunded), address management, and price totals.

Terminal window
npx @backcap/cli add orders

The Order entity is the aggregate root. All state transitions go through Order methods — confirm(), process(), ship(), deliver(), cancel().

import { Order } from "./domains/orders/domain/entities/order.entity";
import { OrderItem } from "./domains/orders/domain/entities/order-item.entity";
import { Address } from "./domains/orders/domain/value-objects/address.vo";
const address = Address.create({
street: "123 Main St",
city: "Paris",
country: "France",
postalCode: "75001",
}).unwrap();
const item = OrderItem.create({
id: crypto.randomUUID(),
productId: "prod-123",
quantity: 2,
unitPriceCents: 1999,
}).unwrap();
const result = Order.create({
id: crypto.randomUUID(),
items: [item],
shippingAddress: address,
billingAddress: address,
});
if (result.isOk()) {
const order = result.unwrap();
console.log(order.status.value); // "pending"
console.log(order.totalCents); // 3998
console.log(order.itemCount); // 1
}
FieldTypeDescription
idstringUnique identifier (UUID)
itemsreadonly OrderItem[]Order line items
statusOrderStatusCurrent order status
shippingAddressAddressShipping address
billingAddressAddressBilling address
totalCentsnumberComputed sum of all line totals
itemCountnumberNumber of items

Orders follow a strict state machine enforced by a VALID_TRANSITIONS map:

  • pendingconfirmed via order.confirm()
  • pendingcanceled via order.cancel()
  • confirmedprocessing via order.process()
  • confirmedcanceled via order.cancel()
  • processingshipped via order.ship()
  • processingcanceled via order.cancel()
  • shippeddelivered via order.deliver()
  • deliveredrefunded (future)

Cancellation is only allowed from pending, confirmed, or processing — not from shipped or delivered.

const item = OrderItem.create({
id: crypto.randomUUID(),
productId: "prod-123",
quantity: 2,
unitPriceCents: 1999,
});
if (item.isOk()) {
console.log(item.unwrap().lineTotal); // 3998
}
VODescription
OrderStatusEnum with 7 states and valid transitions map
AddressStreet, city, country, postal code (all required, trimmed)
Use CaseDescription
PlaceOrderCreate a new order with items and addresses
ConfirmOrderTransition order to confirmed status
ShipOrderTransition order to shipped status (must be processing)
CancelOrderCancel order (only from pending/confirmed/processing)
GetOrderGet order with all details
ListOrdersList all orders
import { createOrderService } from "./domains/orders/contracts";
import type { IOrderService, OrderOutput } from "./domains/orders/contracts";
const orders: IOrderService = createOrderService({
orderRepository,
});
// Place an order
const result = await orders.placeOrder({
items: [{ productId: "prod-123", quantity: 2, unitPriceCents: 1999 }],
shippingAddress: { street: "123 Main", city: "Paris", country: "FR", postalCode: "75001" },
billingAddress: { street: "123 Main", city: "Paris", country: "FR", postalCode: "75001" },
});
// Lifecycle transitions
await orders.confirmOrder("order-id");
await orders.shipOrder("order-id");
await orders.cancelOrder("order-id");
// Query
const order = await orders.getOrder("order-id");
const all = await orders.listOrders();
PortDescription
IOrderRepositoryOrder persistence (findById, findAll, save, update)