# 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`) - ❌ 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`