# Porto SAP

Porto is an architectural pattern published by Mahmoud Zalt (MIT, ~1.6k★ on [github.com/Mahmoudz/Porto](https://github.com/Mahmoudz/Porto)) for organising server-side application code — primarily aimed at PHP/Laravel but framework-agnostic in principle. The framework that implements Porto for Laravel is **Apiato** ([apiato.io](https://apiato.io)); the Porto repo itself is the pattern spec and documentation, not a runtime.

The current README is a thin landing page — the real content lives in the [docs site](https://mahmoudz.github.io/Porto/). Two ideas carry the pattern.

## Two layers: Containers and Ship

Application code splits in half:

```
app/
├── Containers/
│   └── {Section}/
│       └── {Container}/
│           ├── Actions/
│           ├── Tasks/
│           ├── Models/
│           ├── Controllers/
│           ├── Requests/
│           ├── Routes/
│           ├── Transformers/
│           ├── Events/
│           ├── Listeners/
│           ├── Jobs/
│           ├── Commands/
│           ├── Migrations/
│           ├── Tests/
│           ├── Configs/
│           └── Exceptions/
└── Ship/
    ├── Parents/        # base classes (Controller, Model, Request, ...)
    ├── Providers/
    ├── Middleware/
    ├── Exceptions/
    └── Configs/
```

- **Containers** hold business logic for one bounded area (`User`, `Billing`, `Order`, ...). Sections group related Containers (`Authentication` section might hold `User`, `Login`, `Roles`).
- **Ship** holds everything cross-cutting: framework base classes Containers extend, global middleware, shared service providers, app-wide configs.

The stated payoff is a monolith-to-microservices migration path: a Container is meant to be self-contained enough that splitting it into its own service is mostly a build/deploy change, not a code rewrite. Whether real-world Porto codebases actually keep Containers that clean is another question — same gap that bites bounded-context-as-microservice in DDD literature.

## Actions and Tasks

Inside a Container, business logic is split into two component types:

- **Action** — orchestrates one use case (e.g. `RegisterUserAction`). It composes Tasks in a sequence and is what Controllers, Jobs, or Commands call into.
- **Task** — does one thing, has one public method `run()`, is reusable across Actions (e.g. `CreateUserTask`, `SendWelcomeEmailTask`, `AssignRoleTask`).
- **Sub-Action** — a named group of Tasks shared by multiple Actions, to avoid repeating Task sequences.

This is the same idea as use-case classes in [Clean Architecture](https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html) or interactors/services in DDD-flavoured codebases, with the rule tightened to one-class-one-method-one-job. Controllers stay thin: parse the request, call an Action, return the result.

## Everything-has-its-own-class

The pattern's most distinctive trait isn't the layers — it's the insistence that each conceptually distinct artifact lives in its own class in a predictable folder. Routes (web / api / cli) live in dedicated files; request validation in Form Request classes; response shaping in Transformers; cross-cutting concerns in Middleware; domain events in Events + Listeners; queue work in Jobs; CLI in Commands; data access in Repositories; persistent state in Models; DTOs for inter-Container data transfer; Exceptions per error condition.

The result is a wide-and-shallow tree: many small files, each named after what it does. Authors of conventional Laravel codebases sometimes object that this is over-engineering; Porto's counter is that the cost of one more file is small and the cost of finding "where does X happen" in a monolithic Controller is high. The pattern bets on tooling — IDE jump-to-symbol, search — being cheap and exhaustive class-splitting therefore being a structural win.

## The AI-friendliness pitch

The current README leads with this:

> Porto's strict adherence to the single responsibility principle enhances its compatibility with AI tools like GitHub Copilot, which thrive on clear, well-defined classes.

That argument lines up with [[clean-code-coding-agents]] (and its parent reasoning from Uncle Bob's *Clean Architecture*): LLM context windows are finite, and a codebase where each file does one named thing is cheaper to navigate per token than a codebase where you have to read a 600-line Controller to figure out what happens during `POST /users`. Porto's small-classes-in-predictable-folders shape is what an agent's grep-and-read loop wants: a file named `RegisterUserAction.php` in `app/Containers/Authentication/User/Actions/` tells the agent what it does and where to look for the next hop without opening the file.

This is the pattern's most defensible 2026-era selling point. The monolith-to-microservices claim is harder to verify (it's the kind of thing that's true on day one and degrades silently as Container boundaries leak), but the agent-friendliness claim is testable per-file: open a file, ask whether its name tells you what it does. Porto says yes by construction; conventional MVC says "maybe, depending on the developer."

## Lineage

Porto blends:

- **MVC** — keeps Models/Views/Controllers as Laravel uses them, but demotes Controllers to thin adapters.
- **DDD-lite** — Containers are bounded contexts in everything but name. Sections are a coarser grouping.
- **Clean Architecture** — Actions are use cases; Tasks are the granular operations under them.
- **Hexagonal / ports-and-adapters** — Ship/Container split echoes the "your domain core doesn't depend on infrastructure" rule, though Porto enforces it by folder convention rather than by dependency-rule lint.

What it doesn't take from DDD: aggregates, value objects, domain events as first-class invariants, ubiquitous language drilling. Porto is a structural pattern, not a modelling philosophy.

## When it's a fit

- Laravel apps that have grown past the default `app/Http/Controllers/` flat layout and need a place for cross-cutting features.
- Teams that want to enforce structure by convention instead of by review.
- Codebases worked on by coding agents alongside humans (see [[clean-code-coding-agents]]).

## When it isn't

- Small apps where the file overhead is real cost, not paid-back-later cost.
- Teams that haven't bought into one-class-one-job — Porto without that discipline degrades into Laravel-with-more-folders.
- Languages without Laravel-shaped lifecycle hooks (Providers, Middleware, Form Requests, Events) — the pattern transplants, but the implementation specifics don't.

## Where it sits in the wiki

- [[clean-code-coding-agents]] — the broader argument that structure matters more, not less, with agents in the loop.
- [[programming-as-theory-building]] — Naur's frame for why folder-convention enforcement is a weak proxy for the team's shared model, but the best one a pattern can offer.
- [[no-silver-bullet]] — Brooks on accidental vs essential complexity; Porto attacks accidental complexity (where does X go?) and leaves essential complexity (what should X do?) to the domain.
