Reverse Engineering your Software Architecture with Claude Code to help Claude Code

Coding agents can do more when they understand your system.

Reverse Engineering your Software Architecture with Claude Code to help Claude Code

I have been using Claude Code for a variety of purposes and one thing I realise is that the more it understands about the functionality of the system (the domain, the use cases, the end-to-end flows) the more it can help me.

For example, when I paste a production error log, Claude can read the stack trace, identify the affected code and tell me if there is a bug. But when the issue is more complex, like a customer support ticket, and there is no stacktrace, Claude is less useful.

The main challenge is that end-to-end processes are long and complex spanning many code repositories. So just asking Claude Code to analyse a single repository wasn’t going to work (and the default /init wasn’t producing sufficient detail even for this single codebase)

So I decided to use Claude Code to analyse the system, to map out the end-to-end flows relevant to the domain I work in, so that Claude Code(and humans) can use this to handle more complex challenges.

This post shares what I knocked together in one day, building on knowledge and tooling I’ve already gained from real work examples and experiments.

This is one post in a series. You can find the other posts here: https://medium.com/nick-tune-tech-strategy-blog/software-architecture-as-living-documentation-series-index-post-9f5ff1d3dc07

This post was written 100% by me. I asked Claude to generate the anonymized example at the end mirroring the type of content and style used in the real examples I created.

Setting the Initial Context

To begin my project, I created a very light requirements document:

# AI Architecture AnalysisThis document contains the instructions for an important task - using AI to define the architecture of this system, so that it can be used by humans and AI agents to more easily understand the system.## ObjectiveMap out all of the flows that this application is involved in (use sub agents where necessary to work in parallel). A flow should map out the end-to-process from an action in the UI (in the [readacted] repo) to a BFF, to backend APIs, or flows that are triggered by events.Flows should be documented in Mermaid format to allow AI agents to understand, for versioning (in git), and for easy visualization.## RequirementsEach flow should have a descriptive name and should include:1. The URL path of the page where the interaction is triggered2. The URL path of the BFF endpoint (and the repository it lives in)3. The URL path of calls made to downstream services4. Any database interactions5. Any events produced or consumed (full name of event e.g. orders.orderPlaced)6. Consumers of events (if easy to identify)7. Any workflows triggered (like the synchronizeOrder)To do this, you will need to look in other repositories which can be found in the parent folder. The github client can also be used if necessary.The list of flows should live in ../flows/index.md and each individual flow should be defined in a separate folder.# Where to find information- /docs/architecture contains various folders describing the design of this system and domain knowledge- Each API project in this repository ([redacted], [redacted]) has an openapi.json. This must be used to identify all flows and validate. The [redacted] and [redacted] repositories also have openapi spec files- The entities in the domain [redacted], [redacted] [redacted] have method that clearly describe the domain operations that can be performed on them. Equally, each operation is invoke from a use case that clearly describes the use case

The output I want is end-to-end flows like: UI -> BFF -> API -> update DB -> publish event -> handler -> us case -> publish event -> …

I don’t want 10 different kinds of architecture diagram and different levels of detail. I want Claude Code to understand behaviour of the system so he can identify anomalies (by looking at production data and logs) and analyze the impact of potential changes.

I also created some light information about the system in these 2 files:

The domain concepts file explains the entities in the system. Very brief explanation. The system overview file explains the relationship betwen this codebase and other repositories which is crucial. Again, it’s very light — a bullet list of repository names and one or two sentences describing their relationship to this one.Searching Across Multiple Repositories

The instructions for this task live inside the main repository of the domain I work in. This is the centre of the universe for this agent, but it needs to be able to read other repositories to join up the end to end flow.

The solution I use for this is in the description above:

To do this, you will need to look in other repositories which can be found in the parent folder. The github client can also be used if necessary.

