feat: add guide

This commit is contained in:
2026-08-22 08:29:30 +07:00
parent 3d22e0dfc0
commit 1715e366c6
5 changed files with 447 additions and 0 deletions
+91
View File
@@ -0,0 +1,91 @@
# APLP Backend — Conventions
| | |
| --- | --- |
| **Status** | Draft |
## 1. Naming & Package
- Base package: `com.aplp.backend`
- Mỗi module: `com.aplp.backend.<module>.<layer>` với layer = `api | application | domain | persistence` (xem `ARCHITECTURE.md`).
- Tên class theo responsibility:
- Controller: `XxxController`
- Use case: `XxxUseCase` hoặc `XxxService`
- Request/Response DTO: `XxxRequest`, `XxxResponse`
- Aggregate/Root: tên domain concept (vd `Learner`, `Course`)
- Repository interface: `XxxRepository` (định nghĩa ở domain)
## 2. Layer Rules
| Layer | Được phép | Cấm |
| --- | --- | --- |
| `api` | AuthN/authorization (framework), input validation, DTO mapping | Business rules |
| `application` | Orchestrate use case, transaction, call domain/persistence | Nhúng business rules riêng |
| `domain` | Business logic, invariants, domain services, repository interface | Spring/JPA/HTTP dependencies |
| `persistence` | Repository impl, JPA entities, mappers | Business logic |
- **Domain không import Spring/JPA/HTTP.**
- Persistence entities tách biệt (hoặc mappers) khỏi domain model nếu cần.
## 3. Transaction
- Transaction mở ở **Application** layer (`@Transactional` trên use case/service).
- Không ném transaction qua domain khi chỉ để đọc.
- Repository phương thức read nên read-only transaction khi cần.
## 4. Validation
- **Input/API validation** ở `api` layer (bean validation trên DTO).
- **Business invariant** trong `domain` (domain exception).
- Response lỗi dùng format đồng nhất (vd `ApiError` với code + message).
## 5. Errors & Exceptions
- `DomainException` cho lỗi business; mapping sang HTTP status ở `api` layer.
- Error response nhất quán: `code`, `message`, `details` (tuỳ thỏa thuận).
- Kèm `traceId`/requestId để dễ debug (Phase 0).
- Error code dùng **global enum `ErrorCode`**`common/api` (kèm HTTP status); mở rộng bằng cách thêm hằng số khi có module mới.
## 6. DTO Mapping
- Không để JPA entity lọt ra ngoài `persistence`/`api` response.
- **Mapping thủ công** (static method) trong repository impl / DTO factory — quyết định ở Phase 0 (không dùng MapStruct cho giai đoạn này; thêm khi có justification).
## 7. Repository
- Interface repository của module ở `domain`; implementation ở `persistence`.
- Chỉ expose các method cần thiết cho use case, không leek Query/spec toàn module.
- Query đặc thù (search, aggregation) nằm trong repository implementation.
## 8. Domain Events (khi cần)
- Dùng để tách rời side-effect giữa module (vd assessment hoàn thành → cập nhật adaptive state).
- Không lạm dụng: nếu đồng bộ đơn giản và cùng transaction, gọi trực tiếp qua interface.
- Nếu dùng Spring events: publish ở application layer, không trong domain.
## 9. Config & Secrets
- Cấu hình theo environment (`application.yml`, profile dev/prod).
- **Không commit secret/key vào repo.** Dùng env vars hoặc bí quyết quản lý (vault) khi có.
- Không log secret/token/password.
## 10. Testing
- Unit test cho `domain` + `application`.
- Test repository/persistence khi cần.
- Integration test cho API layer.
- Quyết định framework/test DB ở Phase 0.
## 11. Code Style
- Java theo tiêu chuẩn project (indent 4 spaces — xác nhận khi setup).
- Code của backend **không comment thừa**; tên rõ nghĩa.
- `@author`/metadata không bắt buộc.
## 12. Open Questions
| ID | Question | Status |
| --- | --- | --- |
| CON-001 | Dùng MapStruct hay mapping thủ công? | **Resolved**: thủ công (Phase 0) |
| CON-002 | Error code convention (enum per module vs global)? | **Resolved**: global `ErrorCode` trong `common/api` |
| CON-003 | JPA entities tách hay dùng chung domain model? | **Resolved**: tách riêng (`*JpaEntity` trong `persistence`, domain model trong `domain`) |