One process, multiple domain boundaries. Consolidates the software: same transaction when needed, extraction to a service later once the module exists. Microservices: microservices-architecture. Contexts: ddd. Arrows: clean-architecture.
When (not) to use
Use with one team or a few teams, one pipeline, a domain that is still unstable, or frequent data coupling.
Do not use as an excuse for a global common folder. It is not a “messy monolith with namespaces”.
Module = context
apps/api/ # host (composição)
modules/
catalog/ # público: catalogapi
ordering/
billing/
shared/ # kernel mínimo (ids, clock) — não o domínio
- Each module: code + schema (prefixed tables or SQL schema) + tests.
- Dependency only via the module's public API (
orderingapi.PlaceOrder), never the neighbor'sinternal/ packagedb. - Cycles forbidden. If A needs B and B needs A: event, ACL, or the boundary is wrong (
ddd).
Data
- Writes: each module owns its tables. No cross-module FK (or FK only for what is a stable and deliberate contract).
- Reads from another context: the owner's API/query, materialized view, or eventual copy — not a silent
JOINin the global ORM. - Transaction cross-module in the same DB: documented exception (first step), not the default. Prefer eventual consistency —
event-driven-architecture.
Vertical slice
Inside the module, organize by feature, not by the app's global layer:
ordering/
placeorder/
handler.go | endpoint
service.go
sql.go
getorder/
...
- A slice can talk to the own module's domain. It does not import the
billing. - Clean Layers adapter inside the slice if the slice grows; do not force 4 projects per POST.
Host
- One
main: registers modules, middleware, config. - Authn in the host; authz in the module that owns the resource.
- Feature flags to hide an incomplete module — not
if module == nilscattered around.
Extraction
Signal to become a service: different deploy cycle, different scale, owning team, isolatable failure.
Checklist: public API is already stable, data is copyable, events already exist, contracts tested. Then microservices-architecture.
Anti-patterns
shared/domainwith all entities- One
AppDbContext/PrismaClientwith 80 models used by everyone - Modules by layer (
module-controllers,module-repos) - Microservice extracted in the first PR “to get it right from the start”
- Internal import “only in this file”
Integration with other skills
- Decision:
software-architecture - Contexts:
ddd - Dependencies:
clean-architecture - Events between modules:
event-driven-architecture - After the split:
microservices-architecture - Host HTTP:
api-design
Completion criteria
- Modules with a public API and owned data
- No import cycle
- Features in slice (or layers within the module)
- Imaginable extraction path without rewriting the domain
- Host only composition