Skip to content

Where would you put the boundary between the web app, API and worker?

1 min read · main part only; folded sections are optional

After this you can answer: Where would you put the boundary between the web app, API and worker?

Start with the invariant: a confirmed booking must have its seats deducted exactly once for that user intent. The API owns that transaction. Moving the seat decision into the browser or an asynchronous email handler would split the decision from its durable record.

The Next.js app can render pages and cache public event data. Feature hooks call the API; browser code does not import its runtime. The API validates input and checks the session before applying business rules. The worker consumes versioned messages containing the facts it needs, rather than querying Postgres for email content.

These are responsibility boundaries, not a demand for many independently deployed services. MiniTickets keeps one API with small layers. I would split further only when ownership, scaling or failure isolation justified the operational cost.

What happens when email is down?
The booking can commit. Its outbox event remains durable, and queue delivery or worker processing retries separately. A successful booking response does not prove an email reached an inbox.
Why not let the worker book the seats?
That would change the product contract into an asynchronous request for a booking. We would need pending, rejected and confirmed states, plus a way to tell the caller which outcome occurred.
How would you prove the boundary helps?
Test booking when publishing fails, and test workers with saved event payloads. In operations, compare booking success with outbox backlog, queue age and ticket readiness; one metric cannot describe all three outcomes.

Read Layers, then inspect the api-app piece →.

apps/api/src/services/bookings.ts → bookTicket

Read this book online: https://book.theversehub.in/