> ## Documentation Index
> Fetch the complete documentation index at: https://docs.charle.agency/llms.txt
> Use this file to discover all available pages before exploring further.

# CI/CD Pipeline

> Automated testing and deployment workflow

CharleOS uses **GitHub Actions** for continuous integration and **Vercel** for continuous deployment. This page explains the automated pipeline.

## CI/CD Overview

```
Developer pushes code
  ↓
GitHub Actions (CI)
  ├── Lint code
  ├── Type check
  ├── Run unit tests
  ├── Run E2E tests
  └── Build application
  ↓
All checks pass?
  ├── Yes → Vercel deploys (CD)
  └── No → Block merge
```

## GitHub Actions Workflows

CharleOS has several automated workflows:

<CardGroup cols={2}>
  <Card title="CI Pipeline" icon="circle-check">
    Runs on every PR to `main`

    * Linting
    * Type checking
    * Unit tests
    * Build verification
  </Card>

  <Card title="E2E Tests" icon="robot">
    Runs on PRs (separate workflow)

    * Playwright E2E tests
    * Critical user flows
    * Browser compatibility
  </Card>

  <Card title="Dependabot" icon="arrows-rotate">
    Automatic dependency updates

    * Security patches
    * Minor version bumps
    * Auto-merge for tests
  </Card>

  <Card title="Release" icon="tag">
    Automated changelog and versioning

    * Conventional commits
    * Semantic versioning
    * GitHub releases
  </Card>
</CardGroup>

## CI Workflow (`.github/workflows/ci.yml`)

### Workflow Configuration

```yaml theme={null}
name: CI

on:
  pull_request:
    branches: [main]

jobs:
  setup:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 22
      
      - name: Cache dependencies
        uses: actions/cache@v4
        with:
          path: node_modules
          key: ${{ runner.os }}-node-${{ hashFiles('package-lock.json') }}
      
      - name: Install dependencies
        if: steps.cache.outputs.cache-hit != 'true'
        run: npm ci
```

### Lint Job

```yaml theme={null}
lint:
  needs: setup
  runs-on: ubuntu-latest
  steps:
    - uses: actions/checkout@v4
    - uses: actions/setup-node@v4
    
    - name: Restore dependencies
      uses: actions/cache/restore@v4
      with:
        path: node_modules
        key: ${{ runner.os }}-node-${{ hashFiles('package-lock.json') }}
    
    - name: Run ESLint
      run: npm run lint
```

**What it checks:**

* Code style (Prettier)
* ESLint rules
* Import order
* Unused variables

### Type Check Job

```yaml theme={null}
type-check:
  needs: setup
  runs-on: ubuntu-latest
  steps:
    - uses: actions/checkout@v4
    - uses: actions/setup-node@v4
    
    - name: Restore dependencies
      uses: actions/cache/restore@v4
      with:
        path: node_modules
        key: ${{ runner.os }}-node-${{ hashFiles('package-lock.json') }}
    
    - name: Run TypeScript compiler
      run: npm run type-check
```

**What it checks:**

* TypeScript compilation errors
* Type mismatches
* Missing type definitions

### Unit Tests Job

```yaml theme={null}
unit-tests:
  needs: setup
  runs-on: ubuntu-latest
  steps:
    - uses: actions/checkout@v4
    - uses: actions/setup-node@v4
    
    - name: Restore dependencies
      uses: actions/cache/restore@v4
      with:
        path: node_modules
        key: ${{ runner.os }}-node-${{ hashFiles('package-lock.json') }}
    
    - name: Run unit tests with coverage
      run: npm run test:coverage
    
    - name: Upload coverage report
      uses: actions/upload-artifact@v4
      if: always()
      with:
        name: coverage-report
        path: coverage/
```

**What it tests:**

* Business logic
* Utility functions
* Billing calculations
* Date/time utilities

### Build Job

```yaml theme={null}
build:
  needs: setup
  runs-on: ubuntu-latest
  steps:
    - uses: actions/checkout@v4
    - uses: actions/setup-node@v4
    
    - name: Restore dependencies
      uses: actions/cache/restore@v4
      with:
        path: node_modules
        key: ${{ runner.os }}-node-${{ hashFiles('package-lock.json') }}
    
    - name: Cache Next.js build
      uses: actions/cache@v4
      with:
        path: .next/cache
        key: ${{ runner.os }}-nextjs-${{ hashFiles('package-lock.json') }}
    
    - name: Build application
      run: npm run build
      env:
        # Dummy env vars for build
        DATABASE_URL: "postgresql://dummy:dummy@localhost:5432/dummy"
        BETTER_AUTH_SECRET: "dummy-secret-for-build-must-be-32-chars-long"
        BETTER_AUTH_URL: "http://localhost:3000"
        GOOGLE_CLIENT_ID: "dummy"
        GOOGLE_CLIENT_SECRET: "dummy"
```

