# Hướng Dẫn Đóng Góp

## Quy Trình Git & Branching

### Nhánh Chính

| Nhánh | Mục đích | Protected |
|-------|---------|-----------|
| `main` / `master` | Production branch — stable releases | ✅ Yes |
| `develop` | Development branch — integration point | ✅ Yes |
| `feature/*` | Feature branches — phát triển tính năng mới | ❌ No |
| `fix/*` | Bug fix branches | ❌ No |
| `docs/*` | Documentation updates | ❌ No |
| `refactor/*` | Code refactoring, cleanup | ❌ No |

### Quy Trình Tạo Feature Branch

```bash
# 1. Cập nhật branch chính
git checkout develop
git pull origin develop

# 2. Tạo feature branch
git checkout -b feature/awesome-feature

# Naming convention:
# feature/user-authentication
# fix/csrf-middleware-double-middleware
# docs/api-documentation
# refactor/remove-dead-code
```

### Pull Request Workflow

```bash
# 1. Commit changes
git add .
git commit -m "feat(auth): implement phone OTP login"

# 2. Push to origin
git push origin feature/awesome-feature

# 3. Open PR on GitHub
# - Title: Short summary (max 70 chars)
# - Description: Why, what changed, how to test
# - Link related issues: Fixes #GOO-7
# - Request reviewers: team lead, domain expert

# 4. Address review feedback
git add .
git commit -m "refactor(auth): address PR feedback"
git push

# 5. Merge when approved
# - Squash commits if many small fixes
# - Delete branch after merge
```

### Protected Branch Rules

`main` và `develop` branches yêu cầu:

- ✅ All CI checks pass (lint, typecheck, test, build)
- ✅ 1 approval từ code owner
- ✅ Dismiss stale PR approvals
- ✅ Branches must be up to date before merge
- ❌ Force push không được phép

---

## Quy Ước Commit

