# 2.Quy chuẩn phát triển module

### 2.1. Mục tiêu chương

Chương này quy định cấu trúc chuẩn của mỗi module và trách nhiệm của từng layer nhằm:

- Tách biệt rõ ràng các tầng xử lý
- Giảm phụ thuộc giữa các thành phần
- Dễ bảo trì, mở rộng và test
- Đảm bảo tính nhất quán giữa các module trong hệ thống

### 2.2. Khái niệm / phạm vi áp dụng

Quy tắc này áp dụng cho:

- Tất cả các module trong thư mục modules/\*\*
- Cả Core Team và Partner Team
- Tất cả các chức năng mới được phát triển

#### Cấu trúc chuẩn mỗi module

![](https://docs.lifetex.vn/uploads/images/gallery/2026-02/scaled-1680-/embedded-image-q0uzrb7j-png.png)

modules/&lt;module-name&gt;/

 controller/

 service/

 repository/

 entity/

 dto/

#### Ý nghĩa từng thành phần

<div align="left" dir="ltr" id="bkmrk-layer-vai-tr%C3%B2-v%C3%AD-d%E1%BB%A5%C2%A0"><table><colgroup><col width="80"></col><col width="256"></col><col width="323"></col></colgroup><tbody><tr><td>Layer

</td><td>Vai trò

</td><td>ví dụ

</td></tr><tr><td>controller

</td><td>Nhận request từ client và trả response

</td><td>@PostMapping

public ApiResponse&lt;PlanningResponse&gt; create(@Valid @RequestBody PlanningCreateRequest req) {

 return ApiResponse.ok(service.create(req));

}

  
</td></tr><tr><td>service

</td><td>Xử lý logic nghiệp vụ

</td><td>public PlanningResponse get(Long id) {

 PlanningEntity e = repo.findById(id).orElseThrow(() -&gt;

 new AppException(ErrorCode.NOT\_FOUND, HttpStatus.NOT\_FOUND, "Planning not found: " + id)

 );

 return toResponse(e);

}

</td></tr><tr><td>repository

</td><td>Truy cập và thao tác dữ liệu

</td><td>public interface PlanQueryRepository {

 long count(PlanListFilter filter);

 List&lt;PlanListItem&gt; list(PlanListFilter filter);

}

  
</td></tr><tr><td>entity

</td><td>Mapping bảng database

</td><td>public class PlanningEntity {

 @Id

 @GeneratedValue(strategy = GenerationType.IDENTITY)

 private Long id;

}

</td></tr><tr><td>dto

</td><td>Model request và response

</td><td>public class PlanListFilter {

 private String keyword;

 private Integer page = 1; // 1-based

 private Integer size = 20;

 private String sortBy = "created\_at";

 private String sortDir = "desc";

 public String getKeyword() { return keyword; }

 public void setKeyword(String keyword) { this.keyword = keyword; }

 public Integer getPage() { return page; }

 public void setPage(Integer page) { this.page = page; }

 public Integer getSize() { return size; }

 public void setSize(Integer size) { this.size = size; }

 public String getSortBy() { return sortBy; }

 public void setSortBy(String sortBy) { this.sortBy = sortBy; }

 public String getSortDir() { return sortDir; }

 public void setSortDir(String sortDir) { this.sortDir = sortDir; }

}

</td></tr></tbody></table>

</div>### 2.3. Quy định chính

#### Trách nhiệm từng layer

##### Controller

- Nhận request từ client
- Gọi service tương ứng
- Trả response về client
- Không xử lý logic nghiệp vụ

##### Service

- Xử lý logic nghiệp vụ
- Điều phối repository
- Chuyển đổi entity ↔ DTO

##### Repository

- Truy cập database
- Thực hiện các thao tác CRUD
- Không chứa logic nghiệp vụ

##### Entity

- Mapping với bảng database
- Không chứa logic nghiệp vụ phức tạp

##### DTO

- Model cho request/response
- Không gắn trực tiếp với entity

---

#### Quy tắc bắt buộc

1. Controller không được chứa logic nghiệp vụ
2. Không trả trực tiếp Entity ra API
3. Luôn dùng DTO cho request/response
4. Response chuẩn toàn hệ thống: ApiResponse&lt;T&gt;

### 2.4. Cách thực hiện / quy trình

#### Quy trình phát triển một chức năng mới

Bước 1: Tạo DTO

Ví dụ:

UserCreateRequest

UserResponse

Bước 2: Tạo Entity

Mapping với bảng database:

UserEntity

Bước 3: Tạo Repository

UserRepository

Bước 4: Tạo Service

UserService

Xử lý logic:

- Validate dữ liệu
- Gọi repository
- Mapping entity → DTO

Bước 5: Tạo Controller

UserController

- Nhận request
- Gọi service

[![image.png](https://docs.lifetex.vn/uploads/images/gallery/2026-02/scaled-1680-/image-png.png)](https://docs.lifetex.vn/uploads/images/gallery/2026-02/scaled-1680-/image-png.png)

### 2.5. Ví dụ minh họa

#### Ví dụ sai (vi phạm quy tắc)

Controller chứa logic:

@GetMapping("/users")

public List&lt;UserEntity&gt; getAll() {

 return userRepository.findAll();

}

Sai vì:

- Trả Entity trực tiếp
- Không dùng Service
- Không dùng ApiResponse

---

#### Ví dụ đúng

@GetMapping("/users")

public ApiResponse&lt;List&lt;UserResponse&gt;&gt; getAll() {

 return ApiResponse.ok(userService.getAll());

}

Service:

public List&lt;UserResponse&gt; getAll() {

 return userRepository.findAll()

 .stream()

 .map(this::toResponse)

 .toList();

}

### 2.6. Checklist áp dụng

Trước khi commit module mới:

- Có đủ:
- controller/
- service/
- repository/
- entity/
- dto/

- Controller không chứa logic nghiệp vụ
- Không trả Entity ra API
- Tất cả API trả về ApiResponse&lt;T&gt;
- DTO tách biệt với Entity

<div align="left" dir="ltr" id="bkmrk--3"></div>