**What it checks:**

* Next.js builds successfully
* No build errors
* TypeScript compiles in build mode

### Security Audit

```yaml theme={null}
security-audit:
  runs-on: ubuntu-latest
  steps:
    - uses: actions/checkout@v4
      with:
        sparse-checkout: |
          package.json
          package-lock.json
    
    - name: Run npm audit
      run: npm audit --audit-level=high
      continue-on-error: true
```

**What it checks:**

* Known vulnerabilities in dependencies
* Security advisories
* High/critical severity issues

## E2E Workflow (`.github/workflows/e2e.yml`)

```yaml theme={null}
name: E2E Tests

on:
  pull_request:
    branches: [main]

jobs:
  e2e-tests:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
      
      - name: Install dependencies
        run: npm ci
      
      - name: Install Playwright
        run: npx playwright install --with-deps
      
      - name: Run E2E tests
        run: npm run test:e2e
        env:
          DATABASE_URL: ${{ secrets.TEST_DATABASE_URL }}
      
      - name: Upload test results
        if: always()
        uses: actions/upload-artifact@v4
        with:
          name: playwright-report
          path: playwright-report/
```

**What it tests:**

* Authentication flows
* Critical user journeys
* Task/quote workflows
* Client portal functionality

## Dependabot Configuration

Automatic dependency updates:

```yaml theme={null}
# .github/dependabot.yml
version: 2
updates:
  - package-ecosystem: "npm"
    directory: "/"
    schedule:
      interval: "weekly"
    open-pull-requests-limit: 10
    reviewers:
      - "lukespoor"
    assignees:
      - "lukespoor"
```

**Auto-merge workflow:**

```yaml theme={null}
# .github/workflows/dependabot-auto-merge.yml
name: Dependabot Auto-Merge

on:
  pull_request:
    types: [opened, synchronize]

jobs:
  auto-merge:
    if: github.actor == 'dependabot[bot]'
    runs-on: ubuntu-latest
    steps:
      - name: Wait for CI to pass
        uses: lewagon/wait-on-check-action@v1.3.1
        with:
          check-name: 'CI'
          
      - name: Auto-merge patch/minor updates
        if: |
          startsWith(github.event.pull_request.title, 'Bump') &&
          (contains(github.event.pull_request.title, 'patch') ||
           contains(github.event.pull_request.title, 'minor'))
        run: gh pr merge --auto --squash "$PR_URL"
        env:
          PR_URL: ${{ github.event.pull_request.html_url }}
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
```

## Branch Protection Rules

`main` branch is protected with:

**Required checks:**

* ✅ Lint
* ✅ Type check
* ✅ Unit tests
* ✅ Build
* ✅ E2E tests

**Additional rules:**

* Require PR review (1 approval)
* Dismiss stale reviews on new push
* Require linear history
* No force push allowed

## Continuous Deployment

### Vercel Integration

Vercel automatically deploys:

**Production:**

* Trigger: Push to `main`
* URL: `https://charle.agency`
* Only after CI passes

**Preview:**

* Trigger: Open/update PR
* URL: `https://charle-os-git-{branch}.vercel.app`
* Deploys even if CI fails (for testing)

### Deployment Process

```
PR merged to main
  ↓
GitHub triggers Vercel webhook
  ↓
Vercel Build
  ├── Install dependencies
  ├── Run migrations (postinstall)
  ├── Build Next.js
  └── Upload to CDN
  ↓
Live at charle.agency
```

## Release Workflow

Automated releases using Release Please:

```yaml theme={null}
# .github/workflows/release.yml
name: Release

on:
  push:
    branches: [main]

jobs:
  release:
    runs-on: ubuntu-latest
    steps:
      - uses: googleapis/release-please-action@v4
        with:
          release-type: node
          package-name: charle-os
```

**How it works:**

1. Analyzes conventional commits since last release
2. Generates changelog
3. Bumps version in `package.json`
4. Creates GitHub release
5. Tags commit

