# Brewing a Reliable Coffee Subscription Platform

BeanRoute started with a simple promise: deliver freshly roasted coffee on each customer’s preferred schedule. The first version was a monolithic web application that handled checkout, subscription changes, and fulfillment exports. That worked for hundreds of subscribers, but growth exposed a recurring problem: billing events, address updates, and warehouse cutoffs could occur simultaneously, producing duplicate orders or shipments to outdated addresses.

## Designing Around Subscription Events

We moved fulfillment into an event-driven workflow. Stripe webhooks, customer updates, and scheduled renewal jobs publish normalized events to a queue. A fulfillment worker consumes those events and creates shipment records using the subscription period as an idempotency key. This lets us retry failed operations without creating extra bags of coffee or charging customers twice.

```yaml
fulfillment:
  cutoff_hour_utc: 14
  max_retries: 5
  idempotency_key: "{subscription_id}:{billing_period}"
```

## Handling Freshness and Inventory

Coffee inventory is different from typical retail stock because freshness matters as much as quantity. Instead of tracking only units on hand, we allocate inventory by roast batch and “ship by” date. The matching service selects a batch based on the subscriber’s roast preference, grind setting, and estimated carrier transit time, while reserving a small buffer for damaged packages and manual replacements.

## Observability in Production

We monitor the platform using business-level metrics alongside infrastructure telemetry. Queue latency tells us whether workers are falling behind, but the more useful alert is the percentage of paid renewals without a shipment after fifteen minutes. Structured logs include subscription, payment, and shipment identifiers, allowing support engineers to trace an order without searching across several dashboards.

## What We Learned

The most important architectural decision was treating each subscription renewal as a durable workflow rather than a single request. Payments, roasting, inventory allocation, and shipping all fail in different ways and recover on different timelines. Explicit state transitions and idempotent workers added complexity, but they gave BeanRoute predictable fulfillment during promotions and enough visibility to resolve problems before customers missed their morning coffee.