# CI/CD Pipeline

GoodGo Platform sử dụng **GitHub Actions** để tự động hóa build, test, và deployment. Pipeline tuân theo quy tắc _"build once, deploy anywhere"_ — một lần build, deploy tới nhiều môi trường.

## Pipeline Overview

Pipeline bao gồm **4 bước chính**:

```
1. Lint (ESLint)
   ↓
2. TypeScript Check (tsc)
   ↓
3. Unit Tests (Jest/Vitest)
   ↓
4. Build (Turborepo)
```

Mỗi bước phải **pass** trước khi tiếp tục bước tiếp theo. Nếu bất kỳ bước nào thất bại, workflow dừng ngay.

---

## Trigger Events

Pipeline **tự động chạy** khi:

| Event | Branches | Hành động |
|-------|----------|----------|
| **Push** | `main`, `master`, `develop` | Chạy đầy đủ pipeline (lint → typecheck → test → build) |
| **Pull Request** | Bất kỳ branch | Chạy đầy đủ pipeline trước khi merge |
| **Manual** (workflow_dispatch) | Bất kỳ branch | Cho phép chạy thủ công từ GitHub UI |

---

## Step 1: Lint (ESLint)

**File:** `.github/workflows/ci.yml` → job `lint`

**Mục đích:** Kiểm tra style code, conventions, và phát hiện anti-patterns.

**Command:**
```bash
pnpm lint
```

**Chi tiết:**
- ESLint config: `.eslintrc.json` (root)
- Rules: import order, naming, unused variables, etc.
- Auto-fixable issues: `pnpm lint --fix`
- **Non-auto-fixable issues:** workflow fails, developer phải fix thủ công

**Quy tắc chính:**
- ✅ Imports ordered: `external` → `internal` (path alias) → `relative`
- ✅ Không dùng `any` type (TypeScript strict)
- ✅ Không có unused variables hoặc imports
- ❌ Không mix `require()` và `import` (dùng `import` for ES6)

**Thời gian:** ~30 giây

---

## Step 2: TypeScript Check (tsc)

**File:** `.github/workflows/ci.yml` → job `typecheck`

**Mục đích:** Kiểm tra type safety toàn codebase mà không compile.

**Command:**
```bash
pnpm typecheck
```

**Chi tiết:**
- Chạy `tsc --noEmit` trên mỗi package (API, Web, etc.)
- **TypeScript config:** `tsconfig.json` (per-package)
- **Strict mode:** `strict: true`
- Path aliases: `@modules/*` (API), `@/*` (Web)

**Quy tắc chính:**
- ✅ Mọi function phải có explicit return types
- ✅ Mọi parameter phải có type annotation (strict)
- ✅ Generic types phải đủ specificity (không `Promise<any>`)
- ❌ Không dùng `any` ngoại lệ (có comment `@ts-expect-error`)

**Thời gian:** ~45 giây

---

## Step 3: Unit Tests (Jest/Vitest)

**File:** `.github/workflows/ci.yml` → job `test`

**Mục đích:** Chạy suite kiểm thử đơn vị, đảm bảo logic ngữ nghĩa đúng.

**Command:**
```bash
pnpm test
```

**Chi tiết:**
- **API (NestJS):** Jest + `@nestjs/testing`
- **Web (Next.js):** Vitest + `@testing-library/react`
- Coverage threshold: API ≥ 60%, Web ≥ 50%
- Snapshot tests: must commit `.snap` file changes

**Test Locations:**
| Package | Pattern | Runner |
|---------|---------|--------|
| API | `apps/api/src/**/*.spec.ts` | Jest |
| Web | `apps/web/src/**/*.spec.ts` | Vitest |
| Libs | `libs/**/*.spec.ts` | Jest (libs) / Vitest (web libs) |

**Quy tắc viết Test:**
- ✅ Test AAA pattern: **A**rrange → **A**ct → **A**ssert
- ✅ Describe blocks: `[Unit/Integration] ClassName.method()`
- ✅ Mock external dependencies (database, HTTP, etc.)
- ✅ Test happy path + error cases + edge cases
- ❌ Không mock internal logic
- ❌ Không snapshot-test component trees (snapshot brittle)

**Thời gian:** ~60 giây (API), ~30 giây (Web)

**Xem coverage:**
```bash
pnpm test -- --coverage
```

---

## Step 4: Build (Turborepo)

**File:** `.github/workflows/ci.yml` → job `build`

**Mục đích:** Production build tất cả packages, detect breaking changes.

**Command:**
```bash
pnpm build
```

**Chi tiết:**
- **Turborepo caching:** Bỏ qua build lại nếu code không thay đổi
- **Targets:** `apps/api`, `apps/web`, `libs/ai-services`, `libs/mcp-servers`
- **Output:** `dist/` per-package
- Vô hiệu hóa cache: `--no-cache`

**Per-Package Build:**
| Package | Command | Output | Notes |
|---------|---------|--------|-------|
| API | `nest build` | `dist/` | Production NestJS app |
| Web | `next build` | `.next/` | Optimized Next.js app |
| AI Services | `docker build` | `Dockerfile` | Python FastAPI image (không build trong CI, chỉ lint + test) |
| MCP Servers | Bundled vào API | N/A | TypeScript → JS |

**Thời gian:** ~120 giây (with Turborepo cache)

---

## Error Handling & Retry

### CI Pipeline Retry Policy