**Commit conventions:**

```
feat: Add new feature          → Minor version bump
fix: Fix bug                   → Patch version bump
feat!: Breaking change         → Major version bump
chore: Update dependencies     → No release
```

## Monitoring CI/CD

### GitHub Actions Dashboard

View workflow runs:

**URL:** [https://github.com/charle/charle-os/actions](https://github.com/charle/charle-os/actions)

**Information:**

* All workflow runs
* Duration and status
* Logs for each step
* Artifacts (coverage reports, test results)

### Notifications

Failed CI sends notifications via:

* GitHub UI
* Email (to PR author)
* Slack (optional integration)

## Performance Optimization

### Caching

Cache speeds up CI significantly:

**Dependencies:**

```yaml theme={null}
- uses: actions/cache@v4
  with:
    path: node_modules
    key: ${{ runner.os }}-node-${{ hashFiles('package-lock.json') }}
```

**Next.js build:**

```yaml theme={null}
- uses: actions/cache@v4
  with:
    path: .next/cache
    key: ${{ runner.os }}-nextjs-${{ hashFiles('**/*.ts', '**/*.tsx') }}
```

**Playwright browsers:**

```yaml theme={null}
- uses: actions/cache@v4
  with:
    path: ~/.cache/ms-playwright
    key: ${{ runner.os }}-playwright
```

### Parallelization

Jobs run in parallel when possible:

```
Setup (1 min)
  ↓
┌───────────┬──────────────┬─────────────┬────────┐
│ Lint      │ Type Check   │ Unit Tests  │ Build  │
│ (30s)     │ (45s)        │ (1 min)     │ (2 min)│
└───────────┴──────────────┴─────────────┴────────┘
  ↓
All pass → Merge allowed
```

**Total time:** \~3 minutes (vs. 5+ minutes sequentially)

## Troubleshooting

### CI Failing

**Error:** "Lint failed"

**Fix:**

```bash theme={null}
# Run locally
npm run lint

# Auto-fix issues
npm run lint -- --fix

# Commit fixes
git add .
git commit -m "fix: lint errors"
```

**Error:** "Type check failed"

**Fix:**

```bash theme={null}
# Run locally
npm run type-check

# Fix TypeScript errors
# Then commit
```

**Error:** "Tests failed"

**Fix:**

```bash theme={null}
# Run locally
npm run test

# Debug specific test
npm run test -- -t "failing test name"

# Fix and commit
```

### Dependabot PRs Not Auto-Merging

**Cause:** CI not passing or version is major bump

**Fix:**

1. Check CI logs
2. Fix any test failures
3. For major bumps, review manually

### E2E Tests Flaky

**Cause:** Timing issues, race conditions

**Fix:**

1. Add explicit waits: `await page.waitForSelector(...)`
2. Use `waitForLoadState('networkidle')`
3. Increase timeouts for slow operations

## Best Practices

<AccordionGroup>
  <Accordion title="Always Test Locally First" icon="flask">
    Before pushing:

    ```bash theme={null}
    npm run lint
    npm run type-check
    npm run test
    npm run build
    ```
  </Accordion>

  <Accordion title="Write Good Commit Messages" icon="message">
    Use conventional commits:

    ```
    feat: add new feature
    fix: resolve bug
    chore: update dependencies
    docs: update readme
    test: add missing tests
    ```
  </Accordion>

  <Accordion title="Monitor CI Failures" icon="chart-line">
    Don't ignore failed CI:

    * Fix failures immediately
    * Don't merge with failing tests
    * Investigate flaky tests
  </Accordion>

  <Accordion title="Keep CI Fast" icon="bolt">
    Optimize for speed:

    * Use caching
    * Parallelize jobs
    * Only run necessary checks
  </Accordion>
</AccordionGroup>

## Related Documentation

<CardGroup cols={2}>
  <Card title="Deployment Overview" icon="cloud" href="/developer/deployment">
    Deployment process and strategy
  </Card>

  <Card title="Vercel" icon="triangle" href="/developer/deployment/vercel">
    Vercel configuration
  </Card>

  <Card title="Testing" icon="flask" href="/developer/testing">
    Testing strategy
  </Card>

  <Card title="GitHub Actions" icon="book" href="https://docs.github.com/en/actions">
    Official GitHub Actions docs
  </Card>
</CardGroup>
