Tài liệu hướng dẫn quy trình phát triển Api sử dụng Springboot


Tổng quan kiến trúc hệ thống

Tổng quan kiến trúc hệ thống

Nội dung chi tiết

1. Tổng quan kiến trúc hệ thống

1.1. Mục tiêu kiến trúc

Kiến trúc backend được thiết kế nhằm:

Tất cả các service backend phải tuân thủ kiến trúc chuẩn được định nghĩa trong tài liệu này.


1.2. Mô hình kiến trúc

Hệ thống backend sử dụng mô hình:

Modular Monolith – Layered Architecture

Đặc điểm:

Sơ đồ tổng thể:

image.png

Tích hợp ngoài:

image.png


1.3. Quy tắc phân lớp (Layered Architecture)

Mỗi module phải tuân thủ cấu trúc phân lớp sau:

controller service repository entity dto mapper exception

1.3.1. Controller Layer (API Layer)

Chức năng:

Quy định:

Ví dụ:


@RestController @RequestMapping("/api/users") public class UserController { private final UserService userService; @PostMapping public ApiResponse<UserResponse> create(@Valid @RequestBody UserRequest req) { return ApiResponse.success(userService.create(req)); } }

1.3.2. Service Layer (Business Layer)

Chức năng:

Quy định:

Ví dụ:


@Service public class UserService { @Transactional public UserResponse create(UserRequest req) { User entity = mapper.toEntity(req); repository.save(entity); return mapper.toResponse(entity); } }

1.3.3. Repository Layer (Persistence Layer)

Chức năng:

Quy định:

Ví dụ:


public interface UserRepository extends JpaRepository<User, Long> { }

1.3.4. Entity Layer

Chức năng:

Quy định:


1.3.5. DTO Layer

Gồm:

Chức năng:

Quy định:


1.3.6. Mapper Layer

Chức năng:

Có thể dùng:

Quy định:


1.4. Quy tắc phụ thuộc (Dependency Direction)

Dependency chỉ được phép đi theo một chiều:


Controller → Service → Repository → DB

Không được phép:

Nguyên tắc:

Layer trên được gọi layer dưới
Layer dưới không được gọi layer trên


1.5. Tổ chức module theo domain

Project được tổ chức theo domain thay vì technical layer toàn cục.

Cấu trúc chuẩn:


com.company.project ├── common │ ├── config │ ├── exception │ ├── util │ ├── user │ ├── controller │ ├── service │ ├── repository │ ├── entity │ ├── dto │ ├── mapper │ ├── document │ ├── controller │ ├── service │ ├── repository │ ├── entity │ ├── dto │ ├── mapper

1.6. Tích hợp hệ thống ngoài

Backend có thể tích hợp các thành phần sau:

Quy tắc tích hợp:

Ví dụ:


integration ├── sso │ ├── SsoClient │ ├── redis │ ├── RedisService │ ├── external │ ├── ExternalApiClient

1.7. Nguyên tắc kiến trúc bắt buộc

Tất cả backend service phải tuân thủ:

Vi phạm kiến trúc được xem là lỗi nghiêm trọng trong review code.


1.8. Khả năng mở rộng Microservice

Kiến trúc hiện tại cho phép tách module thành microservice khi cần:

Ví dụ:


user module → user-service document moduledocument-service auth module → auth-service

1.9. Xử lý ngoại lệ toàn cục (Exception Handling Strategy)

1.9.1. Mục tiêu

Chuẩn hóa cơ chế xử lý lỗi toàn hệ thống nhằm:

Tất cả API backend phải sử dụng cơ chế xử lý ngoại lệ toàn cục.


1.9.2. Global Exception Handler

Hệ thống sử dụng Global Exception Handler thông qua @ControllerAdvice.

Chức năng:

Quy định:

Ví dụ:


@RestControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler(ResourceNotFoundException.class) public ResponseEntity<ApiError> handleNotFound(ResourceNotFoundException ex) { return build(HttpStatus.NOT_FOUND, ex.getCode(), ex.getMessage()); } @ExceptionHandler(AccessDeniedException.class) public ResponseEntity<ApiError> handleForbidden(AccessDeniedException ex) { return build(HttpStatus.FORBIDDEN, "ACCESS_DENIED", "Access denied"); } @ExceptionHandler(MethodArgumentNotValidException.class) public ResponseEntity<ApiError> handleValidation(MethodArgumentNotValidException ex) { return build(HttpStatus.BAD_REQUEST, "VALIDATION_ERROR", "Invalid request"); } @ExceptionHandler(Exception.class) public ResponseEntity<ApiError> handleSystem(Exception ex) { return build(HttpStatus.INTERNAL_SERVER_ERROR, "SYSTEM_ERROR", "Internal server error"); } private ResponseEntity<ApiError> build(HttpStatus status, String code, String message) { ApiError error = ApiError.of(code, message); return ResponseEntity.status(status).body(error); } }

1.9.3. Mapping Exception → HTTP Status

Chuẩn mapping bắt buộc:

Exception HTTP Status
ValidationException 400 Bad Request
MethodArgumentNotValid 400 Bad Request
IllegalArgumentException 400 Bad Request
AccessDeniedException 403 Forbidden
AuthenticationException 401 Unauthorized
ResourceNotFoundException 404 Not Found
BusinessException 422 Unprocessable
SystemException 500 Internal Server Error
Exception (default) 500 Internal Server Error

Không được trả:


1.9.4. Chuẩn format response lỗi

Tất cả API khi lỗi phải trả format thống nhất:


{ "timestamp": "2026-02-23T10:15:30Z", "code": "USER_NOT_FOUND", "message": "User not found", "traceId": "abc123" }

Ý nghĩa:

Field Mô tả
timestamp Thời điểm lỗi
code Mã lỗi hệ thống
message Thông báo lỗi
traceId ID truy vết log

Quy định:


1.9.5. Quy tắc định nghĩa Exception

Mỗi loại lỗi phải có class riêng:


exception ├── ResourceNotFoundException ├── ValidationException ├── BusinessException ├── SystemException

Ví dụ:


public class ResourceNotFoundException extends RuntimeException { private final String code; public ResourceNotFoundException(String code, String message) { super(message); this.code = code; } public String getCode() { return code; } }

1.9.6. Quy tắc sử dụng Exception

Service layer phải throw exception domain:


public User getUser(Long id) { return repository.findById(id) .orElseThrow(() -> new ResourceNotFoundException( "USER_NOT_FOUND", "User not found" )); }

Không được:


1.9.7. TraceId và logging

Mỗi request phải có traceId để truy vết lỗi:

Ví dụ:


public class ApiError { private String timestamp; private String code; private String message; private String traceId; public static ApiError of(String code, String message) { ApiError e = new ApiError(); e.timestamp = Instant.now().toString(); e.code = code; e.message = message; e.traceId = MDC.get("traceId"); return e; } }

1.9.8. Nguyên tắc bắt buộc

Tất cả backend service phải tuân thủ:

Vi phạm quy tắc xử lý lỗi được xem là lỗi nghiêm trọng trong code review

Chương 1: Setup môi trường

Chương này hướng dẫn chuẩn bị môi trường phát triển cho dự án, bao gồm cài đặt công cụ cần thiết, cấu hình biến môi trường, thiết lập IDE và kiểm tra kết nối đến các dịch vụ phụ trợ (DB, cache, message broker…). Sau khi hoàn thành, lập trình viên có thể chạy dự án ở môi trường local.

Chương 1: Setup môi trường

Hướng dẫn setup môi trường và start project

1. Mục tiêu

Hướng dẫn developer:


2. Yêu cầu hệ thống

2.1. Phần mềm cần cài đặt

Công cụ Phiên bản khuyến nghị
Java JDK 17 (bắt buộc)
Maven 3.8+
Git Mới nhất
IDE IntelliJ IDEA 2023+
PostgreSQL 14 hoặc 15
DB Tool DBeaver / PgAdmin

2.2. Kiểm tra cài đặt

Mở terminal:


java -version

Kết quả mong muốn:


java version "17.0.x"

Kiểm tra Maven:


mvn -v

3. Clone source code


4. Cấu hình biến môi trường

Project sử dụng file:

application.properties

4.1. Các biến môi trường cơ bản

Ví dụ file:


application.properties

server: port: 8080 spring: datasource: url: jdbc:postgresql://localhost:5432/lifetex username: lifetex pass

#spring.application.name=demo
#server.port=8080
#
## ===== Oracle datasource =====
#spring.datasource.url=jdbc:oracle:thin:@//192.168.0.111:1111/ORCLPDB1
#spring.datasource.username=test
#spring.datasource.password=test
#spring.datasource.driver-class-name=oracle.jdbc.OracleDriver
#
## ===== JPA =====
#spring.jpa.hibernate.ddl-auto=none
#spring.jpa.show-sql=true
#spring.jpa.properties.hibernate.format_sql=true
#spring.jpa.database-platform=org.hibernate.dialect.OracleDialect
#
## ===== Hikari pool (optional) =====
#spring.datasource.hikari.maximum-pool-size=10
#spring.datasource.hikari.minimum-idle=2
#spring.datasource.hikari.connection-timeout=30000
#
#management.endpoints.web.exposure.include=health,info

