Files
goodgo-platform/docs/ci-cd.md
Ho Ngoc Hai e798468e4c docs(GOO-33): comprehensive documentation sprint
Create/update all Sprint 6 documentation:
- CHANGELOG.md: document GOO-33 and recent audit findings
- CONTRIBUTING.md: add branching, PR, commit conventions
- docs/ci-cd.md: GitHub Actions pipeline documentation
- docs/onboarding.md: developer setup & onboarding guide
- docs/mcp-servers.md: MCP servers API documentation
- docs/PROJECT_TRACKER.md: mark GOO-33 as in_progress
- docs/QA_TRACKER.md: test status and verification plans

Curate audit reports (reduce ~103 → 12 canonical files):
- Keep canonical audit reports with descriptive index
- Archive obsolete/duplicate audit exploration files

Acceptance Criteria:
- [x] QA_TRACKER.md exists with current test status
- [x] CHANGELOG.md updated to today
- [x] PROJECT_TRACKER.md reflects current sprint status
- [x] CI/CD pipeline documented
- [x] CONTRIBUTING.md has branching, PR, commit conventions
- [x] docs/audits/ reduced to canonical reports

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-22 23:29:20 +07:00

9.1 KiB

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:

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: externalinternal (path alias) → relative
  • Không dùng any type (TypeScript strict)
  • Không có unused variables hoặc imports
  • Không mix require()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:

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:

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: Arrange → Act → Assert
  • 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:

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:

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

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

# .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:

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

Production Deployment Logs

# 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

# 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

# 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