CI/CD Pipeline
Overview
BookWish uses GitHub Actions for continuous integration and deployment. Every push and pull request triggers automated tests, builds, and deployments.
Pipeline Architecture
┌─────────────┐
│ Git Push │
└──────┬──────┘
│
▼
┌─────────────────────────────┐
│ GitHub Actions Trigger │
└──────┬──────────────────────┘
│
├──────────────────┬──────────────────┬──────────────────┐
▼ ▼ ▼ ▼
┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐
│ Lint │ │ Test │ │ Build │ │ Deploy │
└──────────┘ └──────────┘ └──────────┘ └──────────┘
Workflows
Pull Request Workflow
Runs on every pull request to main:
# .github/workflows/pr.yml
name: Pull Request
on:
pull_request:
branches: [main]
jobs:
lint:
- ESLint (backend)
- Flutter analyze (app)
- TypeScript type check
test:
- Backend unit tests
- Flutter unit tests
- Integration tests
build:
- Backend build
- Flutter build (iOS, Android, Web)
Status: Must pass before merge is allowed
Continuous Integration (Main Branch)
Runs on every push to main:
# .github/workflows/ci.yml
name: CI
on:
push:
branches: [main]
jobs:
lint-and-test:
- Run all linting
- Run all tests
- Generate coverage reports
deploy-staging:
- Deploy backend to staging
- Deploy web app to staging
- Run smoke tests
Release Workflow
Runs when a version tag is pushed:
# .github/workflows/release.yml
name: Release
on:
push:
tags:
- 'v*'
jobs:
build-ios:
- Build iOS app
- Upload to TestFlight
build-android:
- Build Android app
- Upload to Play Store
build-web:
- Build web app
- Deploy to Vercel
create-release:
- Generate changelog
- Create GitHub release
Workflow Details
Linting
- name: Lint Backend
run: |
cd backend
npm run lint
- name: Lint Flutter
run: |
cd app
flutter analyze
Checks:
- Code style compliance
- No TypeScript
anytypes - No console.log statements
- No print() statements
- Proper imports
Testing
- name: Backend Tests
run: |
cd backend
npm test
- name: Flutter Tests
run: |
cd app
flutter test --coverage
Coverage Requirements:
- Backend: 80% minimum
- Flutter: 70% minimum
Building
- name: Build Backend
run: |
cd backend
npm run build
- name: Build Flutter Web
run: |
cd app
flutter build web --release
- name: Build Flutter iOS
run: |
cd app/ios
bundle exec fastlane build
Secrets Management
All sensitive data is stored in GitHub Secrets:
Required Secrets
| Secret | Used For | Required By |
|---|---|---|
APPLE_CERTIFICATE_BASE64 | iOS signing | Release workflow |
ANDROID_KEYSTORE_BASE64 | Android signing | Release workflow |
VERCEL_TOKEN | Web deployment | Release workflow |
DATABASE_URL | Test database | CI workflow |
Adding Secrets
- Go to
Repository → Settings → Secrets and variables → Actions - Click "New repository secret"
- Add name and value
- Reference in workflow:
${{ secrets.SECRET_NAME }}
Environment Variables
Development
NODE_ENV=development
DATABASE_URL=postgresql://localhost/bookwish_dev
API_BASE_URL=http://localhost:3000
Staging
NODE_ENV=staging
DATABASE_URL=${{ secrets.STAGING_DATABASE_URL }}
API_BASE_URL=https://staging-api.bookwish.io
Production
NODE_ENV=production
DATABASE_URL=${{ secrets.PRODUCTION_DATABASE_URL }}
API_BASE_URL=https://api.bookwish.io
Deployment Targets
Backend API
Platform: AWS ECS / Railway / Render (specify your platform)
Process:
- Build Docker image
- Push to container registry
- Deploy to production cluster
- Run database migrations
- Health check verification
Flutter Web
Platform: Vercel
Process:
- Build Flutter web
- Upload to Vercel
- Deploy to production domain
- Invalidate CDN cache
Mobile Apps
iOS:
- Build with Xcode Cloud or GitHub Actions
- Upload to TestFlight
- Manual submission to App Store
Android:
- Build with GitHub Actions
- Upload to Play Store Internal Track
- Promote to Beta/Production manually
Monitoring
Build Status
Monitor builds at:
- GitHub Actions tab
- Status badges in README
- Slack/Discord notifications (if configured)
Deployment Status
Check deployment status:
- Vercel dashboard (web)
- App Store Connect (iOS)
- Google Play Console (Android)
- Your hosting provider (backend)
Notifications
Configure notifications in:
# .github/workflows/notify.yml
- name: Notify on Failure
if: failure()
uses: 8398a7/action-slack@v3
with:
status: ${{ job.status }}
webhook_url: ${{ secrets.SLACK_WEBHOOK }}
Caching
Speed up builds with caching:
- name: Cache Dependencies
uses: actions/cache@v3
with:
path: |
~/.npm
~/.pub-cache
key: ${{ runner.os }}-deps-${{ hashFiles('**/package-lock.json', '**/pubspec.lock') }}
Troubleshooting
Build Failures
- Check logs: Click on failed job in GitHub Actions
- Reproduce locally: Run same commands on your machine
- Check secrets: Ensure all required secrets are set
- Verify dependencies: Check for broken dependencies
Deployment Failures
- Check deployment logs in your hosting platform
- Verify environment variables are set correctly
- Check database migrations have run successfully
- Verify API connectivity from deployed app
Common Issues
Issue: Tests fail in CI but pass locally
- Solution: Check for environment-specific code, ensure test database is seeded properly
Issue: Build timeout
- Solution: Increase timeout in workflow, optimize build steps, add caching
Issue: Secrets not available
- Solution: Verify secret names match exactly, check repository permissions
Best Practices
Do's
✅ Keep workflows fast (< 10 minutes) ✅ Use caching for dependencies ✅ Fail fast on critical errors ✅ Run tests in parallel when possible ✅ Use matrix builds for multiple platforms ✅ Keep secrets secure and rotated ✅ Monitor build status regularly
Don'ts
❌ Commit secrets to repository ❌ Skip tests to make builds faster ❌ Deploy without running tests ❌ Ignore failed builds ❌ Hard-code environment-specific values
Workflow Templates
Basic PR Check
name: PR Check
on: [pull_request]
jobs:
check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup Node
uses: actions/setup-node@v3
with:
node-version: '18'
- name: Install
run: npm ci
- name: Lint
run: npm run lint
- name: Test
run: npm test
- name: Build
run: npm run build
Matrix Build
jobs:
test:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
node: [16, 18, 20]
steps:
- uses: actions/checkout@v3
- name: Setup Node ${{ matrix.node }}
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node }}
- run: npm ci
- run: npm test
Performance Optimization
Parallel Jobs
jobs:
lint:
runs-on: ubuntu-latest
steps: [...]
test-backend:
runs-on: ubuntu-latest
steps: [...]
test-frontend:
runs-on: ubuntu-latest
steps: [...]
Conditional Execution
- name: Deploy
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
run: npm run deploy