4.2. Cách chỉnh sửa biến môi trường

Cách 1: Sửa trực tiếp trong file application.properties

Ví dụ đổi DB:


spring: datasource: url: jdbc:postgresql://localhost:5432/test_db username: test password: test123

Cách 2: Dùng biến môi trường hệ điều hành

Ví dụ trong application.properties:


spring: datasource: url: ${DB_URL} username: ${DB_USER} password: ${DB_PASS}

Trên Windows (PowerShell)


$env:DB_URL="jdbc:postgresql://localhost:5432/lifetex" $env:DB_USER="lifetex" $env:DB_PASS="123456"

Trên Linux/Mac


export DB_URL=jdbc:postgresql://localhost:5432/lifetex export DB_USER=lifetex export DB_PASS=123456

5. Chọn profile chạy

Spring Boot thường dùng profile:


dev staging prod

Ví dụ chạy với profile dev.


Cách cấu hình profile

Cách 1: Trong biến môi trường

Windows:


$env:SPRING_PROFILES_ACTIVE="dev"

Linux/Mac:


export SPRING_PROFILES_ACTIVE=dev

Cách 2: Trong IDE

VM options:


-Dspring.profiles.active=dev

6. Build project

Trong thư mục project:


mvn clean install

Nếu build thành công sẽ thấy:

BUILD SUCCESS

7. Start project

Chạy trong IDE

Trong IntelliJ:

  1. Mở project

  2. Mở file:


DemoApplication.java
  1. Nhấn nút Run


8. Kiểm tra project chạy thành công

Sau khi start, kiểm tra log:

Started DemoApplication in 5.123 seconds

Mở trình duyệt:


http://localhost:8080

Hoặc gọi API:


http://localhost:8080/api/v1/health

Chương 2: Hướng dẫn phát triển (Developer)

Chương này mô tả cấu trúc source code, quy ước coding, cách tạo module mới, cách viết API/UI, quy trình commit/branch, và cách chạy/debug dự án trong quá trình phát triển. Mục tiêu giúp developer hiểu kiến trúc và đóng góp code đúng chuẩn.

Chương 2: Hướng dẫn phát triển (Developer)

Luồng xử lý API Backend (API Processing Flow)

1.1. Mục tiêu chương.


Mô tả luồng xử lý chuẩn của một API backend từ khi nhận request đến khi deploy production nhằm:

Thống nhất cách xây dựng API giữa các team

Đảm bảo tuân thủ đầy đủ các quy định kiến trúc

Dễ trace lỗi và audit

Liên kết các chuẩn đã quy định ở các chương trước

1.2. Phạm vi áp dụng:

Áp dụng cho:

