331 lines
9.2 KiB
Markdown
331 lines
9.2 KiB
Markdown
# Hướng Dẫn Development
|
|
|
|
Hướng dẫn toàn diện về tiêu chuẩn và quy trình đóng góp vào GoodGo Microservices Platform.
|
|
|
|
## Mục lục
|
|
|
|
1. [Cấu Trúc Dự Án](#cấu-trúc-dự-án)
|
|
2. [Tiêu Chuẩn Code](#tiêu-chuẩn-code)
|
|
3. [Quy Trình Git](#quy-trình-git)
|
|
4. [Phát Triển Backend](#phát-triển-backend)
|
|
5. [Chiến Lược Testing](#chiến-lược-testing)
|
|
6. [Quy Trình Database](#quy-trình-database)
|
|
7. [Triển Khai Kubernetes](#triển-khai-kubernetes)
|
|
|
|
---
|
|
|
|
## Cấu Trúc Dự Án
|
|
|
|
Chúng tôi tuân theo cấu trúc monorepo quản lý bởi PNPM Workspaces.
|
|
|
|
```
|
|
Base/
|
|
apps/ # Ứng dụng Frontend
|
|
web-client/ # Next.js 14+ (App Router)
|
|
mobile-client/ # Flutter
|
|
services/ # Backend microservices
|
|
_template/ # Template cho service mới
|
|
iam-service/ # Identity & Access Management
|
|
...
|
|
packages/ # Thư viện chia sẻ
|
|
logger/ # Structured logging (Winston)
|
|
types/ # DTOs & Interfaces chia sẻ
|
|
http-client/ # Internal Service Client
|
|
tracing/ # Cấu hình OpenTelemetry
|
|
infra/ # Infrastructure-as-Code
|
|
traefik/ # API Gateway
|
|
databases/ # Scripts thiết lập Database
|
|
docs/ # Tài liệu (EN & VI)
|
|
```
|
|
|
|
---
|
|
|
|
## Tiêu Chuẩn Code
|
|
|
|
### Quy ước Đặt tên
|
|
|
|
* **Files**: `kebab-case.ts` (ví dụ: `user.controller.ts`, `app.config.ts`)
|
|
* **Classes**: `PascalCase` (ví dụ: `UserController`, `AuthService`)
|
|
* **Functions/Variables**: `camelCase` (ví dụ: `getUserById`, `isValid`)
|
|
* **Constants**: `UPPER_SNAKE_CASE` (ví dụ: `MAX_RETRIES`, `DEFAULT_TIMEOUT`)
|
|
* **Interfaces**: `PascalCase` (ví dụ: `User`, `CreateUserDto`) - *Không dùng tiền tố 'I'*
|
|
|
|
### Bilingual Comments (Bình luận Song ngữ)
|
|
|
|
Đối với logic cốt lõi và public APIs, giả định cả lập trình viên quốc tế và Việt Nam đều đọc code.
|
|
|
|
```typescript
|
|
/**
|
|
* EN: Validates user credentials and returns a token
|
|
* VI: Xác thực thông tin người dùng và trả về token
|
|
*/
|
|
async login(dto: LoginDto): Promise<TokenResponse> { ... }
|
|
```
|
|
|
|
### TypeScript Usage
|
|
|
|
* **Strict Mode**: Được bật trong `tsconfig.json`. Không cho phép `any` (dùng `unknown` nếu cần).
|
|
* **DTOs**: Sử dụng Zod để runtime validation và type inference.
|
|
* **Return Types**: Khai báo rõ ràng kiểu trả về cho tất cả public methods.
|
|
|
|
---
|
|
|
|
## Quy Trình Git
|
|
|
|
### Chiến lược Nhánh (Branching Strategy)
|
|
|
|
* `main`: Code production-ready.
|
|
* `develop`: Nhánh integration cho release tiếp theo.
|
|
* `feature/xyz`: Tính năng mới (tách từ `develop`).
|
|
* `fix/xyz`: Sửa lỗi (tách từ `develop`).
|
|
* `hotfix/xyz`: Sửa lỗi nghiêm trọng (tách từ `main`).
|
|
|
|
```mermaid
|
|
gitGraph
|
|
commit id: "Initial"
|
|
branch develop
|
|
checkout develop
|
|
commit id: "Setup"
|
|
|
|
branch feature/login
|
|
checkout feature/login
|
|
commit id: "Add login form"
|
|
commit id: "Add validation"
|
|
checkout develop
|
|
merge feature/login
|
|
|
|
branch feature/dashboard
|
|
checkout feature/dashboard
|
|
commit id: "Create dashboard"
|
|
checkout develop
|
|
|
|
checkout main
|
|
merge develop tag: "v1.0.0"
|
|
|
|
checkout develop
|
|
merge feature/dashboard
|
|
|
|
checkout main
|
|
branch hotfix/security
|
|
commit id: "Fix security issue"
|
|
checkout main
|
|
merge hotfix/security tag: "v1.0.1"
|
|
checkout develop
|
|
merge hotfix/security
|
|
```
|
|
|
|
### Commit Messages
|
|
|
|
Chúng tôi tuân theo [Conventional Commits](https://www.conventionalcommits.org/):
|
|
|
|
```
|
|
feat(iam): add multi-factor authentication
|
|
fix(db): correct unique constraint on email
|
|
docs(guide): update development setup
|
|
style: format code with prettier
|
|
refactor: simplify auth middleware
|
|
test: add unit tests for user service
|
|
chore: update dependencies
|
|
```
|
|
|
|
---
|
|
|
|
## Phát Triển Backend
|
|
|
|
```mermaid
|
|
graph TD
|
|
Start([Bắt đầu tạo API mới]) --> DTO[1. Định nghĩa DTO - Zod Schema]
|
|
DTO --> Repo[2. Tạo Repository Method]
|
|
Repo --> Service[3. Tạo Service Method - Business Logic]
|
|
Service --> Controller[4. Tạo Controller - HTTP Handler]
|
|
Controller --> Route[5. Đăng ký Route - Express Router]
|
|
Route --> Middleware[6. Thêm Middlewares]
|
|
Middleware --> Test[7. Viết Tests]
|
|
Test --> Done([API hoàn thành])
|
|
|
|
Service --> ErrorCheck{Có lỗi?}
|
|
ErrorCheck -->|Có| ThrowError[Throw HttpError]
|
|
ThrowError --> ErrorHandler[Global Error Handler]
|
|
ErrorHandler --> Response[Error Response]
|
|
ErrorCheck -->|Không| Success[Success Response]
|
|
|
|
style Start fill:#1e3a2e,color:#4ade80,stroke:#4ade80,stroke-width:3px
|
|
style Done fill:#1e3a2e,color:#4ade80,stroke:#4ade80,stroke-width:3px
|
|
style DTO fill:#1e293b,color:#60a5fa
|
|
style Repo fill:#1e293b,color:#3b82f6
|
|
style Service fill:#2e1a47,color:#a78bfa
|
|
style Controller fill:#2d1b0e,color:#fb923c
|
|
style Route fill:#1e293b,color:#3b82f6
|
|
style Middleware fill:#1e293b,color:#60a5fa
|
|
style Test fill:#1e3a2e,color:#4ade80
|
|
style ErrorCheck fill:#2d1b0e,color:#fb923c
|
|
style ThrowError fill:#3f1a1a,color:#f87171
|
|
style ErrorHandler fill:#3f1a1a,color:#f87171
|
|
style Response fill:#27272a,color:#a1a1aa
|
|
style Success fill:#1e3a2e,color:#4ade80
|
|
```
|
|
|
|
### Tạo API Endpoint Mới
|
|
|
|
1. **Định nghĩa DTO** (`modules/user/user.dto.ts`):
|
|
```typescript
|
|
export const CreateUserDto = z.object({
|
|
email: z.string().email(),
|
|
name: z.string().min(2),
|
|
});
|
|
export type CreateUserDto = z.infer<typeof CreateUserDto>;
|
|
```
|
|
|
|
2. **Tạo Service Method** (`modules/user/user.service.ts`):
|
|
* Implement business logic.
|
|
* Sử dụng `BaseRepository`.
|
|
* Throw `HttpError` (ví dụ: `NotFound`, `BadRequest`).
|
|
|
|
3. **Tạo Controller** (`modules/user/user.controller.ts`):
|
|
* Parse body với DTO: `const dto = CreateUserDto.parse(req.body)`.
|
|
* Gọi service.
|
|
* Trả về success response: `res.json({ success: true, data: result })`.
|
|
|
|
4. **Đăng ký Route** (`modules/user/index.ts`):
|
|
* Thêm vào Express router cùng middlewares.
|
|
|
|
### Xử lý Lỗi (Error Handling)
|
|
|
|
Luôn sử dụng các class lỗi tùy chỉnh từ `core/errors`:
|
|
|
|
```typescript
|
|
import { NotFoundError, ConflictError } from '../../core/errors';
|
|
|
|
if (!user) {
|
|
throw new NotFoundError('User not found');
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Chiến Lược Testing
|
|
|
|
```mermaid
|
|
graph TB
|
|
subgraph "Testing Pyramid - Từ dưới lên"
|
|
Unit[Unit Tests - Nhiều nhất, Nhanh nhất]
|
|
Integration[Integration Tests - Trung bình]
|
|
E2E[E2E Tests - Ít nhất, Chậm nhất]
|
|
end
|
|
|
|
Code[Code Changes] --> CheckLint{Lint Pass?}
|
|
CheckLint -->|Không| FixLint[Fix Linting Errors]
|
|
FixLint --> CheckLint
|
|
CheckLint -->|Có| RunUnit[Run Unit Tests]
|
|
|
|
RunUnit --> UnitPass{Unit Tests Pass?}
|
|
UnitPass -->|Không| FixUnit[Fix Unit Tests]
|
|
FixUnit --> RunUnit
|
|
UnitPass -->|Có| RunIntegration[Run Integration Tests]
|
|
|
|
RunIntegration --> IntPass{Integration Pass?}
|
|
IntPass -->|Không| FixIntegration[Fix Integration]
|
|
FixIntegration --> RunIntegration
|
|
IntPass -->|Có| RunE2E[Run E2E Tests]
|
|
|
|
RunE2E --> E2EPass{E2E Pass?}
|
|
E2EPass -->|Không| FixE2E[Fix E2E]
|
|
FixE2E --> RunE2E
|
|
E2EPass -->|Có| Coverage{Coverage > 70%?}
|
|
|
|
Coverage -->|Không| AddTests[Add More Tests]
|
|
AddTests --> RunUnit
|
|
Coverage -->|Có| ReadyMerge[Ready to Merge]
|
|
|
|
style Unit fill:#1e3a2e,color:#4ade80
|
|
style Integration fill:#1e293b,color:#60a5fa
|
|
style E2E fill:#2e1a47,color:#a78bfa
|
|
style Code fill:#1e293b,color:#3b82f6
|
|
style CheckLint fill:#2d1b0e,color:#fb923c
|
|
style UnitPass fill:#1e3a2e,color:#4ade80
|
|
style IntPass fill:#1e293b,color:#60a5fa
|
|
style E2EPass fill:#2e1a47,color:#a78bfa
|
|
style Coverage fill:#2d1b0e,color:#fbbf24
|
|
style RunUnit fill:#1e3a2e,color:#4ade80
|
|
style RunIntegration fill:#1e293b,color:#60a5fa
|
|
style RunE2E fill:#2e1a47,color:#a78bfa
|
|
style ReadyMerge fill:#1e3a2e,color:#4ade80,stroke:#4ade80,stroke-width:3px
|
|
style FixLint fill:#3f1a1a,color:#f87171
|
|
style FixUnit fill:#3f1a1a,color:#f87171
|
|
style FixIntegration fill:#3f1a1a,color:#f87171
|
|
style FixE2E fill:#3f1a1a,color:#f87171
|
|
style AddTests fill:#2d1b0e,color:#fbbf24
|
|
```
|
|
|
|
### Unit Tests (`*.test.ts`)
|
|
|
|
* **Phạm vi**: Các class/function đơn lẻ.
|
|
* **Mocking**: Mock tất cả dependencies bên ngoài (DB, services khác) dùng `jest-mock-extended`.
|
|
* **Vị trí**: Đặt cùng thư mục với file source.
|
|
* **Chạy**: `pnpm test`
|
|
|
|
### E2E Tests (`tests/**/*.e2e.ts`)
|
|
|
|
* **Phạm vi**: Full API flows (Controller -> Service -> DB).
|
|
* **Database**: Sử dụng test database riêng biệt (Dockerized).
|
|
* **Chạy**: `pnpm test:e2e`
|
|
|
|
### Linting & Formatting
|
|
|
|
* **Lint**: `pnpm lint` (ESLint)
|
|
* **Format**: `pnpm format` (Prettier)
|
|
* **Typecheck**: `pnpm typecheck` (TSC)
|
|
|
|
---
|
|
|
|
## Quy Trình Database
|
|
|
|
Chúng tôi sử dụng **Prisma** với **Neon PostgreSQL**.
|
|
|
|
### Migrations
|
|
|
|
1. Sửa `prisma/schema.prisma`.
|
|
2. Tạo migration (Dev):
|
|
```bash
|
|
./scripts/db/migrate.sh iam-service dev --name add_user_profile
|
|
```
|
|
3. Áp dụng cho Production (CI/CD):
|
|
```bash
|
|
./scripts/db/migrate.sh iam-service deploy
|
|
```
|
|
|
|
### Seed Data
|
|
|
|
Nạp dữ liệu mẫu vào database:
|
|
```bash
|
|
./scripts/db/seed.sh iam-service
|
|
```
|
|
|
|
### Xem Dữ liệu Trực quan
|
|
|
|
Sử dụng Prisma Studio:
|
|
```bash
|
|
pnpm --filter @goodgo/iam-service prisma studio
|
|
```
|
|
|
|
---
|
|
|
|
## Triển Khai Kubernetes
|
|
|
|
Để test Kubernetes cục bộ (Docker Desktop / Minikube):
|
|
|
|
```bash
|
|
# 1. Build images
|
|
docker build -t goodgo/iam-service:latest -f services/iam-service/Dockerfile .
|
|
|
|
# 2. Deploy
|
|
cd deployments/local/kubernetes
|
|
./deploy.sh
|
|
|
|
# 3. Xác minh
|
|
kubectl get pods -n iam-local
|
|
kubectl logs -f -l app=iam-service -n iam-local
|
|
```
|
|
|
|
Xem [Hướng Dẫn Kubernetes](./kubernetes-local.md) để biết chi tiết.
|