Basic Architecture of Sport Web

This commit is contained in:
Nông Đức Huy
2026-08-11 13:37:25 +07:00
commit 8032fff6ac
262 changed files with 20348 additions and 0 deletions
+53
View File
@@ -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.