Tất cả REST API trong modules/**

Core Team và Partner Team

Tất cả service Spring Boot

1.3. Tổng quan luồng xử lý API


Luồng chuẩn:

image.png


1.4. Các bước xử lý chi tiết


Bước 1. Client gọi API


Ví dụ:

POST /api/v1/users
Payload:

{
  "username": "test",
  "password": "123456"
}
Quy định liên quan:

👉 Chương 7 — API Design & Response Standard

Bước 2. Security / Authentication


Hệ thống kiểm tra:

JWT / SSO token

Permission

Role

Nếu fail:

401 Unauthorized
403 Forbidden
Quy định liên quan:

👉 Chương 8 — Cơ chế xác thực & SSO (WSO2)

Bước 3. Controller nhận request

@PostMapping
public ApiResponse<UserResponse> create(
        @Valid @RequestBody UserCreateRequest request) {
    return ApiResponse.ok(userService.create(request));
}
Quy định:

Name Controller

Không chứa business logic

👉 Chương 3 — Coding Convention
👉 Chương 7 — API Design

Bước 4. DTO Validation


DTO:

public class UserCreateRequest {

    @NotBlank
    @Size(max = 100)
    private String username;

    @NotBlank
    private String password;
}
Spring tự validate trước khi vào service.

Nếu lỗi:

400 Bad Request
Response chuẩn:


{
  "code": "VALIDATION_ERROR",
  "message": "username is required"
}
Quy định:

👉 Chương 3 — Coding Convention (Validation)
👉 Chương 7 — Response Standard

Bước 5. Service xử lý logic

public UserResponse create(UserCreateRequest req) {
    log.info("Create user {}", req.getUsername());

    UserEntity e = mapper.toEntity(req);
    repo.save(e);

    return mapper.toResponse(e);
}
Cấu trúc chuẩn 1 hàm service:

image.png


Quy định:

👉 Chương 3 — Coding Convention
👉 Chương 4 — Entity & Database

Bước 6. Repiository & Database

userRepository.save(entity);
Nếu thay đổi schema:

update entity

migration script

Quy định:

👉 Chương 4 — Thay đổi Entity & DB
👉 Chương 5 — Schema & Migration

Bước 7. Mapping Response

return UserResponse.builder()
        .id(e.getId())
        .username(e.getUsername())
        .build();
Response chuẩn:


{
  "code": "SUCCESS",
  "data": {
    "id": 1,
    "username": "test"
  }
}
Quy định:

👉 Chương 7 — Response Standard

Bước 8. Logging & Audit


Trong service:


log.info("User created id={}", e.getId());
Nếu nghiệp vụ quan trọng:

ghi audit_log

Quy định:

👉 Chương 3 — Logging
👉 Chương 6 — Audit Log

Bước 9. Exception Handling


Ví dụ:


if (exists) {
    throw new BusinessException("USER_EXISTS");
}
Global handler:


@ExceptionHandler(BusinessException.class)
Response:


{
  "code": "USER_EXISTS",
  "message": "User already exists"
}
Quy định:

👉 Chương 7 — Response & Error

1.5. Luồng phát triển & release API


Sau khi code xong:


Dev → Commit → PR → Review → Merge → CI Build → Deploy


Bước 10. Commit & PR


Quy định:

👉 Chương 9 — Git Workflow & Pull Request

Bước 11. Checklist trước merge


Quy định:

👉 Chương 10 — Checklist merge

Bước 12. Deploy & Update DB


Nếu có migration:

chạy script

deploy service

Quy định:

👉 Chương 5 — Migration
👉 Chương 12 — Connect DB

1.6. Sơ đồ tổng thể API lifecycle


https://docs.lifetex.vn/link/333#bkmrk-request-%E2%86%93-auth-%28ch8%29

Request
  ↓
Auth (Ch8)
  ↓
Controller (Ch3,7)
  ↓
DTO Validate (Ch3)
  ↓
Service Logic (Ch3)
  ↓
Entity/DB (Ch4,5)
  ↓
Mapping (Ch7)
  ↓
Logging/Audit (Ch3,6)
  ↓
Response (Ch7)
  ↓
Git/PR (Ch9,10)
  ↓
Deploy (Ch5,12)

1.7. Transaction trong xử lý API

1.7.1. Nguyên tắc transaction

Mọi thao tác thay đổi dữ liệu nghiệp vụ trong API phải được thực hiện trong transaction nhằm đảm bảo:

Transaction phải được đặt tại Service layer.


1.7.2. Quy định transaction

Transaction:

Không được đặt transaction tại:


1.7.3. Ví dụ transaction chuẩn


@Transactional public UserResponse create(UserCreateRequest req) { if (repo.existsByUsername(req.getUsername())) { throw new BusinessException("USER_EXISTS"); } UserEntity e = mapper.toEntity(req); repo.save(e); auditService.logCreate("USER", e.getId()); return mapper.toResponse(e); }

1.7.4. Quy tắc rollback

Transaction phải rollback khi:

Không được:


1.8. Security Context trong Service

1.8.1. Khái niệm

Security Context là thông tin người dùng hiện tại sau khi xác thực (JWT / SSO).

Thông tin thường có:


1.8.2. Sử dụng trong Service

Service được phép truy cập Security Context để:

Ví dụ:


Long userId = SecurityUtils.getCurrentUserId(); String username = SecurityUtils.getCurrentUsername();

1.8.3. Quy định sử dụng

Không được:

Permission check phải tại Service layer.


1.8.4. Ví dụ kiểm tra quyền


public void updateUser(Long id, UserUpdateRequest req) { Long currentUser = SecurityUtils.getCurrentUserId(); if (!permissionService.canUpdateUser(currentUser, id)) { throw new AccessDeniedException("NO_PERMISSION"); } ... }

1.9. Xử lý API danh sách (List API)

1.9.1. Nguyên tắc List API

API trả danh sách phải hỗ trợ:

Mục tiêu:


1.9.2. Chuẩn request List API

Ví dụ:


GET /api/v1/users?page=0&size=20&sort=createdAt,desc

Tham số chuẩn:


1.9.3. Chuẩn response List API


{ "code": "SUCCESS", "data": { "content": [], "page": 0, "size": 20, "totalElements": 100, "totalPages": 5 } }

1.9.4. Quy định bắt buộc


1.10. Gọi hệ thống ngoài trong API

1.10.1. Phạm vi

API có thể cần gọi:


1.10.2. Kiến trúc gọi ngoài

Luồng chuẩn:

Service → Integration Client → External System

Ví dụ:


UserInfo info = ssoClient.getUser(token);

1.10.3. Quy định

Không được gọi external tại:

Phải:


1.10.4. Xử lý lỗi external

Nếu external fail:


1.11. Monitoring & Metrics trong API

1.11.1. Mục tiêu

Ngoài Logging & Audit, API production cần hỗ trợ:


1.11.2. Metrics cần có


1.11.3. Trace request

Mỗi request phải có:

TraceId phải liên kết:


1.12. Versioning API

1.12.1. Chuẩn version

API phải có version trong URL:


/api/v1/...

1.12.2. Nguyên tắc version


1.12.3. Ví dụ


/api/v1/users /api/v2/users

1.13. Testing trước merge

1.13.1. Mục tiêu

Đảm bảo API hoạt động đúng trước khi merge và deploy.


1.13.2. Loại test bắt buộc


1.13.3. Quy định

API mới hoặc thay đổi logic phải có test:


1.14. Hiệu năng & Database

1.14.1. Nguyên tắc thiết kế DB trong API

API phải đảm bảo:


1.14.2. Các lỗi cần tránh


1.14.3. Kiểm tra khi review

Khi review API cần kiểm tra:

Chương 2: Hướng dẫn phát triển (Developer)

1.Cấu trúc dự án

1.1. Mục tiêu chương

Chương này quy định cấu trúc dự án chuẩn và phạm vi quản lý mã nguồn giữa Core Team và các đơn vị Partner nhằm:

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

Tài liệu áp dụng cho:

Cấu trúc dự án chuẩn:

com.example.demo

 ├── common/   (thành phần dùng chung)

 ├── config/   (cấu hình hệ thống)

 ├── modules/  (các module nghiệp vụ)

 └── DemoApplication.java


Ý nghĩa từng khu vực

Thư mục

Vai trò

Phạm vi sử dụng

common

Thành phần dùng chung toàn hệ thống

Core quản lý

config

Cấu hình hệ thống, security, hạ tầng

Core quản lý

modules

Các module nghiệp vụ

Core + Partner

1.3. Quy định chính

Phân quyền quản lý code

Khu vực

Đơn vị quản lý

Quyền chỉnh sửa

common/**

Core Team

Partner không được sửa

config/**

Core Team

Partner không được sửa

modules/**

Core + Partner

Được phép phát triển

Quy định bắt buộc

Đối tác KHÔNG được phép sửa trực tiếp:

common/**

config/**

Mọi thay đổi trong các khu vực này phải:

  1. Tạo yêu cầu thay đổi (Core Change Request)

  2. Được Core Team xem xét

  3. Core Team phê duyệt và thực hiện

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

Quy trình thay đổi code dùng chung

Bước 1: Partner phát hiện nhu cầu thay đổi
Bước 2: Tạo ticket với tiêu đề: các phần mềm quản lý công việc liên quan (Jira / Redmine / YouTrack) hoặc nội bộ

[CORE CHANGE REQUEST] Thêm field phone vào user_account

Luồng xử lý: 

  1. Partner tạo ticket

  2. Core Team review

  3. Chuyển trạng thái:

Trạng thái

Ý nghĩa

Open

Ticket mới

Under Review

Core đang đánh giá

Approved

Đồng ý thay đổi

Rejected

Từ chối

Implemented

Core đã code

Merged

Đã merge vào develop


Bước 3: Core Team đánh giá:

Bước 4: Nếu hợp lệ:

Bước 5: Partner pull code mới về và tiếp tục phát triển

1.5. Ví dụ minh họa

Trường hợp hợp lệ

Partner cần thêm logic trong module planning:

modules/planning/service/PlanningService.java

→ Được phép sửa trực tiếp và tạo PR.

Trường hợp không hợp lệ

Partner muốn sửa:

common/security/JwtAuthenticationFilter.java

→ Không được sửa trực tiếp.

Phải thực hiện:

  1. Tạo Core Change Request

  2. Chờ Core Team phê duyệt

  3. Core Team thực hiện thay đổi

1.6. Checklist áp dụng

Trước khi commit hoặc tạo PR, cần kiểm tra:

Chương 2: Hướng dẫn phát triển (Developer)

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:

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

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

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

modules/<module-name>/

  controller/ 

  service/

  repository/

  entity/

  dto/

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

Layer

Vai trò

ví dụ 

controller

Nhận request từ client và trả  response

@PostMapping

public ApiResponse<PlanningResponse> create(@Valid @RequestBody PlanningCreateRequest req) {

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

}


service

Xử lý logic nghiệp vụ

public PlanningResponse get(Long id) {

   PlanningEntity e = repo.findById(id).orElseThrow(() ->

           new AppException(ErrorCode.NOT_FOUND, HttpStatus.NOT_FOUND, "Planning not found: " + id)

   );

   return toResponse(e);

}

repository

Truy cập và thao tác dữ liệu

public interface PlanQueryRepository {

   long count(PlanListFilter filter);

   List<PlanListItem> list(PlanListFilter filter);

}


entity

Mapping bảng database

public class PlanningEntity {

   @Id

   @GeneratedValue(strategy = GenerationType.IDENTITY)

   private Long id;

}

dto

Model request và response

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; }

}

2.3. Quy định chính

Trách nhiệm từng layer

Controller
Service
Repository
Entity
DTO

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<T>

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:

Bước 5: Tạo Controller

UserController

image.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<UserEntity> getAll() {

    return userRepository.findAll();

}

Sai vì:


Ví dụ đúng

@GetMapping("/users")

public ApiResponse<List<UserResponse>> getAll() {

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

}

Service:

public List<UserResponse> getAll() {

    return userRepository.findAll()

        .stream()

        .map(this::toResponse)

        .toList();

}

2.6. Checklist áp dụng

Trước khi commit module mới:

Chương 2: Hướng dẫn phát triển (Developer)

3.Coding convention

3.1. Mục tiêu chương

Chương này quy định chuẩn coding và nguyên tắc thiết kế nhằm:


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

Quy định này áp dụng cho:


3.3. Quy định chính

3.3.1. Quy tắc đặt tên

Các thành phần phải đặt tên theo quy ước thống nhất:

Thành phần Quy tắc đặt tên Ví dụ
Controller <Name>Controller UserController
Service <Name>Service UserService
Repository <Name>Repository UserRepository
Entity <Name>Entity UserEntity
DTO Request <Name>CreateRequest, <Name>UpdateRequest UserCreateRequest
DTO Response <Name>Response UserResponse
Mapper <Name>Mapper UserMapper
Enum <Name>Enum UserStatusEnum

3.3.2. Quy tắc chung Java

Dùng camelCase cho:

Dùng PascalCase cho:

Ví dụ:


private String fullName; // đúng private String FullName; // sai public class UserService { } // đúng public class userService { } // sai

3.3.3. Quy định về logging

Không được dùng:


System.out.println("Error");

Phải dùng logging chuẩn:


private static final Logger log = LoggerFactory.getLogger(UserService.class); log.info("User created"); log.error("Create user failed", ex);

3.3.4. Validation dữ liệu đầu vào

Tất cả dữ liệu đầu vào phải được validate bằng annotation.

Annotation chuẩn:

Ví dụ:


public class UserCreateRequest { @NotBlank @Size(max = 100) private String username; @NotBlank private String password; }

3.4. Nguyên lý thiết kế SOLID áp dụng trong dự án

3.4.1. S — Single Responsibility

Một class chỉ có một trách nhiệm.

Quy định dự án:

Sai:


public class UserController { @Autowired UserRepository repo; // sai tầng }

Đúng:


public class UserController { @Autowired UserService userService; }

3.4.2. O — Open/Closed

Code phải mở rộng được nhưng không sửa code cũ.

Áp dụng:

Ví dụ:


public interface NotificationService { void send(Message msg); }

Triển khai:


public class EmailNotificationService implements NotificationService { } public class SmsNotificationService implements NotificationService { }

3.4.3. L — Liskov Substitution

Class con có thể thay thế class cha.

Quy định:

Sai:


public class UserServiceImpl implements UserService { public User get(String id) { throw new UnsupportedOperationException(); } }

3.4.4. I — Interface Segregation

Không tạo interface quá lớn.

Sai:


public interface UserService { create(); update(); delete(); exportExcel(); sendEmail(); }

Đúng:


public interface UserService { } public interface UserExportService { } public interface UserNotificationService { }

3.4.5. D — Dependency Inversion

Phụ thuộc abstraction, không phụ thuộc implementation.

Quy định:

Sai:


UserService service = new UserServiceImpl();

Đúng:


@Autowired UserService userService;

3.5. Quy tắc kiến trúc Spring Boot trong dự án

3.5.1. Luồng chuẩn tầng


Controller → Service → Repository → Database

Không được:


Controller → Repository Controller → EntityManager

3.5.2. Controller không chứa nghiệp vụ

Sai:


@PostMapping public User create(...) { user.setCreatedDate(LocalDateTime.now()); // sai }

Đúng:


@PostMapping public UserResponse create(...) { return userService.create(request); }

3.5.3. Service không chứa logic HTTP

Sai:


throw new ResponseStatusException(HttpStatus.BAD_REQUEST);

Đúng:


throw new BusinessException("USER_EXISTS");

3.5.4. Repository chỉ truy vấn dữ liệu

Không chứa:


3.6. Design pattern sử dụng trong hệ thống

3.6.1. Service pattern

Service là tầng nghiệp vụ trung tâm.


Controller → Service → Repository

3.6.2. DTO pattern

Tách DTO khỏi Entity.

Không trả Entity ra API.

Sai:


public UserEntity create(...) { }

Đúng:


public UserResponse create(...) { }

3.6.3. Mapper pattern

Convert DTO ↔ Entity.


UserEntity entity = mapper.toEntity(request);

3.6.4. Exception pattern

Dùng BusinessException thống nhất.


throw new BusinessException(ErrorCode.USER_NOT_FOUND);

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

Quy trình tạo DTO đúng chuẩn

Bước 1: Tạo class DTO theo quy tắc đặt tên

Ví dụ:

Bước 2: Thêm validation annotation

Bước 3: Dùng DTO trong controller


@PostMapping public ApiResponse<UserResponse> create( @Valid @RequestBody UserCreateRequest request) { return ApiResponse.ok(userService.create(request)); }

Quy trình logging chuẩn

Bước 1: Khai báo logger trong class


private static final Logger log = LoggerFactory.getLogger(UserService.class);

Bước 2: Dùng logger thay cho System.out.println


3.8. Ví dụ minh họa

Trường hợp sai


public class usercontroller { public void CreateUser() { System.out.println("Create user"); } }

Sai vì:


Trường hợp đúng


@RestController public class UserController { private static final Logger log = LoggerFactory.getLogger(UserController.class); private final UserService userService; public UserController(UserService userService) { this.userService = userService; } @PostMapping public ApiResponse<UserResponse> create( @Valid @RequestBody UserCreateRequest request) { log.info("Create user {}", request.getUsername()); return ApiResponse.ok(userService.create(request)); } }

Ví dụ DTO sai


public class userDTO { public String name; }

Sai vì:


Ví dụ DTO đúng


public class UserCreateRequest { @NotBlank @Size(max = 255) private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } }

3.9. Checklist áp dụng

Trước khi commit hoặc tạo PR:

Naming


Coding


Validation


SOLID


Architecture

3.10. Cấu trúc chuẩn của một hàm xử lý nghiệp vụ

3.10.1. Mục tiêu

Quy định cấu trúc thống nhất của một hàm xử lý nghiệp vụ nhằm:


3.10.2. Cấu trúc chuẩn bắt buộc

Một hàm service/controller phải theo thứ tự:


1. Validate input 2. Log input 3. Business logic 4. Catch exception (nếu cần) 5. Trả response / throw BusinessException

3.10.3. Quy định chi tiết từng phần

1. Validate

Ví dụ:


if (repo.existsByUsername(request.getUsername())) { throw new BusinessException(ErrorCode.USER_EXISTS); }

2. Log

Phải log:


log.info("Create user {}", request.getUsername());

3. Business logic

Chỉ chứa xử lý nghiệp vụ:


UserEntity entity = mapper.toEntity(request); repo.save(entity);

4. Exception handling

Không catch Exception chung chung nếu không xử lý.

Sai:


try { repo.save(entity); } catch (Exception e) { }

Đúng:


try { repo.save(entity); } catch (DataIntegrityViolationException ex) { log.error("DB error", ex); throw new BusinessException(ErrorCode.DB_ERROR); }

5. Response

Service:

Controller:


return UserResponse.from(entity);

Controller:


return ApiResponse.ok(userService.create(request));

3.10.4. Ví dụ hàm sai


public User create(UserCreateRequest req) { UserEntity e = new UserEntity(); e.setUsername(req.getUsername()); repo.save(e); return e; }

Sai vì:


3.10.5. Ví dụ hàm đúng chuẩn dự án


public UserResponse create(UserCreateRequest request) { // 1. Validate if (repo.existsByUsername(request.getUsername())) { throw new BusinessException(ErrorCode.USER_EXISTS); } // 2. Log log.info("Create user {}", request.getUsername()); // 3. Business logic UserEntity entity = mapper.toEntity(request); repo.save(entity); // 4. Response return mapper.toResponse(entity); }

3.10.6. Checklist

Khi review hàm service/controller:

Chương 2: Hướng dẫn phát triển (Developer)

4. Quy định thay đổi cấu trúc dữ liệu (Entity & Database)

4.1. Mục tiêu chương


Chương này quy định cách kiểm soát các thay đổi liên quan đến cấu trúc dữ liệu nhằm:

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


Quy định này áp dụng cho:

Các loại thay đổi cần kiểm soát

4.3. Quy định chính


4.3.1. Không được tự ý thay đổi các field chuẩn

Các field chuẩn hệ thống:

Quy định bắt buộc

Không được:

Các field này được coi là system fields và được dùng chung cho:


4.3.2. Thêm field mới trong module

Partner chỉ được phép thêm field khi:


4.3.3. Các thay đổi bắt buộc xin phép Core Team

Các thay đổi sau không được tự ý thực hiện:

Tất cả các trường hợp trên phải qua:

Data Model Change Request

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


Trường hợp 1: Thêm field trong module

Bước 1: Cập nhật entity trong:

modules/<module>/entity/**


Bước 2: Tạo migration script:

V<timestamp>__add_<field>_to_<table>.sql


Bước 3: Tạo Pull Request, trong PR phải có:

Bước 4: Core Team review:

Bước 5: Merge vào develop


Trường hợp 2: Thay đổi field hoặc quan hệ entity

Bước 1: Tạo ticket: các phần mềm quản lý công việc liên quan (Jira / Redmine / YouTrack) hoặc nội bộ

[DATA MODEL CHANGE REQUEST] <mô tả thay đổi>

Bước 2: Cung cấp thông tin:

Bước 3: Core Team review:

Bước 4: Nếu được duyệt:

4.5. Ví dụ minh họa


Trường hợp hợp lệ

Partner thêm field vào entity module:

@Column(name = "PRIORITY")

private Integer priority;


Và có migration:

ALTER TABLE PLANNING ADD PRIORITY INT;


→ Được phép.


Trường hợp không hợp lệ

Partner sửa:

@Column(name = "CREATED_AT")

private String createdAt;


→ Đổi kiểu dữ liệu từ timestamp sang string.

→ Không được phép.

Phải tạo:

[DATA MODEL CHANGE REQUEST]



Trường hợp cần xin phép

Partner muốn:

4.6. Checklist áp dụng


Trước khi commit hoặc tạo PR:

Chương 2: Hướng dẫn phát triển (Developer)

5.Quy định về Database, Schema và Migration

5.1. Mục tiêu chương


Chương này quy định cách quản lý cấu trúc database và các thay đổi schema nhằm:

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


Quy định này áp dụng cho:

Hệ thống phân loại bảng dữ liệu thành hai nhóm:


1. Core tables (dùng chung toàn hệ thống)

Bao gồm các bảng:

Đây là các bảng dữ liệu lõi, được dùng chung cho:


2. Module tables

Bao gồm:

Ví dụ:

5.3. Quy định chính

5.3.1. Quy định với Core tables

Partner không được phép:

Mọi thay đổi liên quan đến core tables phải thông qua:

DB Core Change Request -> sử dụng jira/… hoặc các phần mềm quản lý công việc nội bộ

Và do Core Team thực hiện.


5.3.2. Quy định với Module tables

Partner được phép:

Nhưng phải tuân thủ:


5.3.3. Migration bắt buộc

Mọi thay đổi database phải tuân thủ các nguyên tắc sau:

Công cụ sử dụng:


Format migration

Tên file migration:

V<timestamp>__<description>.sql


Ví dụ:

V20260209__create_planning_table.sql

V20260210__add_priority_to_planning.sql

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


Trường hợp 1: Thêm hoặc sửa bảng trong module

Bước 1: Cập nhật entity trong:

modules/<module>/entity/**


Bước 2: Tạo migration script:

V<timestamp>__<description>.sql


Bước 3: Commit:

Bước 4: Tạo Pull Request

Bước 5: Core Team review:

Bước 6: Merge vào develop


Trường hợp 2: Thay đổi core tables

Bước 1: Tạo ticket:

[DB CORE CHANGE REQUEST] <mô tả thay đổi>

Bước 2: Cung cấp thông tin:

Bước 3: Core Team review

Bước 4: Nếu được duyệt:

Merge vào develop

5.5. Ví dụ minh họa


Trường hợp hợp lệ

Partner thêm bảng mới:

CREATE TABLE PLANNING (

    ID BIGINT PRIMARY KEY,

    NAME VARCHAR(255),

    DESCRIPTION VARCHAR(1000)

);


→ Thuộc module table → được phép.


Trường hợp không hợp lệ

Partner chạy trực tiếp trên production:

ALTER TABLE USER_ACCOUNT ADD PHONE VARCHAR(20);


→ Sai quy định vì:


Trường hợp cần xin phép

Partner muốn:

ALTER TABLE ROLE ADD DESCRIPTION VARCHAR(255);


→ Đây là core table.

Phải tạo: trên phần mềm quản lý công việc nội bộ hoặc phần mềm nghiệp vụ tương đương

[DB CORE CHANGE REQUEST]

5.6. Checklist áp dụng


Trước khi commit hoặc tạo PR:

5.7. Quy định thay đổi cấu trúc dữ liệu (Entity & Database)


5.7.1. Mục tiêu chương


Chương này quy định cách kiểm soát các thay đổi liên quan đến cấu trúc dữ liệu nhằm:

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


Quy định này áp dụng cho:

Các loại thay đổi cần kiểm soát

5.7.3. Quy định chính


5.7.3.1. Không được tự ý thay đổi các field chuẩn

Các field chuẩn hệ thống:

Quy định bắt buộc

Không được:

Các field này được coi là system fields và được dùng chung cho:


5.7.3.2. Thêm field mới trong module

Partner chỉ được phép thêm field khi:


5.7.3.3. Các thay đổi bắt buộc xin phép Core Team

Các thay đổi sau không được tự ý thực hiện:

Tất cả các trường hợp trên phải qua:

Data Model Change Request

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


Trường hợp 1: Thêm field trong module

Bước 1: Cập nhật entity trong:

modules/<module>/entity/**


Bước 2: Tạo migration script:

V<timestamp>__add_<field>_to_<table>.sql


Bước 3: Tạo Pull Request, trong PR phải có:

Bước 4: Core Team review:

Bước 5: Merge vào develop


Trường hợp 2: Thay đổi field hoặc quan hệ entity

Bước 1: Tạo ticket: các phần mềm quản lý công việc liên quan (Jira / Redmine / YouTrack) hoặc nội bộ

[DATA MODEL CHANGE REQUEST] <mô tả thay đổi>

Bước 2: Cung cấp thông tin:

Bước 3: Core Team review:

Bước 4: Nếu được duyệt:

5.7.5. Ví dụ minh họa


Trường hợp hợp lệ

Partner thêm field vào entity module:

@Column(name = "PRIORITY")

private Integer priority;


Và có migration:

ALTER TABLE PLANNING ADD PRIORITY INT;


→ Được phép.


Trường hợp không hợp lệ

Partner sửa:

@Column(name = "CREATED_AT")

private String createdAt;


→ Đổi kiểu dữ liệu từ timestamp sang string.

→ Không được phép.

Phải tạo:

[DATA MODEL CHANGE REQUEST]



Trường hợp cần xin phép

Partner muốn:

5.7.6. Checklist áp dụng


Trước khi commit hoặc tạo PR:

Chương 2: Hướng dẫn phát triển (Developer)

6.Audit Log & System Metadata

6.1. Mục tiêu chương


Chương này quy định cách quản lý dữ liệu audit nhằm:

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


Audit log là dữ liệu ghi nhận:

Các bảng audit:

Các bảng này được coi là dữ liệu core của hệ thống.

Quy định này áp dụng cho:

Mọi thay đổi liên quan đến audit

6.3. Quy định chính


Partner không được phép:

Các bảng audit được coi là:

Core system data


Mọi thay đổi liên quan đến:

phải được:

Core Team phê duyệt

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


Trường hợp 1: Module cần ghi thêm audit

Bước 1: Sử dụng cơ chế audit có sẵn của hệ thống


Ví dụ:

Bước 2: Không được tự tạo bảng audit riêng

Bước 3: Nếu cần mở rộng dữ liệu audit:

Tạo ticket:

[AUDIT CHANGE REQUEST] <mô tả thay đổi>

Bước 4: Core Team review:


Trường hợp 2: Cần thay đổi cấu trúc bảng audit

Bước 1: Tạo ticket:

[DB CORE CHANGE REQUEST] Audit table change

Bước 2: Cung cấp thông tin:

Bước 3: Core Team review và quyết định

6.5. Ví dụ minh họa

Trường hợp hợp lệ

Module planning muốn ghi log khi tạo kế hoạch:

auditService.logCreate("PLANNING", planningId, userId);


→ Sử dụng cơ chế audit có sẵn → hợp lệ.


Trường hợp không hợp lệ

Partner tự tạo bảng:

CREATE TABLE planning_audit (

    id BIGINT,

    action VARCHAR(50)

);

→ Sai quy định vì:


Trường hợp bị cấm

Partner chạy trực tiếp:

DELETE FROM audit_log WHERE created_at < '2024-01-01';


→ Không được phép xóa dữ liệu audit.

6.6. Checklist áp dụng


Trước khi commit hoặc tạo PR:

Chương 2: Hướng dẫn phát triển (Developer)

7.API Design & Response Standard

7.1. Mục tiêu chương


Chương này quy định chuẩn API và định dạng response nhằm:

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


Quy định này áp dụng cho:

Mọi API phải tuân theo:

7.3. Quy định chính


7.3.1. Chuẩn Base Path

Tất cả API phải có dạng:

/api/v1/<module-name>

vd: http://localhost:8080/api/v1/auth/config

Trong đó:


Ví dụ base path hợp lệ

Module

Base path

auth

/api/v1/auth

planning

/api/v1/planning

document

/api/v1/document

user

/api/v1/user


7.3.2. Chuẩn Response

Tất cả API phải trả về:

ApiResponse<T>

image.png

Không được trả:

trực tiếp ra API.


Cấu trúc chuẩn của ApiResponse

Ví dụ:

{

  "success": true,

  "message": "OK",

  "data": {

    "id": 1,

    "name": "Test"

  }

}


Hoặc với danh sách:

{

  "success": true,

  "message": "OK",

  "data": [

    { "id": 1, "name": "A" },

    { "id": 2, "name": "B" }

  ]

}

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

Bước 1: Tạo controller theo base path

Ví dụ:

@RestController

@RequestMapping("/api/v1/planning")

public class PlanningController {

}



Bước 2: Service trả DTO

public PlanningResponse getById(Long id) {

    // xử lý nghiệp vụ

}



Bước 3: Controller trả ApiResponse

@GetMapping("/{id}")

public ApiResponse<PlanningResponse> getById(@PathVariable Long id) {

    return ApiResponse.ok(planningService.getById(id));

}

7.5. Ví dụ minh họa

Trường hợp sai

@GetMapping("/planning")

public List<PlanningEntity> getAll() {

    return planningRepository.findAll();

}


Sai vì:


Trường hợp đúng

@GetMapping

public ApiResponse<List<PlanningResponse>> getAll() {

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

}



Trường hợp sai về base path

@RequestMapping("/planning")


→ Sai vì thiếu:

/api/v1/

7.6. Checklist áp dụng


Trước khi commit hoặc tạo PR:

Chương 2: Hướng dẫn phát triển (Developer)

8. Cơ chế xác thực & tích hợp SSO (WSO2)

8.1. Mục tiêu chương


Quy định cơ chế xác thực linh hoạt giữa:

Nhằm:

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

Hai chế độ xác thực:

Chế độ

Mô tả

Local

Login nội bộ

WSO2

Login qua SSO OIDC

8.3. Quy định chính


Nguyên tắc chung

Logic xác thực nằm trong:

modules/auth

common/security


Cấu hình chế độ đăng nhập

auth.type = local

auth.type = wso2



Local Login


WSO2 SSO flow

  1. FE redirect sang WSO2

  2. User login

  3. WSO2 trả access_token

FE gọi BE với:

Authorization: Bearer <token>

  1. BE validate token


Quy tắc FE

Không được hardcode.


Quy tắc BE

Không hardcode user

8.4. Quy trình thêm FE mới vào SSO


  1. Partner cung cấp:

  2. Core tạo OAuth client

  3. Cấp client_id, scope

8.5. Checklist tích hợp xác thực


Chương 2: Hướng dẫn phát triển (Developer)

9.Git Workflow & Pull Request

Chú ý: tham chiếu sang tài liệu để theo dõi rõ ràng đầy đủ hơn:  https://docs.lifetex.vn/books/quy-dinh-git-workflow-va-quy-uoc-code c
9.1. Mục tiêu chương


Chương này quy định chuẩn commit và quy trình merge code nhằm:

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


Quy định này áp dụng cho:

Quy trình phát triển tuân theo:

Điều kiện merge bắt buộc

9.3. Quy định chính

9.3.1. Format commit

Tất cả commit phải theo format:

<type>: <description>


Trong đó:

Ví dụ commit hợp lệ

feat: add planning API

fix: validate file upload

refactor: optimize planning service

docs: update API guideline

test: add unit test for planning service

chore: update dependency versions


Type hợp lệ

Type

Ý nghĩa

feat

Thêm chức năng mới

fix

Sửa lỗi

refactor

Tối ưu, không đổi logic

docs

Cập nhật tài liệu

test

Thêm hoặc sửa test

chore

Thay đổi cấu hình, build, dependency


9.3.2. Branch strategy

Hệ thống sử dụng mô hình branch chuẩn:

Branch

Mục đích

main

Bản stable, dùng cho production

develop

Bản tích hợp, nơi merge các feature

feature/*

Phát triển chức năng mới

fix/*

Sửa lỗi


Quy tắc làm việc với branch


Ví dụ tên branch hợp lệ

feature/planning-create-api

feature/document-upload

fix/login-null-pointer

fix/planning-date-validation


9.3.3. Điều kiện merge Pull Request

Pull Request chỉ được merge khi đáp ứng đầy đủ các điều kiện:

  1. Build thành công

Không sửa:

common/**

config/**

  1. Không sửa shared entity

Có review từ Core Team

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


Quy trình phát triển tính năng

Bước 1: Tạo branch từ develop

git checkout develop

git pull

git checkout -b feature/planning-create-api


Bước 2: Thực hiện commit theo chuẩn

git commit -m "feat: add planning create API"


Bước 3: Push branch lên remote

git push origin feature/planning-create-api


Bước 4: Tạo Pull Request vào develop

Bước 5: Core Team review

Bước 6: Nếu đạt yêu cầu → merge vào develop


Quy trình sửa lỗi

Bước 1: Tạo branch fix

git checkout develop

git checkout -b fix/planning-null-error


Bước 2: Commit

git commit -m "fix: handle null planning name"


Bước 3: Tạo PR và chờ review

9.5. Ví dụ minh họa

Trường hợp commit sai

Sai vì:


Trường hợp commit đúng

fix: handle null planning name


Trường hợp merge sai

Partner:

→ Vi phạm quy trình.


Trường hợp merge đúng

  1. Tạo branch feature/planning-api

  2. Commit theo chuẩn

  3. Tạo PR vào develop

  4. Core Team review

  5. Build pass

  6. Merge

9.6. Checklist áp dụng


Trước khi tạo Pull Request:

Chương 2: Hướng dẫn phát triển (Developer)

10.Checklist kiểm tra trước khi merge

10.1. Mục tiêu chương


Chương này quy định checklist bắt buộc trước khi merge code nhằm:

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


Checklist này áp dụng cho:

Checklist được dùng trong:

Kiểm tra trước khi release

10.3. Quy định chính


Pull Request chỉ được phép merge khi đáp ứng đầy đủ các điều kiện sau:

Code nằm trong khu vực được phép:

modules/**

  1. Không sửa các khu vực bị cấm:


common/**

config/**

  1. Không sửa shared entity trong:


common/entity/**

  1. Nếu có thay đổi database:

  2. API phải đúng chuẩn:

/api/v1/<module-name>


  1. Response phải dùng:

ApiResponse<T>


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

Quy trình kiểm tra trước khi merge

Bước 1: Dev hoàn thành feature hoặc fix bug
Bước 2: Tạo Pull Request vào develop
Bước 3: Dev tự kiểm tra checklist
Bước 4: Core Team review theo checklist
Bước 5: Nếu đạt yêu cầu → merge

Nếu không đạt:

10.5. Ví dụ minh họa

Trường hợp hợp lệ

PR:

Chỉ sửa code trong:

modules/planning/**

→ Được merge.


Trường hợp không hợp lệ

PR:

Sửa file:

common/entity/UserEntity.java

→ Vi phạm quy định shared entity.

→ PR bị từ chối.


Trường hợp bị từ chối do thiếu migration

PR:

Thêm field trong entity:

private Integer priority;

→ PR bị reject.

10.6. Checklist áp dụng


Dev phải tick đủ các mục sau trước khi merge:

[ ] Code nằm trong modules/**

[ ] Không sửa common/**

[ ] Không sửa config/**

[ ] Không sửa shared entity

[ ] Có migration nếu thay đổi DB

[ ] API đúng chuẩn /api/v1/

[ ] Response dùng ApiResponse

[ ] Build thành công


Core Team chỉ merge khi checklist đạt đầy đủ.

Chương 2: Hướng dẫn phát triển (Developer)

11.Quy trình phối hợp & quản lý thay đổi liên nhóm

11.1. Mục tiêu chương


Chương này quy định cách phối hợp giữa nhiều đơn vị phát triển nhằm:

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


Áp dụng khi:

Mọi thay đổi liên quan:

đều phải thông qua Core Team.

11.3. Quy định chính

Nguyên tắc chung


Trường hợp FE và BE khác source, dùng chung DB

Rủi ro:

Quy định:

Quy trình:

  1. FE tạo ticket: API CONTRACT ISSUE

  2. BE/Core xác nhận

  3. Fix backward compatible hoặc tạo API v2


Trường hợp FE và BE dùng DB riêng khi dev

Quy định:

Quy trình:

  1. Nếu staging lỗi → so version migration

  2. Không cho merge nếu thiếu migration


Trường hợp nhiều FE dùng chung một BE

Quy định:

Quy trình:

  1. FE đăng ký client_id

  2. Core cấu hình redirectUri, scope

  3. Core cấp quyền


Trường hợp FE chung source, BE nhiều service

Quy định:

Quy trình:

  1. Thêm service → tạo Integration Checklist

  2. Core cấu hình CORS và token audience


Trường hợp thay đổi response làm FE vỡ

Quy định:

Quy trình:

  1. Tạo BREAKING CHANGE REQUEST

  2. Core duyệt

  3. Thông báo FE


Trường hợp xung đột entity/model

Quy định:

Quy trình:

  1. Partner đề xuất field + migration

  2. Core review

  3. Approve hoặc yêu cầu sửa


Trường hợp migration xung đột

Quy định:

Quy trình:

  1. Rebase

  2. Tạo migration mới

  3. Test staging


Trường hợp seed/master data bị sửa

Quy định:

Quy trình:

  1. Tạo MASTER DATA REQUEST

  2. Core duyệt và triển khai

11.4. Quy trình triển khai tính năng nhiều tầng


  1. Tạo ticket Feature

  2. Chốt API contract (OpenAPI)

  3. Chốt entity/migration

  4. BE implement

  5. FE integrate

  6. Test staging

  7. Release

11.5.Ví dụ minh họa


1. bảng mô tả các môi trường hệ thống:

Env FE URL BE URL DB Auth
dev http://localhost:4200 http://localhost:8080 local mock
staging https://staging.app.vn https://staging.api.vn shared WSO2 thật
prod https://app.vn https://api.vn prod WSO2 thật
Chương 2: Hướng dẫn phát triển (Developer)

12. Connect Database & mẫu CRUD & switch Oracle/MSSQL

12.Quy định kết nối Database và Message Queue

12.1. Mục tiêu chương


Chuẩn hóa kết nối DB và Message Queue nhằm:

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


Áp dụng cho:

12.3. Quy định chính

Kết nối Database

Cấu hình datasource tại:

config/**

application-*.yml


Message Queue

Cấu hình tại:

config/**

common/messaging/**

Partner không được:


Chuẩn đặt tên queue/topic

<system>.<module>.<purpose>

Ví dụ:

core.audit.log

planning.project.created

auth.user.synced

12.4. Quy trình tạo queue/topic


Tạo ticket:

[QUEUE REQUEST] <module> - <purpose>


  1. Cung cấp:

Core tạo queue và cấp quyền

12.5. Checklist DB & Queue


Database:

Queue:

13.1. Mục tiêu chương


Thiết kế kiến trúc đa database nhằm:

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


Áp dụng cho:

13.3. Quy định chính


Nguyên tắc thiết kế

db.vendor = oracle | mssql



Cấu trúc khuyến nghị

modules/<module>/

  controller/

  service/

  repository/

  query/

    QueryProvider.java

    OracleQueryProvider.java

    SqlServerQueryProvider.java

  entity/

  dto/



Quy định đa DB

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

Khi thay đổi nghiệp vụ

  1. Sửa Service

  2. Cập nhật query tương ứng trong provider


Khi khác DB

  1. Chỉ sửa query trong:

  2. Không sửa Service


Khi tạo Pull Request

PR phải:

13.5. Ví dụ minh họa

Cấu hình

db.vendor = mssql


Hệ thống tự inject:

SqlServerQueryProvider


image.png


Ví dụ sai

if (dbType.equals("oracle")) {

   // SQL

} else {

   // SQL

}


Sai vì logic DB nằm trong Service.


Ví dụ đúng

Service:

queryProvider.getFindAllPlanningSql();


QueryProvider quyết định SQL theo DB.

13.6. Checklist áp dụng


Chương 2: Hướng dẫn phát triển (Developer)

13.Swagger API Documentation & JWT Testing

13.1. Mục tiêu chương

Chương này quy định cách:

Mục tiêu:


13.2. Truy cập Swagger UI

Sau khi chạy service:


http://localhost:8080/swagger-ui/index.html

Hoặc:


http://localhost:8080/swagger-ui.html

Swagger hiển thị danh sách API theo controller.


13.3. Cấu hình Swagger trong Spring Boot

Dependency Maven:


<dependency> <groupId>org.springdoc</groupId> <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId> <version>2.7.0</version> </dependency>

13.3.1. Cấu hình OpenAPI + JWT

File:


config/OpenApiConfig.java

@Configuration public class OpenApiConfig { @Bean public OpenAPI api() { return new OpenAPI() .info(new Info() .title("Company Backend API") .version("v1.0") .description("API documentation")) .components(new Components() .addSecuritySchemes("bearerAuth", new SecurityScheme() .type(SecurityScheme.Type.HTTP) .scheme("bearer") .bearerFormat("JWT") ) ) .addSecurityItem(new SecurityRequirement().addList("bearerAuth")); } }

13.4. Đánh dấu API cần JWT trong Controller

Controller cần auth:


@RestController @RequestMapping("/api/v1/users") @SecurityRequirement(name = "bearerAuth") public class UserController {

Swagger sẽ hiển thị icon:


🔒 GET /api/v1/users

13.5. Cấu hình Spring Security cho Swagger

Swagger UI phải được phép truy cập không cần auth:


.requestMatchers( "/swagger-ui/**", "/swagger-ui.html", "/v3/api-docs/**" ).permitAll()

API business:


.anyRequest().authenticated()

13.6. Test API có JWT trên Swagger (Step-by-Step)

Bước 1. Login lấy JWT

Gọi API login:


POST /api/v1/auth/login

Response:


{ "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." }

Bước 2. Mở Swagger


http://localhost:8080/swagger-ui/index.html

Bước 3. Click Authorize

Góc phải Swagger:


Authorize 🔒

Click vào.


Bước 4. Nhập JWT

Nhập:


Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

Lưu ý:

Ví dụ đúng:


Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9

Bước 5. Authorize

Click:


Authorize

Swagger sẽ lưu token cho toàn bộ API.


Bước 6. Test API

Chọn API có 🔒:


GET /api/v1/theme-config

Click:


Execute

Swagger gửi request:


Authorization: Bearer eyJhbGciOiJIUzI1Ni...

13.7. Kiểm tra Swagger đã gửi token chưa

Trong Swagger phần Curl phải có:


-H "Authorization: Bearer eyJhbGciOiJIUzI1Ni..."

Nếu không có → chưa Authorize.


13.8. Lỗi thường gặp

403 Forbidden

Nguyên nhân:


Không thấy nút Authorize

Nguyên nhân:

Khắc phục:


Ctrl + F5

Swagger call được API không cần token

Nguyên nhân:

Security config permitAll API.

Ví dụ:


.requestMatchers("/api/v1/**").permitAll()

Swagger không cần JWT.


13.9. Quy định chuẩn sử dụng Swagger trong dự án

Controller cần auth:


@SecurityRequirement(name = "bearerAuth")

Controller public:

không cần annotation.


API test phải:


13.10. Quy định commit & PR

API mới phải:

PR bị reject nếu:


13.11. Checklist Swagger cho Dev

Trước khi merge:


13.12. Best Practice

Không permitAll API production.

Swagger chỉ permit:


/swagger-ui/** /v3/api-docs/**

JWT luôn test qua Authorize.

Chương 3: Triển khai hệ thống (Deploy)

Chương này hướng dẫn quy trình build và triển khai ứng dụng Java (Spring Boot) lên các môi trường dev/staging/production. Bao gồm chuẩn bị hạ tầng, build artifact (JAR), cấu hình biến môi trường, chạy ứng dụng dạng service hoặc Docker container, cấu hình reverse proxy (Nginx), database migration và kiểm tra sau triển khai. Mục tiêu đảm bảo ứng dụng chạy ổn định, có thể giám sát và rollback khi cần.

Chương 3: Triển khai hệ thống (Deploy)

Hướng dẫn chi tiết

1. Yêu cầu hạ tầng

Server tối thiểu

Cài Java:


sudo apt update sudo apt install openjdk-17-jdk -y java -version

2. Build ứng dụng

Build bằng Maven

mvn clean package -DskipTests

Artifact tạo ra:

target/app.jar

 

Chương 4: Kiểm thử đơn vị (Unit Test)

Chương này hướng dẫn cách viết unit test cho API trong ứng dụng Java Spring Boot. Nội dung bao gồm cấu trúc test chuẩn, cách mock dependency, kiểm tra validate input, xác thực (authentication/authorization), ghi log, xử lý exception và kiểm tra logic service. Mục tiêu đảm bảo mỗi API hoạt động đúng, an toàn và ổn định trước khi tích hợp hoặc triển khai.

Chương 4: Kiểm thử đơn vị (Unit Test)

Nội dung chi tiết

 

1. Nguyên tắc Unit Test API

Mỗi API cần test các nhóm case cơ bản:

  1. Validate input

  2. Auth / permission

  3. Business logic

  4. Repository interaction

  5. Exception handling

  6. Logging

  7. HTTP status & response


2. Ví dụ API mẫu

Controller:


@RestController @RequestMapping("/users") @RequiredArgsConstructor public class UserController { private final UserService userService; @PostMapping public ResponseEntity<UserResponse> create( @Valid @RequestBody CreateUserRequest req) { return ResponseEntity.ok(userService.create(req)); } }

DTO:


@Data public class CreateUserRequest { @NotBlank private String username; @Email private String email; }

Service:


@Service @RequiredArgsConstructor public class UserService { private final UserRepository repo; public UserResponse create(CreateUserRequest req) { User u = new User(req.getUsername(), req.getEmail()); repo.save(u); return new UserResponse(u.getId(), u.getUsername()); } }

3. Cấu trúc test chuẩn

Dependency:


<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency>

Controller test dùng:


4. Test Validate Input

Case cần có:


@WebMvcTest(UserController.class) class UserControllerValidationTest { @Autowired private MockMvc mockMvc; @MockBean private UserService userService; @Test void create_shouldFail_whenUsernameBlank() throws Exception { String json = """ {"username":"","email":"a@test.com"} """; mockMvc.perform(post("/users") .contentType(MediaType.APPLICATION_JSON) .content(json)) .andExpect(status().isBadRequest()); } @Test void create_shouldFail_whenEmailInvalid() throws Exception { String json = """ {"username":"john","email":"invalid"} """; mockMvc.perform(post("/users") .contentType(MediaType.APPLICATION_JSON) .content(json)) .andExpect(status().isBadRequest()); } }

5. Test Auth / Permission

Giả sử API cần login:


@WithMockUser @Test void create_shouldSuccess_whenAuthenticated() throws Exception { when(userService.create(any())) .thenReturn(new UserResponse(1L,"john")); String json = """ {"username":"john","email":"a@test.com"} """; mockMvc.perform(post("/users") .contentType(MediaType.APPLICATION_JSON) .content(json)) .andExpect(status().isOk()); }

Test chưa login:


@Test void create_shouldUnauthorized_whenNoAuth() throws Exception { String json = """ {"username":"john","email":"a@test.com"} """; mockMvc.perform(post("/users") .contentType(MediaType.APPLICATION_JSON) .content(json)) .andExpect(status().isUnauthorized()); }

6. Test Business Logic (Service)


@ExtendWith(MockitoExtension.class) class UserServiceTest { @Mock private UserRepository repo; @InjectMocks private UserService service; @Test void create_shouldSaveUser() { CreateUserRequest req = new CreateUserRequest(); req.setUsername("john"); req.setEmail("a@test.com"); when(repo.save(any())).thenAnswer(i -> i.getArgument(0)); UserResponse res = service.create(req); assertEquals("john", res.getUsername()); verify(repo).save(any()); } }

7. Test Exception Handling

Giả sử email trùng:


when(repo.save(any())) .thenThrow(new DataIntegrityViolationException("dup"));

Test:


@Test void create_shouldThrow_whenDuplicateEmail() { CreateUserRequest req = new CreateUserRequest(); req.setUsername("john"); req.setEmail("a@test.com"); when(repo.save(any())) .thenThrow(new RuntimeException("duplicate")); assertThrows(RuntimeException.class, () -> service.create(req)); }

8. Test Logging

Giả sử service có log:


log.info("Create user {}", req.getUsername());

Test log:


@ExtendWith(MockitoExtension.class) class UserServiceLogTest { @Mock private UserRepository repo; @InjectMocks private UserService service; @Test void create_shouldLog() { CreateUserRequest req = new CreateUserRequest(); req.setUsername("john"); req.setEmail("a@test.com"); when(repo.save(any())).thenAnswer(i -> i.getArgument(0)); service.create(req); verify(repo).save(any()); } }

(Thực tế có thể dùng LogCaptor)


9. Test HTTP Response


@Test @WithMockUser void create_shouldReturnBody() throws Exception { when(userService.create(any())) .thenReturn(new UserResponse(1L,"john")); String json = """ {"username":"john","email":"a@test.com"} """; mockMvc.perform(post("/users") .contentType(MediaType.APPLICATION_JSON) .content(json)) .andExpect(status().isOk()) .andExpect(jsonPath("$.username").value("john")); }

10. Danh sách Case chuẩn cho mỗi API

Mỗi API cần tối thiểu:

Validate

Auth

Business

Repository

Exception

Response

Log

 


11. Checklist Unit Test API

Chương 5: Đóng gói & phát hành (Packaging)

Chương này hướng dẫn cách đóng gói dự án thành artifact phát hành (jar, docker image, bundle web…), đặt version, ghi changelog, ký số (nếu có) và lưu trữ trên repository. Kết quả là gói cài đặt sẵn sàng để triển khai hoặc phân phối.

Chương 6: Sử dụng AI agent skill

chương này hướng dẫn cách hoạt động và sử dụng AI để thực hiện các tác vụ về tạo mới api

Chương 6: Sử dụng AI agent skill

Nội dung chi tiết

1. Cài đặt ban đầu — Clone thư mục .agent

Trước khi sử dụng skill, bạn cần clone repository cấu hình về thư mục gốc của project bằng lệnh sau:

git clone -b master http://192.168.0.95/minhnd/chat-gpt-agent.git .agent

Lệnh trên sẽ tải branch master và đặt toàn bộ nội dung vào thư mục .agent ngay trong thư mục hiện tại của bạn.

Lưu ý: Chạy lệnh này tại thư mục gốc (root) của project, không phải bên trong thư mục con nào khác.

2. Hướng dẫn cài đặt Google Antigravity Truy cập link sau https://antigravity.google/download

 

Sau đó cài đặt như bình thường.

3. Mục tiêu của Skill

Skill này được thiết kế để:

• Chuẩn hóa cấu trúc dự án Spring Boot.

• Đảm bảo tính nhất quán (Consistency) giữa các module.

• Tự động hóa việc ra quyết định về kiến trúc (Layered Architecture).

• Tuân thủ các quy tắc bảo mật và lưu vết (Audit log).

4. Cách kích hoạt (Activation)

Skill này hoạt động hoàn toàn TỰ ĐỘNG khi project có thư mục cấu hình .agent.

Cơ chế: Khi bạn gửi yêu cầu (ví dụ: "Tạo API User"), hệ thống nhận diện .agent, kích hoạt @backend-specialist và tự động áp dụng các quy chuẩn trong skill api-processing-flow.

Lưu ý: Bạn không cần copy nội dung skill vào chatbot, chỉ cần đảm bảo thư mục .agent nằm trong project.

 

 

5. Các Quy tắc "Vàng" (Mandatory Rules)

Cần tuân thủ 5 quy tắc bắt buộc sau khi viết code:

1. Kiến trúc 3 lớp: Luôn tuân theo luồng Controller -> Service -> Repository.

2. Không Logic ở Controller: Controller chỉ nhận request, check validation cơ bản và gọi Service.

3. ApiResponse Standard: Mọi API phải trả về object ApiResponse<T>. Không trả về trực tiếp DTO hay Entity.

4. DTO vs Entity: Tuyệt đối không trả về Entity cho Client. Luôn dùng DTO cho Request và Response.

5. In-memory Storage: Dùng ConcurrentHashMap hoặc List trong Repository nếu chưa có Database bên ngoài.

5b. Cấu trúc Module chuẩn

Mỗi module mới khi tạo ra phải có cấu trúc thư mục như sau:

modules/<module-name>/

+-- controller/ (Chua @RestController)

+-- service/ (Chua Business Logic & Interface)

+-- repository/ (Chua truy van du lieu)

+-- entity/ (Chua mapping du lieu)

+-- dto/ (Chua Request/Response models)

 

6. Quy trình phát triển 5 bước (API Workflow)

Để tạo một tính năng mới, hãy đi theo trình tự:

6. B1: Tạo DTO: Định nghĩa Request và Response model.

7. B2: Tạo Entity: Định nghĩa cấu trúc dữ liệu mapping.

8. B3: Tạo Repository: Định nghĩa các phương thức lưu trữ dữ liệu.

9. B4: Tạo Service: Viết Business Logic (Xử lý dữ liệu, chuyển đổi Entity <-> DTO).

10. B5: Tạo Controller: Khai báo Endpoint và gọi Service.

7. Coding Convention (Quy tắc đặt tên)

Bảng quy ước đặt tên các thành phần trong dự án:

Thành phần Quy tắc đặt tên Ví dụ

Controller <n>Controller UserController

Service <n>Service UserService

Repository <n>Repository UserRepository

Entity <n>Entity UserEntity

DTO Request <n>CreateRequest UserCreateRequest

DTO Response <n>Response UserResponse

 

8. Ví dụ một phương thức Service chuẩn

Dưới đây là cấu trúc chuẩn của một phương thức trong Service layer:

public UserResponse create(UserCreateRequest request) {

 

// 1. Validate (Kiem tra du lieu)

if (repo.existsByUsername(request.getUsername())) {

throw new BusinessException(ErrorCode.USER_EXISTS);

}

 

// 2. Log (Luu vet hanh dong)

log.info("Creating user: {}", request.getUsername());

 

// 3. Business logic (Xu ly)

UserEntity entity = mapper.toEntity(request);

repo.save(entity);

 

// 4. Return (Tra ve ket qua)

return mapper.toResponse(entity);

}

10. Cơ chế hoạt động

Thư mục .agent (Antigravity Kit) đóng vai trò là "bộ não" và hệ thống điều hành của trợ lý AI trong dự án. Nó chứa các định nghĩa về vai trò, kỹ năng, quy trình làm việc và các kịch bản tự động hóa đảm bảo chất lượng code.

11. Cấu trúc thư mục .agent

Cấu trúc chuẩn của thư mục .agent:

.agent/

+-- rules/

| +-- GEMINI.md # Quy tắc tối cao(P0), định nghĩa hành vi cơ bản

+-- agents/ # Danh sách 20 Agent(Personas)

+-- skills/ # Các kỹ năng mo-dun hóa (Domain knowledge)

+-- workflows/ # Quy trình làm việc (/plan, /create, /debug...)

+-- scripts/ # Các kịch bản kiểm tra và tự động hóa master

+-- ARCHITECTURE.md # Bản đồ tổng thể hế thống Agent

+-- tasks/ # Lưu trữ tài liệu và các tác vụ({task-slug}.md)

 

12. Luồng xử lý — Từ yêu cầu đến code

Mỗi yêu cầu gõ vào chạy qua đúng 6 cổng theo thứ tự sau. Không cổng nào bị bỏ qua:

[USER INPUT]

|

v

[1] Request Classifier <- rules/GEMINI.md doc vao dau tien

| QUESTION --> trả lời thẳng,kết thúc.

| SIMPLE CODE --> chuyển sang bước 2.

| COMPLEX --> tạo tasks/{task-slug}.md rồi mới sang bước 2.

v

[2] Agent Routing <- đọc agents/ chọn đúng agent

| ví dụ: viết API --> @backend-specialist

| viết UI --> @frontend-specialist

| kiểm tra sec --> @security-auditor

v

[3] Modular Skill Loading <- chỉ đọc skills/ cần thiết, không đọc hết

| ví dụ: @backend + API --> skills/api-patterns + nodejs-best-practices

| mọi folder Skill gồm: SKILL.md (hướng dẫn) + scripts/ (công cụ)

v

[4] Rule Priority Check <- áp dụng theo thứ tự P0 > P1 > P2

| P0: rules/GEMINI.md (Toàn cục -cao nhất, không thể override)

| P1: agents/{agent}.md (quy tắc riêng của Specialist)

| P2: skills/{skill}.md (kỹ thuật cụ thể cửa Skill được nạp)

v

[5] Socratic Gate <- chỉ áp dụng với COMPLEX CODE

| AI hỏi >= 3 câu trước khi viết bất kỳ dòng code nào:

| - Mục tiêu chính là gì?

| - Edge cases nào cần xử lý?

| - Ràng buộc kiến trúc/công nghệ?

v

[6] Implementation & Validation <- viết code + tự động kiểm tra

| Viết code: Clean Code + TDD

| scripts/checklist.py --> Bảo mật, Lint, Schema, UX (nhanh)

| scripts/verify_all.py --> E2E, Performance, SEO (truoc deploy)

v

[OUTPUT] Code đạt chuẩn, đã quan kiểm tra, sẵn sàng review.

 

13. Các lệnh Slash Commands phổ biến

Hệ thống hỗ trợ các quy trình chuẩn hóa thông qua lệnh /. Gõ trực tiếp trong chat để kích hoạt:

/plan — Lập kế hoạch chi tiết, chia nhỏ tác vụ (không viết code).

/create — Bắt đầu tạo một tính năng hoặc ứng dụng mới.

/debug — Kích hoạt chế độ kiểm tra lỗi hệ thống 4 giai đoạn.

/orchestrate — Phối hợp nhiều chuyên gia để giải quyết vấn đề đa chiều.

/status — Kiểm tra tiến độ và trạng thái hiện tại của dự án.

 

Ghi chú: Mọi thay đổi đối với cấu trúc hệ thống Agent nên được thực hiện thông qua việc cập nhật các file trong .agent để đảm bảo AI luôn cập nhật được “tư duy” mới nhất.