A business application usually starts small: a form, a list, an export. Two years later it handles approvals, roles, notifications and dozens of screens. What separates a project that stays pleasant to evolve from one nobody dares to touch is a handful of decisions made early.

Key takeaways

  • Thin controllers: they receive the request, delegate and return a response. Business logic lives elsewhere.
  • Action classes (ApproveRequest, GenerateInvoice): one class, one business operation, easy to test and reuse from a controller, a command or a scheduled job.
  • Validation in Form Requests, never copy-pasted between controllers.
  • Permissions in Policies: $this->authorize('approve', $request) reads like a sentence and keeps rules in one place.

States instead of booleans

An approval flow is poorly modelled with is_validated and is_rejected. A status column backed by a PHP enum (draft, pending, approved, rejected) makes transitions explicit and rules out impossible combinations.

Slow work goes to a queue

PDF generation, e-mails, Excel imports: anything slower than a second goes to a queue. Users keep a fast interface, and a failure can be retried without starting over.

Practical tip

Before adding a feature, write the business operation it represents in one sentence. If the sentence holds, it becomes an action class. If it doesn’t, the need isn’t clear enough to be coded yet.