Basic Architecture of Sport Web
This commit is contained in:
@@ -0,0 +1,53 @@
|
||||
# Module anatomy
|
||||
|
||||
Every feature module follows the same internal shape. Consistency here is worth
|
||||
more than local cleverness — a developer opening `orders/` for the first time
|
||||
should already know where everything is.
|
||||
|
||||
```
|
||||
<module>/
|
||||
├── <module>.module.ts # Wiring only. No logic, ever.
|
||||
├── <module>.controller.ts # HTTP surface: parse, delegate, return. No rules.
|
||||
├── <module>.service.ts # Business rules. The only interesting file.
|
||||
├── <module>.repository.ts # The ONLY file allowed to touch PrismaService.
|
||||
├── dto/ # Request/response shapes + Zod schema bindings.
|
||||
├── mappers/ # Prisma row → API type. Keeps Prisma types internal.
|
||||
├── events/ # Events this module publishes and subscribes to.
|
||||
└── public/
|
||||
└── index.ts # The only entry point for other modules.
|
||||
```
|
||||
|
||||
## The four rules
|
||||
|
||||
1. **Controllers contain no business logic.** If a controller has an `if` that
|
||||
is not input shaping, the rule belongs in the service.
|
||||
|
||||
2. **Only the repository imports Prisma.** Services depend on repository
|
||||
interfaces. This is what makes services unit-testable without a database and
|
||||
what keeps a later storage change from rippling outward.
|
||||
|
||||
3. **A module owns its tables exclusively.** `OrdersModule` never queries
|
||||
`products` — it asks `ProductsModule`'s public service, or it stores a
|
||||
snapshot. Shared tables are how a monolith becomes unsplittable.
|
||||
|
||||
4. **Cross-module imports go through `public/`.** Deep imports are blocked by
|
||||
ESLint (`@sport/eslint-config/nest`). If you need something that is not
|
||||
exported, widen the public surface deliberately — do not reach around it.
|
||||
|
||||
## Talking to another module
|
||||
|
||||
| Need | Mechanism |
|
||||
| ---------------------------------------- | ------------------------------------------------ |
|
||||
| An answer, now, to continue this request | Call its public service |
|
||||
| To react to something that happened | Subscribe to its domain event |
|
||||
| To change its data | Call its public service — never write its tables |
|
||||
|
||||
## Modules marked EXTRACTION CANDIDATE
|
||||
|
||||
`inventory`, `orders`, `payments` and `search` are written so they could become
|
||||
independent services later: no foreign reads, communication via events, and no
|
||||
shared transactions with the rest of the monolith beyond their own tables.
|
||||
|
||||
That is a _constraint on how they are written_, not a plan to extract them.
|
||||
Extraction is justified by a real scaling or team-boundary problem, and nothing
|
||||
here assumes it will ever happen.
|
||||
Reference in New Issue
Block a user