I give Claude the following permissions in .claude/settings.local.json and it can then access all the repositories on machine or use the github client if it thinks there are repositories I don’t have available locally:

 "permissions": {    "allow": [      ...      "Read(//Users/nicktune/code/**)",      ...
```Telling Claude Where to Look

You’ll notice the requirements also give Claude tips on where to look for key information like Open API spec files which are like an index of the operations the application supports.

This is useful as a validation mechanism later in the flow. I would ask Claude “List all of the API endpoints and events produced or consumed by this application — are there any that aren’t part of any flows”. I can then see if we may have missed anything important.

### Mapping the First Flow

I put Claude in plan mode and asked it read the file. It then popped up a short questionnaire asking me about my needs and preferences. One of the questions it asked was process related: should we map out the whole system in parallel, work step-by-step etc.

I said, let’s do the first one together and use this as a template for the others to follow.

It took about 2 hours to build the first flow as I reviewed what Claude produced and gave feedback on what I needed. For example, at first it created a sequence diagram which looked nice, but was too hard to read for complex flows that involve many repositories.

Eventually, we settled on horizontal flow diagrams where each was repository is a container and we defined what steps could be. At first, it went too granular with the steps adding individual method calls.

```markdown
### diagram.mermaid Requirements**CRITICAL RULES:**1. **File Format**: Must be pure Mermaid syntax with `.mermaid` extension   - NO markdown headers   - NO markdown code fences (no ` ```mermaid ` wrapper)   - Starts directly with `flowchart LR`2. **Use Swimlane Format**: `flowchart LR` (left-to-right with horizontal swimlanes)   - Each repository is a horizontal swimlane (subgraph)   - Flow progresses left to right   - Swimlane labels should be prominent (use emoji for visibility)   - Example: `subgraph systemA["🔧 systemA"]`3. **Systems as Containers**:   - Each repository MUST be a `subgraph` (horizontal swimlane)   - Repository name is the subgraph label   - Operations are nodes inside the subgraph   - Use `direction LR` inside each subgraph4. **Valid Step Types** - A step in the diagram can ONLY be one of the following:   - **HTTP Endpoint**: Full endpoint path (e.g., `POST /blah/{blahId}/subblah`)   - **Aggregate Method Call**: Domain method on an aggregate (e.g., `Order.place`, `Shipping.organiz`)   - **Database Operation**: Shown with cylinder shape `[(Database: INSERT order)]`   - **Event Publication**: (e.g., `Publish: private.ordering.order.placed`)   - **Workflow Trigger**: Must be labeled as workflow (e.g., `⚙️ Workflow: syncOrders`)   - **Workflow Step**: Any step inside a workflow MUST include the workflow name as prefix (e.g., `syncOrderWorkflow: Update legacy order`, `updateOrderInfo: POST /legacy/fill-order`)   - **Lambda Invocation**: (e.g., `Lambda: blah-blah-lambda-blah-blah`)   - **UI Actions**: User interactions (e.g., `Show modal form`, `User enters firstName, lastName`)

I’ve added an anonymized flow at the end of this document.

I also had to add some corrections to Claude to ensure it was looking in all the right places and understanding what certain concepts mean in other parts of our system, we weren’t just iterating on the diagram for 2 hours.

Choosing the Next Flow

After the first flow the next flows went much faster. I verified the output of each flow and gave Claude feedback, but generally around 15 minutes, and most of the time it was working so I could do other things while waiting.

One of the interesting challenges was deciding which flows are actually needed? What is a flow? Where should a flow start and end? What about relationships between flows?

Here I was in the driving seat quite a bit. I asked Claude to propose flows (just list them before analyzing) and then I asked it to show me how each API endpoint and event fit into the flows, and we used that to iterate a bit.

One of the things I had to do after Claude had produced the first draft is to ask “are you sure there are no other consumers for these events that are not listed here”. It would then do a more thorough search and sometime find consumers in repositories I didn’t have locally (it would use github search).Learning Value

As I reviewed each use case I was learning things about the system that I didn’t fully understand or maybe there were nuances I wasn’t aware of. This alone would have justified all the effort I spent on this.

Then I started to imagine the value for people who are new to a codebase or a legacy system that nobody understands anymore. Or maybe someone who works in a different team and needs to figure out how a bug or a change in their domain is related to other domains.

Evolving the Requirements

As we went through the process, I regularly told Claude to update the requirements file. So after we’d finished the first flow we had instructions like this added to the file:

## Documentation StructureEach flow must be documented in a separate folder with the following structure:```docs/architecture/flows/[flow-name]/├── README.md              # Complete documentation (all content in one file)└── diagram.mermaid        # Mermaid diagram```**IMPORTANT**: Use ONLY these two files. Do NOT create separate diagram-notes.md or other files. Keep all documentation consolidated in README.md for easier maintenance.### README.md Contents**Use the blueprint as a template**: `docs/architecture/flows/[redacted]/`

The file is now 449 lines long.

One of the reasons I did this was so that I could start a new Claude session, now or in the future, without a completely clean context window and execute the process to get similar results.

I did actually use a new session to map each new flow to validate the requirements were somewhat repeatable. In general they were, but often Claude would ignore some parts of the requirements. So at the end, I told it to review the requirements and compare the outputs and it would usually identify most of the errors it had made and fix them.

Here’s an example of some of the rules that started to build up. Some rules were ensuring Claude produced the right type of output, and some were to help Claude avoiding common mistakes like mermaid syntax errors.

### 2. Trace Workflows to Their Final Event**Problem**: Missing events because you don't read the actual workflow implementation.**Rule**: When you encounter a workflow, you MUST:1. Find the workflow definition file (usually `.asl.json` for AWS Step Functions)2. Read the ENTIRE workflow to see ALL events it publishes3. Document EVERY event in sequence**Example from our blueprint**:- We initially thought `[readacted]` ended with `[readacted]`- Reading `[redacted].asl.json` revealed it actually ends with `[readacted]`- This event was CRITICAL to the flow continuing**File locations**:- Intgrations workflows: `[another-repo]/domains/*/workflows/*.asl.json`- Look for `SendEvent` or `publish` actions in the workflow steps

Claude Code never follows every instruction as described. But adding these rules does seem to increase the quality and reduces the number of iterations needed.

Testing the Output

After I mapped out 4 or 5 of the flows I decided it was time to test it out — does this information actually help Claude Code or is it mainly just a human audience that benefits from the outputs?

So I went into our support ticket system and picked a ticket that looked complex. I asked my investigation agent to look at the ticket and identify the problem. But this time I added an extra step into it’s instructions:

4. Identify the affected flows in /docs/architecture/flows

As part of it’s analysis, it said:

“Let me explore the architecture flows to understand how [redacted] and [redacted] should be handled:”

Then it produced it’s analysis correctly identifying the flow and expected behaviours :

## Affected Flow**[BlahA Upload and BlahB History Thing](../architecture/flows/[redacted]/README.md)**The [redacted] workflow should populate [redacted] data via:- [redacted] selection ([redacted] standard OR [redacted] enhanced based on `[redacted]` flag)- Parallel execution of: DomainA, DomainB, DomainC, DomainD- Publishing `order.blahBlahed` event on completion...

And for the next steps it wanted to query the events published by the system to verify that what actually happened matched the expected behaviours defined in the flow:

### Step 1: Query [redacted] Events for Both [redacted]**Objective:** Compare event history to identify what happened differently between old and new [redacted]**What to look for:**- `[redacted event name]` - Did [redacted] complete for new [redacted]?- `[redacted event name]` - Were [redacted] created?- `[redacted event name]` - Were [redacted] created?- `[redacted event name]` - Did workflow complete for new [redacted]?- `[redacted event name]` - Final confirmation event- Any error/failure events related to the workflow

Previously, Claude would have had to analyze the codebase to work out what should have happened. It takes a long time and takes up a lot of context window for complex tasks and the analysis has to be verified.

Now, Claude knows immediately about the specific workflow and affected behaviours and can immediately begin planning an investigation (if the documentation is accurate enough). This analysis is structured with the key information that I need to see. I don’t need to iterate with Claude to produce an analysis in the format I need.

In this case, Claude didn’t resolve the problem immediately, but the conversation was more like I might have with a team member — someone who has a deeper understanding of how the system works and what might be wrong here, rather than just using Claude to analyze patterns in data, read stacktraces or summarize text descriptions of the problem.

Accuracy and Hallucinations

I do think it’s right to be concerned about accuracy. We don’t want to make important choices about our system based on incomplete or incorrect details. And there have been significant inaccuracies that I had to spot and correct (imagine if I didn’t know they were wrong).

I explored the challenge of accuracy in this later post: https://nicktune.medium.com/extracting-your-software-architecture-with-ts-morph-73059771d2d6 showing how we can use determistic tools like ts-morph to build the model that humans and AI can both benefit from

So here’s what I’m thinking:

  1. Sometimes we don’t need perfect accuracy — as long as the agent picks the right path it can re-inspect certain details or dive deeper as needed
  2. We can build checks and steps in into our CI pipelines to update things
  3. Regularly destroy and regenerate the flows (once a quarter?)
  4. Build verification agents or swarms

When I spotted the error and asked a new agent to analyze the flow for inaccuracies, it re-scanned the code and found what I saw. So I think option 4 is very credible, it’s just more effort to build a verification system (which could make the overall effort not worth it).

But I’m not sure this is the optimal way of approaching the situation. Instead….

The Next Phase of Platform Engineering

Avoiding the need to reverse engineer these flows will be key. And I’m starting to think this will become the main challenge for platform engineering teams — how can we build frameworks and tooling that expose our system as a graph of dependencies? Built in to our platform so that AI agents don’t need to reverse engineer, they can just consult the source of truth.

Things should all happen transparently for software engineers — you follow the platform paved path, and everything just works. Companies that do this, and especially start ups with no legacy, could immensely profit from AI agents.

Tools like Event Catalog are in a strong position here.

Example Flow

I just asked Claude to translate one of my company’s domain flows into a boring ecommerce example. The design and naming is not important the type of information and the visualization is what I’m trying to convey.

Remember, this is based on one day of hacking around. I’m sure there are lots of improvement opportunities here. Let me know if you have seen anything better.The README:

# Place Order with Payment and Fulfillment**Status**: Active**Type**: Write Operation**Complexity**: High**Last Updated**: 2025-10-19## OverviewThis flow documents the process of placing an order in an ecommerce system, including payment authorization, inventory reservation, and shipment creation. This is the baseline order placement experience where:- Orders start with `status: 'pending'`- Payment is authorized before inventory reservation- Inventory is reserved upon successful payment- Shipment is created after inventory reservation## Flow Boundaries**Start**: Customer clicks "Place Order" button on checkout page**End**: Publication of `shipping.shipment-created` event (public event with `DOMAIN` scope)**Scope**: This flow covers the entire process from initial order submission through payment authorization, inventory reservation, shipment creation, and all asynchronous side effects triggered by these operations.## Quick Reference### API Endpoints| Endpoint | Method | Repository | Purpose ||----------|--------|------------|---------|| `/checkout` | GET | storefront-app | Checkout page || `/api/orders` | POST | order-api | Creates order || `/api/payments/authorize` | POST | payment-api | Authorizes payment || `/api/inventory/reserve` | POST | inventory-api | Reserves inventory || `/api/shipments` | POST | shipping-api | Creates shipment || `/api/orders/{orderId}/status` | GET | order-api | Frontend polls for order status |### Events Reference| Event Name | Domain | Subject | Purpose | Consumers ||------------|--------|---------|---------|-----------|| `private.orders.order.created` | ORDERS | order | Order creation | PaymentHandler, AnalyticsHandler || `private.payments.payment.authorized` | PAYMENTS | payment | Payment authorized | InventoryReservationHandler || `private.payments.payment.failed` | PAYMENTS | payment | Payment failed | OrderCancellationHandler || `private.inventory.stock.reserved` | INVENTORY | stock | Inventory reserved | ShipmentCreationHandler || `private.inventory.stock.insufficient` | INVENTORY | stock | Insufficient stock | OrderCancellationHandler || `private.shipping.shipment.created` | SHIPPING | shipment | Shipment created | NotificationHandler || `shipping.shipment-created` | SHIPPING | shipment | **PUBLIC** Shipment created | External consumers |### Database Tables| Table | Operation | Key Fields | Purpose ||-------|-----------|------------|---------|| `orders` | INSERT | orderId, customerId, status='pending', totalAmount | Order aggregate storage || `order_items` | INSERT | orderItemId, orderId, productId, quantity, price | Order line items || `payments` | INSERT | paymentId, orderId, amount, status='authorized' | Payment aggregate storage || `inventory_reservations` | INSERT | reservationId, orderId, productId, quantity | Inventory reservation tracking || `shipments` | INSERT | shipmentId, orderId, trackingNumber, status='pending' | Shipment aggregate storage |### Domain Operations| Aggregate | Method | Purpose ||-----------|--------|---------|| Order | `Order.create()` | Creates new order with pending status || Order | `Order.confirmPayment()` | Marks payment as confirmed || Order | `Order.cancel()` | Cancels order due to payment or inventory failure || Payment | `Payment.authorize()` | Authorizes payment for order || Payment | `Payment.capture()` | Captures authorized payment || Inventory | `Inventory.reserve()` | Reserves stock for order || Shipment | `Shipment.create()` | Creates shipment for order |## Key Characteristics| Aspect | Value ||--------|-------|| Order Status | Uses `status` field: `'pending'``'confirmed'``'shipped'` || Payment Status | Uses `status` field: `'pending'``'authorized'``'captured'` || Inventory Strategy | Reserve-on-payment approach || Shipment Status | Uses `status` field: `'pending'``'ready'``'shipped'` |## Flow Steps1. **Customer** navigates to checkout page in storefront-app (`/checkout`)2. **Customer** reviews order details and clicks "Place Order" button3. **storefront-app UI** shows loading state with order confirmation message4. **storefront-app** sends POST request to order-api (`/api/orders`)   - Request includes: customerId, items (productId, quantity, price), shippingAddress, billingAddress5. **order-api** creates Order aggregate with `status: 'pending'` and persists to database6. **order-api** creates OrderItem records for each item in the order7. **order-api** publishes `private.orders.order.created` event8. **order-api** returns orderId and order details to storefront-app9. **storefront-app** redirects customer to order confirmation page### Asynchronous Side Effects - Payment Processing10. **order-events-consumer** receives `private.orders.order.created` event11. **PaymentHandler** processes the event    - Calls payment-api to authorize payment12. **payment-api** calls external payment gateway (Stripe, PayPal, etc.)13. **payment-api** creates Payment aggregate with `status: 'authorized'` and persists to database14. **payment-api** publishes `private.payments.payment.authorized` event (on success)    - OR publishes `private.payments.payment.failed` event (on failure)### Asynchronous Side Effects - Inventory Reservation15. **payment-events-consumer** receives `private.payments.payment.authorized` event16. **InventoryReservationHandler** processes the event    - Calls inventory-api to reserve stock17. **inventory-api** loads Inventory aggregate for each product18. **inventory-api** calls `Inventory.reserve()` for each order item    - Validates sufficient stock available    - Creates reservation record    - Decrements available stock19. **inventory-api** creates InventoryReservation records and persists to database20. **inventory-api** publishes `private.inventory.stock.reserved` event (on success)    - OR publishes `private.inventory.stock.insufficient` event (on failure)### Asynchronous Side Effects - Shipment Creation21. **inventory-events-consumer** receives `private.inventory.stock.reserved` event22. **ShipmentCreationHandler** processes the event    - Calls shipping-api to create shipment23. **shipping-api** creates Shipment aggregate with `status: 'pending'` and persists to database24. **shipping-api** calls external shipping carrier API to generate tracking number25. **shipping-api** updates Shipment with trackingNumber26. **shipping-api** publishes `private.shipping.shipment.created` event27. **shipping-events-consumer** receives `private.shipping.shipment.created` event    - **ShipmentCreatedPublicHandler** processes the event    - Loads shipment from repository to get full shipment details    - Publishes public event: `shipping.shipment-created`    - **This marks the END of the flow**### Order Status Updates28. Throughout the flow, order-api receives events and updates order status:    - On `private.payments.payment.authorized`: Updates order with paymentId    - On `private.inventory.stock.reserved`: Updates order to `status: 'confirmed'`    - On `private.shipping.shipment.created`: Updates order to `status: 'shipped'`### Failure Scenarios**Payment Failure**:- On `private.payments.payment.failed`: OrderCancellationHandler cancels order- Order status updated to `'cancelled'`- Customer notified via email**Inventory Failure**:- On `private.inventory.stock.insufficient`: OrderCancellationHandler cancels order- Payment authorization is voided- Order status updated to `'cancelled'`- Customer notified via email with option to backorder## Repositories Involved- **storefront-app**: Frontend UI- **order-api**: Order domain- **payment-api**: Payment domain- **inventory-api**: Inventory domain- **shipping-api**: Shipping and fulfillment domain- **notification-api**: Customer notifications## Related Flows- **Process Refund**: Flow for handling order refunds and returns- **Update Shipment Status**: Flow for tracking shipment delivery status- **Inventory Reconciliation**: Flow for syncing inventory counts with warehouse systems## Events Produced| Event | Purpose ||-------|---------|| `private.orders.order.created` | Notifies that a new order has been created || `private.payments.payment.authorized` | Notifies that payment has been authorized || `private.payments.payment.failed` | Notifies that payment authorization failed || `private.inventory.stock.reserved` | Notifies that inventory has been reserved || `private.inventory.stock.insufficient` | Notifies that insufficient inventory is available || `private.shipping.shipment.created` | Internal event that shipment has been created || `shipping.shipment-created` | **Public event** that shipment is created and ready for carrier pickup |## Event Consumers### `private.orders.order.created` Consumers#### 1. order-events-consumer**Handler**: `PaymentHandler`**Purpose**: Initiates payment authorization process**Actions**:- Subscribes to event- Calls `AuthorizePayment` use case- Invokes payment-api to authorize payment with payment gateway- Publishes payment result event#### 2. order-events-consumer**Handler**: `AnalyticsHandler`**Purpose**: Tracks order creation for analytics**Actions**:- Subscribes to event- Sends order data to analytics platform- Updates conversion tracking### `private.payments.payment.authorized` Consumer#### payment-events-consumer**Handler**: `InventoryReservationHandler`**Purpose**: Reserves inventory after successful payment**Actions**:- Subscribes to event- Calls `ReserveInventory` use case- Loads order details- Calls inventory-api to reserve stock for each item- Publishes inventory reservation result event### `private.payments.payment.failed` Consumer#### payment-events-consumer**Handler**: `OrderCancellationHandler`**Purpose**: Cancels order when payment fails**Actions**:- Subscribes to event- Calls `CancelOrder` use case- Updates order status to 'cancelled'- Triggers customer notification### `private.inventory.stock.reserved` Consumer#### inventory-events-consumer**Handler**: `ShipmentCreationHandler`**Purpose**: Creates shipment after inventory reservation**Actions**:- Subscribes to event- Calls `CreateShipment` use case- Calls shipping-api to create shipment record- Integrates with shipping carrier API for tracking number- Publishes shipment created event### `private.inventory.stock.insufficient` Consumer#### inventory-events-consumer**Handler**: `OrderCancellationHandler`**Purpose**: Cancels order when inventory is insufficient**Actions**:- Subscribes to event- Calls `CancelOrder` use case- Voids payment authorization- Updates order status to 'cancelled'- Triggers customer notification with backorder option### `private.shipping.shipment.created` Consumer#### shipping-events-consumer**Handler**: `ShipmentCreatedPublicHandler`**Purpose**: Converts private shipment event to public event**Actions**:- Subscribes to `private.shipping.shipment.created` event- Loads shipment from repository- Publishes public event: `shipping.shipment-created`**Handler**: `NotificationHandler`**Purpose**: Notifies customer of shipment creation**Actions**:- Subscribes to event- Sends confirmation email with tracking number- Sends SMS notification (if opted in)## Database Operations### orders Table- **Operation**: INSERT (via upsert)- **Key Fields**: orderId, customerId, status='pending', totalAmount, createdAt- **Repository**: `OrderRepository`### order_items Table- **Operation**: INSERT (batch)- **Key Fields**: orderItemId, orderId, productId, quantity, price- **Repository**: `OrderItemRepository`### payments Table- **Operation**: INSERT (via upsert)- **Key Fields**: paymentId, orderId, amount, status='authorized', gatewayTransactionId- **Repository**: `PaymentRepository`### inventory_reservations Table- **Operation**: INSERT (via upsert)- **Key Fields**: reservationId, orderId, productId, quantity, reservedAt- **Repository**: `InventoryReservationRepository`### shipments Table- **Operation**: INSERT (via upsert)- **Key Fields**: shipmentId, orderId, trackingNumber, status='pending', carrier- **Repository**: `ShipmentRepository`## External Integrations- **Payment Gateway Integration**: Authorizes and captures payments via Stripe API  - Endpoint: `/v1/payment_intents`  - Synchronous call during payment authorization- **Shipping Carrier Integration**: Generates tracking numbers via carrier API  - Endpoint: `/api/v1/shipments`  - Synchronous call during shipment creation## What Happens After This FlowThis flow ends with the publication of the `shipping.shipment-created` public event, which marks the order as fully processed and ready for carrier pickup.### State at Flow Completion- Order: `status: 'shipped'`- Payment: `status: 'authorized'` (will be captured on actual shipment)- Inventory: Stock reserved and decremented- Shipment: `status: 'pending'`, trackingNumber assigned### Next StepsAfter this flow completes:- Warehouse team picks and packs the order- Carrier picks up the shipment- Shipping status updates flow tracks delivery- Payment is captured upon confirmed shipment- Customer can track order via tracking number### External System IntegrationOnce the `shipping.shipment-created` event is published:- Warehouse management system begins pick/pack process- Customer notification system sends tracking updates- Logistics partners receive shipment manifest- Analytics systems track fulfillment metrics## DiagramSee [diagram.mermaid](./diagram.mermaid) for the complete visual flow showing the progression through systems with horizontal swim lanes for each service.

The Mermaid:

flowchart LR    Start([Customer clicks Place Order<br/>on checkout page])    subgraph storefront["🌐 storefront-app"]        direction LR        ShowCheckout[Show checkout page]        CustomerReview[Customer reviews order]        ShowConfirmation[Show order<br/>confirmation page]    end    CustomerWaitsForShipment([Customer receives<br/>shipment notification])    subgraph orderService["📦 order-api"]        direction LR        CreateOrderEndpoint["POST /api/orders"]        OrderCreate[Order.create]        OrderDB[(Database:<br/>INSERT orders,<br/>order_items)]        PublishOrderCreated["Publish: private.orders<br/>.order.created"]        ReceivePaymentAuth["Receive: private.payments<br/>.payment.authorized"]        UpdateOrderPayment[Update order<br/>with paymentId]        ReceiveStockReserved["Receive: private.inventory<br/>.stock.reserved"]        OrderConfirm[Order.confirmPayment]        UpdateOrderConfirmed[(Database:<br/>UPDATE orders<br/>status='confirmed')]        ReceiveShipmentCreated["Receive: private.shipping<br/>.shipment.created"]        UpdateOrderShipped[(Database:<br/>UPDATE orders<br/>status='shipped')]    end    subgraph paymentService["💳 payment-api"]        direction LR        ReceiveOrderCreated["Receive: private.orders<br/>.order.created"]        AuthorizeEndpoint["POST /api/payments/<br/>authorize"]        PaymentGateway["External: Payment<br/>Gateway API<br/>(Stripe)"]        PaymentAuthorize[Payment.authorize]        PaymentDB[(Database:<br/>INSERT payments)]        PublishPaymentAuth["Publish: private.payments<br/>.payment.authorized"]    end    subgraph inventoryService["📊 inventory-api"]        direction LR        ReceivePaymentAuth2["Receive: private.payments<br/>.payment.authorized"]        ReserveEndpoint["POST /api/inventory/<br/>reserve"]        InventoryReserve[Inventory.reserve]        InventoryDB[(Database:<br/>INSERT inventory_reservations<br/>UPDATE product stock)]        PublishStockReserved["Publish: private.inventory<br/>.stock.reserved"]    end    subgraph shippingService["🚚 shipping-api"]        direction LR        ReceiveStockReserved2["Receive: private.inventory<br/>.stock.reserved"]        CreateShipmentEndpoint["POST /api/shipments"]        CarrierAPI["External: Shipping<br/>Carrier API<br/>(FedEx/UPS)"]        ShipmentCreate[Shipment.create]        ShipmentDB[(Database:<br/>INSERT shipments)]        PublishShipmentCreated["Publish: private.shipping<br/>.shipment.created"]        ReceiveShipmentCreatedPrivate["Receive: private.shipping<br/>.shipment.created"]        LoadShipment[Load shipment<br/>from repository]        PublishPublicEvent["Publish: shipping<br/>.shipment-created"]        FlowEnd([Flow End:<br/>Public event published])    end    Start --> ShowCheckout    ShowCheckout --> CustomerReview    CustomerReview --> CreateOrderEndpoint    CreateOrderEndpoint --> OrderCreate    OrderCreate --> OrderDB    OrderDB --> PublishOrderCreated    PublishOrderCreated --> ShowConfirmation    PublishOrderCreated -.-> ReceiveOrderCreated    ReceiveOrderCreated --> AuthorizeEndpoint    AuthorizeEndpoint --> PaymentGateway    PaymentGateway --> PaymentAuthorize    PaymentAuthorize --> PaymentDB    PaymentDB --> PublishPaymentAuth    PublishPaymentAuth -.-> ReceivePaymentAuth    ReceivePaymentAuth --> UpdateOrderPayment    PublishPaymentAuth -.-> ReceivePaymentAuth2    ReceivePaymentAuth2 --> ReserveEndpoint    ReserveEndpoint --> InventoryReserve    InventoryReserve --> InventoryDB    InventoryDB --> PublishStockReserved    PublishStockReserved -.-> ReceiveStockReserved    ReceiveStockReserved --> OrderConfirm    OrderConfirm --> UpdateOrderConfirmed    PublishStockReserved -.-> ReceiveStockReserved2    ReceiveStockReserved2 --> CreateShipmentEndpoint    CreateShipmentEndpoint --> CarrierAPI    CarrierAPI --> ShipmentCreate    ShipmentCreate --> ShipmentDB    ShipmentDB --> PublishShipmentCreated    PublishShipmentCreated -.-> ReceiveShipmentCreated    ReceiveShipmentCreated --> UpdateOrderShipped    PublishShipmentCreated -.-> ReceiveShipmentCreatedPrivate    ReceiveShipmentCreatedPrivate --> LoadShipment    LoadShipment --> PublishPublicEvent    PublishPublicEvent --> FlowEnd    FlowEnd -.-> CustomerWaitsForShipment    style Start fill:#e1f5e1    style FlowEnd fill:#ffe1e1    style CustomerWaitsForShipment fill:#e1f5e1    style PublishOrderCreated fill:#fff4e1    style PublishPaymentAuth fill:#fff4e1    style PublishStockReserved fill:#fff4e1    style PublishShipmentCreated fill:#fff4e1    style PublishPublicEvent fill:#fff4e1    style OrderDB fill:#e1f0ff    style PaymentDB fill:#e1f0ff    style InventoryDB fill:#e1f0ff    style ShipmentDB fill:#e1f0ff    style UpdateOrderConfirmed fill:#e1f0ff    style UpdateOrderShipped fill:#e1f0ff    style PaymentGateway fill:#ffe1f5    style CarrierAPI fill:#ffe1f5