Testable product workflows outside controllers

Backend architecture

TL;DR
  • Controllers were not the right home for product workflows with real rules.
  • I needed workflows to be easier to name, test, and change outside the HTTP layer.
  • I moved billing, publishing, imports, search, and asset work into focused actions.
  • The result was thinner controllers and clearer ownership for behaviour that mattered.

Controllers are a poor home for product workflows once the workflow has real rules. They know too much about HTTP and not enough about the work itself.

Where it started

As workflows grew, controller methods risked becoming a mix of HTTP handling, domain coordination, and side effects.

What needed to change

Action classes give each workflow a focused place to live. Billing changes, publishing steps, imports, search indexing, and asset operations can each be tested without routing through a full controller.

What I built

Controllers receive requests and delegate to actions. Actions coordinate validation, domain objects, side effects, and return values.

The HTTP layer stays thin, and the product workflow becomes easier to name.

What changed

This makes behaviour easier to test and easier to change. It also helps engineers find the real owner of a workflow.

What I would watch

Actions need clear boundaries. If every helper becomes an action, the architecture becomes noisier without becoming clearer.