Theo chuẩn **[Conventional Commits](https://www.conventionalcommits.org/)**:

```
<type>(<scope>): <subject>

<body>

<footer>
```

### Loại Commit (Type)

| Type | Mục đích | Ví dụ |
|------|---------|-------|
| **feat** | Tính năng mới | `feat(auth): add phone OTP login` |
| **fix** | Bug fix | `fix(csrf): remove double middleware` |
| **docs** | Tài liệu | `docs(readme): update setup instructions` |
| **style** | Code style (không thay đổi logic) | `style(payment): format code` |
| **refactor** | Refactor code | `refactor(search): extract filter logic` |
| **perf** | Performance improvement | `perf(search): add Typesense caching` |
| **test** | Test changes | `test(auth): add OTP verification tests` |
| **chore** | Dependencies, build, etc | `chore(deps): upgrade TypeScript 5.2` |

### Scope

Scope là module/area bị ảnh hưởng:

```
feat(auth): ...       # Auth module
feat(payments): ...   # Payments module
feat(api): ...        # General API
feat(web): ...        # Frontend
feat(deps): ...       # Dependencies
```

### Subject (Tiêu đề)

- ✅ Bắt đầu bằng **verb** (not past tense): "add", "fix", "remove"
- ✅ Viết **lowercase** (trừ proper nouns)
- ✅ **Không kết thúc** bằng dấu chấm
- ✅ Tối đa **50 ký tự**
- ❌ Không dùng "update", "change" — cụ thể hơn

### Body (Chi tiết)

Tùy chọn, giải thích **why** và **how**:

```
feat(payments): implement MoMo IPN webhook

Fix MoMo IPN callback to use correct backend URL instead of frontend URL.

- Extract ipnUrl from redirectUrl in MoMo service
- Validate HMAC signature before processing payment
- Add retry logic for idempotent callbacks

Fixes #GOO-6
```

### Footer (Tham chiếu)

Tham chiếu issue:

```
Fixes #GOO-7
Closes #GOO-8
Related to #GOO-5
```

### Ví dụ Hoàn Chỉnh

```
feat(auth): implement phone OTP login flow

Add phone OTP as primary login method for Vietnamese users.
Simplifies sign-up process vs password login.

- Add OTP request endpoint: POST /auth/otp/request
- Add OTP verify endpoint: POST /auth/otp/verify
- Store OTP in Redis with 5min expiry
- Prevent brute force: max 3 attempts per phone per hour
- Add unit tests for OTP generation and verification

Fixes #GOO-11
Co-Authored-By: Paperclip <noreply@paperclip.ing>
```

### Kiểm Tra Commit Message

Dùng `husky` pre-commit hook:

```bash
# Tự động chạy khi git commit
# Kiểm tra:
# - Format conventional commits
# - No secrets (API keys, passwords)
# - Lint, typecheck

# Nếu hook thất bại, fix và commit lại
```

---

## Pull Request Template

```markdown
## Summary
Một dòng mô tả PR (tương tự commit subject).

## Changes
- Điểm thay đổi 1
- Điểm thay đổi 2
- Điểm thay đổi 3

## Testing
- [ ] Unit tests written
- [ ] E2E tests written (if applicable)
- [ ] Manual testing: describe steps
- [ ] No regressions found

## Screenshots / Logs (if applicable)
Paste images or log outputs.

## Related Issues
Fixes #GOO-7
Related to #GOO-5

## Notes for Reviewers
- Pay attention to X because Y
- Known limitations: Z
```

---

## Quy Ước Xử Lý Lỗi

### Tổng Quan

Toàn bộ xử lý lỗi ở tầng ứng dụng sử dụng **domain exceptions** từ `@modules/shared/domain/domain-exception`. Không bao giờ import các lớp exception từ `@nestjs/common` trong handlers — hãy dùng domain exceptions của dự án.

`GlobalExceptionFilter` bắt tất cả các exception và chuẩn hóa chúng thành một JSON response nhất quán với error codes có cấu trúc.

### Domain Exceptions

| Exception | HTTP Status | Khi nào dùng |
|---|---|---|
| `NotFoundException(entity, id?)` | 404 | Không tìm thấy entity trong database |
| `ValidationException(message, details?)` | 400 | Dữ liệu đầu vào không hợp lệ, vi phạm business rule, lỗi tạo value object |
| `ConflictException(message)` | 409 | Tài nguyên bị trùng lặp, vi phạm idempotency |
| `UnauthorizedException(message?)` | 401 | Thông tin xác thực hoặc token không hợp lệ/đã hết hạn |
| `ForbiddenException(message?)` | 403 | Đã xác thực nhưng không được phép thực hiện hành động |

Import từ:

```typescript
import { NotFoundException, ValidationException } from '@modules/shared/domain/domain-exception';
```

### Các Mẫu Theo Từng Tầng

#### Command/Query Handlers

Handlers ném domain exceptions trực tiếp. Không cần bọc try-catch — `GlobalExceptionFilter` xử lý các exception chưa được bắt.

```typescript
// Good: domain exception with entity context
const user = await this.userRepo.findById(id);
if (!user) throw new NotFoundException('User', id);

// Good: Result pattern from value objects
const phoneResult = Phone.create(command.phone);
if (phoneResult.isErr) {
  throw new ValidationException(phoneResult.unwrapErr());
}
const phone = phoneResult.unwrap();

// Good: business rule validation
if (subscription.status === 'CANCELLED') {
  throw new ValidationException('Subscription da bi huy');
}
```

#### Controllers

Controllers là các tầng ủy quyền mỏng — chúng dispatch tới command/query bus và trả về kết quả. Không cần xử lý lỗi ở tầng controller.

#### Domain Services / Value Objects

Sử dụng mẫu `Result<T, E>` từ `@modules/shared/domain/result`:

```typescript
static create(value: string): Result<Phone, string> {
  if (!isValid(value)) return Result.err('So dien thoai khong hop le');
  return Result.ok(new Phone({ value }));
}
```

Handlers sử dụng `Result` bằng cách kiểm tra `.isErr` và ném `ValidationException`.

### Những Điều KHÔNG Nên Làm

```typescript
// Bad: NestJS built-in exceptions (missing errorCode in response)
import { NotFoundException } from '@nestjs/common';

// Bad: object-style exceptions (inconsistent with domain exception API)
throw new NotFoundException({ code: ErrorCode.NOT_FOUND, message: '...' });

// Bad: generic try-catch swallowing infrastructure errors as domain errors
try {
  await this.prisma.plan.findFirst({ where: { tier } });
} catch {
  throw new NotFoundException('Plan not found'); // hides DB connection errors
}

// Bad: returning Result from handlers to controllers
// Handlers should unwrap Result and throw on error
```

### Kiểu Trả Về Của Repository

Tất cả các phương thức đọc của repository phải trả về DTOs được định kiểu rõ ràng — không bao giờ dùng `Promise<any>` hoặc `PaginatedResult<any>`. Định nghĩa read DTOs ở tầng domain cùng với interface của repository.

Xem `listing-read.dto.ts` để tham khảo ví dụ chuẩn.

---

## Code Review Checklist

Khi review PR, kiểm tra:

### Functionality
- [ ] Changes meet acceptance criteria
- [ ] No breaking changes (or documented)
- [ ] Error handling is robust
- [ ] Edge cases covered

### Code Quality
- [ ] Code follows conventions (style, naming, patterns)
- [ ] No `console.log`, `TODO` without issue reference
- [ ] No dead code, unused imports
- [ ] Functions have clear responsibility

### Testing
- [ ] Unit tests cover happy path + error cases
- [ ] E2E tests for critical flows (if applicable)
- [ ] Coverage maintained / improved (API ≥60%, Web ≥50%)
- [ ] No flaky tests

### Documentation
- [ ] Code comments explain "why", not "what"
- [ ] Updated docs if API/process changed
- [ ] Commit messages follow conventions

### Security
- [ ] No hardcoded secrets (API keys, passwords)
- [ ] Input validation in place
- [ ] Auth checks in place
- [ ] No SQL injection (use Prisma, not raw SQL)

### Performance
- [ ] No N+1 queries
- [ ] Caching applied where appropriate
- [ ] No blocking operations in event loop

---

## Release Process

### Versioning

Tuân theo **Semantic Versioning**: `MAJOR.MINOR.PATCH`

- **MAJOR:** Breaking changes (require migration)
- **MINOR:** New features (backward compatible)
- **PATCH:** Bug fixes

### Creating a Release

```bash
# 1. Update CHANGELOG.md with changes
# 2. Bump version in package.json (root)
# 3. Create git tag
git tag -a v1.5.0 -m "Release 1.5.0: Add phone OTP login"
git push origin v1.5.0

# 4. GitHub Actions automatically:
#    - Builds Docker image
#    - Pushes to GitHub Container Registry
#    - Creates GitHub Release
#    - Deploys to staging (auto)
#    - Waits for manual approval for production
```

---

## Questions?

- 📖 Read `/docs/architecture.md` for system design
- 🏗️ Read `/docs/QUICK_REFERENCE.md` for patterns
- 💬 Ask on Slack `#dev` channel
- 🐛 File an issue: https://github.com/hongochai10/goodgo-bds-platform-ai/issues

**Happy coding! 🚀**