| Failure | Action | Retry |
|---------|--------|-------|
| Network timeout | Auto-retry (3x) | Yes, within same run |
| Out of disk space | Fail + notify | Manual re-run |
| Flaky test | Fail (capture logs) | Manual re-run w/ `--seed` |
| Git checkout error | Fail + notify | Manual re-run |

### Local Debugging

```bash
# Replicate exact CI environment locally
docker pull ghcr.io/actions/runner:latest

# Or run pnpm commands locally
pnpm install
pnpm lint --debug
pnpm typecheck
pnpm test -- --bail  # stop on first failure
pnpm build
```

---

## GitHub Status Checks

Pull requests require **all 4 checks to pass** before merging:

```
✅ lint
✅ typecheck
✅ test
✅ build
```

**Branch Protection Rules:**

- ✅ Require PR reviews: 1 approval minimum (code owner)
- ✅ Dismiss stale PR approvals
- ✅ Require status checks to pass
- ✅ Require branches to be up to date before merging
- ✅ Restrict who can push to matching branches (admin only)

---

## Secrets & Environment Variables

### CI-Only Secrets (`.github/secrets/`)

| Secret | Used In | Purpose |
|--------|---------|---------|
| `DATABASE_URL_TEST` | Step 3 (test) | Test database (PostgreSQL) |
| `REDIS_URL_TEST` | Step 3 (test) | Test Redis cache |
| `OPENAI_API_KEY` | Step 3 (test) | Claude API (if needed) |

### Build-Time Env (`.env.ci`)

```bash
# .env.ci (git-tracked)
NODE_ENV=test
LOG_LEVEL=warn
DATABASE_POOL_MIN=2
DATABASE_POOL_MAX=5
REDIS_TIMEOUT=5000
```

### Deploy-Only Secrets (`.github/secrets/` for Production)

| Secret | Deploy Target | Used In |
|--------|---------------|---------|
| `DOCKER_REGISTRY_TOKEN` | Docker Hub / GitHub Container Registry | Push image after build success |
| `DEPLOY_SSH_KEY` | Production VPS | SSH into server + restart service |
| `SENTRY_AUTH_TOKEN` | Sentry.io | Release tracking |

---

## Deployment Strategy

### Auto-Deploy Trigger

Push to `main` → All checks pass → Auto-deploy to **Staging**

```
main branch
  ↓ (all checks pass)
  ↓
Auto-build Docker image
  ↓
Push to GitHub Container Registry (ghcr.io)
  ↓
SSH into staging server
  ↓
docker pull + docker-compose up -d
  ↓
Health checks (/health/ready) → smoke tests
  ↓
✅ Deployed to staging
```

### Manual Deploy to Production

**Only via GitHub Release tag:**

```bash
git tag -a v1.5.0 -m "Release 1.5.0"
git push origin v1.5.0
```

Tag push triggers **manual approval** in GitHub → Deploy to Production.

---

## Monitoring & Logs

### CI Logs

- **GitHub:** https://github.com/hongochai10/goodgo-bds-platform-ai/actions
- **Per-job logs:** Click workflow run → view step output
- **Artifact download:** Logs, coverage reports, etc.

### Production Deployment Logs

```bash
# SSH into production server
ssh deploy@prod.goodgo.app

# View Docker Compose logs
docker-compose -f docker-compose.prod.yml logs -f
```

### Error Alerts

- **Slack:** Integration notify `#deployments` on failure
- **Email:** GitHub notifications to team@goodgo.app
- **Sentry:** Auto-capture runtime errors after deploy

---

## Performance Tips

### Faster Local Development

```bash
# Lint & typecheck only (skip test & build for quick feedback)
pnpm lint && pnpm typecheck

# Test only changed files
pnpm test -- --onlyChanged

# Build only specific package
pnpm --filter api build
```

### Faster CI (reduce time)

1. **Cache optimization:** Turborepo already caches built packages
2. **Parallel jobs:** Lint + typecheck run simultaneously (in CI yaml, set `runs-on: ubuntu-latest`)
3. **Skip full build on patch commits:** Use `[skip ci]` in commit message (not recommended for main)

---

## Troubleshooting

### Common CI Failures

| Error | Cause | Fix |
|-------|-------|-----|
| `ESLint error: Import not sorted` | Import order wrong | `pnpm lint --fix` |
| `TypeScript error: Type 'any'` | Strict type checking | Add explicit type annotation |
| `Jest timeout: test took > 5000ms` | Slow test (DB, network) | Mock external calls, increase timeout `jest.setTimeout(10000)` |
| `Out of disk space` | GitHub runner full | Clear cache, reduce artifact retention |
| `pnpm install stuck` | Network issue | Retry: `rm -rf node_modules && pnpm install` |

### Re-run CI

```bash
# Re-run entire workflow (GitHub UI)
Actions tab → select workflow → click "Re-run" button

# Or locally, push empty commit
git commit --allow-empty -m "Trigger CI"
git push
```

---

## References

- GitHub Actions: https://docs.github.com/en/actions
- Turborepo Caching: https://turbo.build/repo/docs/core-concepts/caching
- ESLint Config: `/.eslintrc.json`
- TypeScript Config: `/tsconfig.json` (root), `/apps/api/tsconfig.json`, etc.
- Jest Config: `/apps/api/jest.config.js`
- Vitest Config: `/apps/web/vitest.config.ts`
