Files
CompanySite/.agents/devops-engineer/CI_CD_PIPELINE.md
T
Clintchiz d402256547
Deploy to Production / Build & Verify (push) Failing after 5m56s
Ping Search Engines / Notify Search Engines (push) Successful in 2s
Deploy to Production / Pre-Deploy Tests (push) Has been skipped
Deploy to Production / Deploy to Railway (push) Has been skipped
Deploy to Production / Deploy to Render (push) Has been skipped
Deploy to Production / Deploy to VPS (PM2) (push) Has been skipped
Deploy to Production / Deploy to Fly.io (push) Has been skipped
Deploy to Production / Post-Deploy Verification (push) Has been skipped
Deploy to Production / Notify on Failure (push) Successful in 2s
E2E Test Suite / Critical User Journeys (push) Has been skipped
E2E Test Suite / API Integration Tests (push) Has been skipped
E2E Test Suite / Smoke Tests (P0) (push) Failing after 11m26s
E2E Test Suite / Form Interaction Tests (push) Failing after 11m42s
E2E Test Suite / Destructive & Chaos Tests (push) Failing after 12m2s
E2E Test Suite / Cross-Browser Regression (chromium) (push) Failing after 16m14s
E2E Test Suite / Cross-Browser Regression (webkit) (push) Failing after 17m45s
E2E Test Suite / Cross-Browser Regression (firefox) (push) Failing after 25m23s
E2E Test Suite / Security Header Tests (push) Failing after 7m55s
E2E Test Suite / Test Report Summary (push) Failing after 20s
E2E Test Suite / Mobile Device Tests (push) Failing after 2h49m9s
Uptime Monitor / Health & Response Time (push) Failing after 2s
Uptime Monitor / SSL Certificate (push) Successful in 2s
Uptime Monitor / Send Alerts (push) Failing after 3s
Uptime Monitor / Record Uptime Success (push) Has been skipped
First Init
2026-03-21 16:46:46 +05:30

413 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# CI/CD Pipeline — WorkRoot Website
> Production deployment pipeline documentation for the WorkRoot website.
> Framework: Astro SSR + Express | Platform: GitHub Actions
---
## Overview
The CI/CD system consists of two complementary pipelines:
| Workflow | File | Purpose |
|----------|------|---------|
| **E2E Test Suite** | `.github/workflows/e2e-tests.yml` | Runs on every push/PR — 9 test jobs |
| **Deploy to Production** | `.github/workflows/deploy.yml` | Deploys on merge to `main` |
---
## Pipeline Architecture
```
Push to main
├─── E2E Test Suite (parallel) ──────────────────────────────────┐
│ ├── Smoke Tests (P0) │
│ ├── Critical Paths │
│ └── API Integration │
│ │
└─── Deploy Pipeline ────────────────────────────────────────────┘
[Job 1] Build & Verify
│ ✓ npm ci
│ ✓ tsc --noEmit
│ ✓ npm run build
│ ✓ Verify dist/ structure
│ ✓ Upload build artifact
[Job 2] Pre-Deploy Tests
│ ✓ Download build artifact
│ ✓ Start server locally
│ ✓ Run smoke tests (Chromium)
│ ✓ Run API integration tests
[Job 3] Deploy (one of:)
├── Railway (DEPLOY_TARGET=railway)
├── Render (DEPLOY_TARGET=render)
├── VPS/PM2 (DEPLOY_TARGET=vps)
└── Fly.io (DEPLOY_TARGET=fly)
[Job 4] Post-Deploy Verification
│ ✓ Smoke tests against live production
│ ✓ Critical endpoint checks
│ ✓ Upload results (14-day retention)
[Job 5] Notify on Failure (if any stage failed)
```
---
## Deployment Targets
### Option A: Railway (Recommended for simplicity)
Railway auto-deploys from GitHub. CI/CD adds a verification layer.
**Required secrets:**
| Secret | Value |
|--------|-------|
| `RAILWAY_TOKEN` | From Railway dashboard → Settings → Tokens |
**Required variables:**
| Variable | Value |
|----------|-------|
| `DEPLOY_TARGET` | `railway` |
**Setup:**
1. Create a Railway project, connect the GitHub repo
2. Set `START_COMMAND`: `npm run start:prod`
3. Set `PORT`: `10000`
4. Add the `RAILWAY_TOKEN` secret to GitHub
5. Set `DEPLOY_TARGET=railway` in GitHub repo variables
---
### Option B: Render
Render uses deploy hooks triggered by the CI pipeline.
**Required secrets:**
| Secret | Value |
|--------|-------|
| `RENDER_DEPLOY_HOOK_URL` | From Render dashboard → Service → Deploy Hook URL |
**Required variables:**
| Variable | Value |
|----------|-------|
| `DEPLOY_TARGET` | `render` |
**Render service configuration:**
- Environment: Node
- Build command: `npm ci && npm run build`
- Start command: `npm run start:prod`
- Health check path: `/api/health.json`
---
### Option C: VPS with PM2 (Full Control)
SSH-based deployment to any Linux VPS. Includes automatic rollback.
**Required secrets:**
| Secret | Description |
|--------|-------------|
| `VPS_HOST` | VPS IP or hostname |
| `VPS_USER` | SSH user (e.g., `ubuntu`, `deploy`) |
| `VPS_SSH_PRIVATE_KEY` | Private key (contents of `~/.ssh/id_rsa`) |
| `VPS_HOST_KEY` | SSH host key fingerprint |
**Required variables:**
| Variable | Value |
|----------|-------|
| `DEPLOY_TARGET` | `vps` |
**VPS setup (one-time):**
```bash
# On your VPS:
# 1. Create deployment directory
mkdir -p /var/www/workroot
chown -R deploy:www-data /var/www/workroot
# 2. Install Node.js 20 (via nvm or nodesource)
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
sudo apt-get install -y nodejs
# 3. Install PM2 globally
npm install -g pm2
pm2 startup # Follow the output instructions
# 4. Create logs directory
mkdir -p /var/www/workroot/logs
# 5. Set up Nginx reverse proxy (port 80/443 → 10000)
# See Nginx config below
```
**Nginx configuration:**
```nginx
server {
listen 80;
server_name workroot.in www.workroot.in;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
server_name workroot.in www.workroot.in;
ssl_certificate /etc/letsencrypt/live/workroot.in/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/workroot.in/privkey.pem;
location / {
proxy_pass http://localhost:10000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_cache_bypass $http_upgrade;
}
}
```
**Deployment behavior:**
1. Backs up current deployment before replacing
2. Extracts new files to `/var/www/workroot/`
3. Installs production dependencies only
4. Uses `pm2 reload` for zero-downtime restart
5. Runs health check (12 attempts × 10s = 2 minutes max)
6. **Auto-rollback** if health check fails
---
### Option D: Fly.io
Container-based deployment with edge distribution.
**Required secrets:**
| Secret | Value |
|--------|-------|
| `FLY_API_TOKEN` | From `flyctl auth token` |
**Required variables:**
| Variable | Value |
|----------|-------|
| `DEPLOY_TARGET` | `fly` |
**Setup:**
```bash
# Install flyctl
curl -L https://fly.io/install.sh | sh
# Authenticate
flyctl auth login
# Launch app (first time only)
flyctl launch --name workroot-website
# Set production secrets
flyctl secrets set NODE_ENV=production PORT=10000
```
**fly.toml** (create in project root if using Fly.io):
```toml
app = "workroot-website"
primary_region = "sin" # Singapore - closest to India
[build]
[build.args]
NODE_VERSION = "20"
[env]
PORT = "10000"
HOST = "0.0.0.0"
NODE_ENV = "production"
[http_service]
internal_port = 10000
force_https = true
auto_stop_machines = true
auto_start_machines = true
min_machines_running = 1
[http_service.concurrency]
type = "connections"
hard_limit = 25
soft_limit = 20
[[vm]]
cpu_kind = "shared"
cpus = 1
memory_mb = 512
```
---
## GitHub Repository Setup
### Required Secrets (Settings → Secrets → Actions)
Configure secrets for your chosen deployment target:
```
# For ALL targets:
# (none required at the base level)
# For Railway:
RAILWAY_TOKEN=<token>
# For Render:
RENDER_DEPLOY_HOOK_URL=https://api.render.com/deploy/...
# For VPS:
VPS_HOST=123.456.789.0
VPS_USER=deploy
VPS_SSH_PRIVATE_KEY=-----BEGIN OPENSSH PRIVATE KEY-----...
VPS_HOST_KEY=123.456.789.0 ssh-rsa AAAA...
# Optional notifications:
SLACK_WEBHOOK_URL=https://hooks.slack.com/services/...
```
### Required Variables (Settings → Variables → Actions)
```
DEPLOY_TARGET=railway # or: render, vps, fly
```
### Environment Protection Rules
Configure via Settings → Environments:
1. Create environment named `production`
2. Enable "Required reviewers" for manual approval before deploy
3. Set allowed branches to `main` only
---
## Trigger Conditions
| Event | Build | Tests | Deploy |
|-------|-------|-------|--------|
| Push to `main` | ✓ | ✓ | ✓ |
| Manual dispatch | ✓ | ✓ (unless skip_tests=true) | ✓ |
| Push to `develop` | via e2e-tests.yml | ✓ | ✗ |
| Pull Request | via e2e-tests.yml | ✓ | ✗ |
---
## Environment Variables in Production
All env vars must be configured in your hosting platform, not in the workflow.
| Variable | Required | Default | Description |
|----------|----------|---------|-------------|
| `NODE_ENV` | Yes | — | Must be `production` |
| `HOST` | Yes | — | `0.0.0.0` |
| `PORT` | Yes | — | `10000` |
| `CONTACT_EMAIL` | No | — | Where contact form sends emails |
| `SMTP_HOST` | No | — | Email server host |
| `SMTP_USER` | No | — | Email server username |
| `SMTP_PASS` | No | — | Email server password (use platform secrets) |
| `SENTRY_DSN` | No | — | Sentry error tracking |
| `LOG_LEVEL` | No | `info` | Logging verbosity |
---
## Rollback Procedures
### Railway / Render / Fly.io
Use the hosting platform dashboard to redeploy a previous commit or use the rollback button.
### VPS (PM2)
The deployment script auto-rolls back if health checks fail. For manual rollback:
```bash
# SSH to VPS
ssh deploy@your-vps-ip
# Check what backups exist
ls -la /var/www/ | grep workroot-backup
# Rollback to most recent backup
BACKUP=$(ls -t /var/www/ | grep workroot-backup | head -1)
echo "Rolling back to: $BACKUP"
# Stop, restore, restart
pm2 stop workroot-website
cp -r /var/www/$BACKUP/. /var/www/workroot/
cd /var/www/workroot && npm ci --omit=dev
pm2 start ecosystem.config.cjs --env production
pm2 save
# Verify
curl http://localhost:10000/api/health.json
```
### Emergency Deploy (Skip Tests)
Use `workflow_dispatch` with `skip_tests: true` only in genuine emergencies.
Document the reason in the workflow run description.
---
## Monitoring After Deploy
### Immediate (05 minutes)
- [ ] Workflow shows all jobs green
- [ ] Health endpoint: `https://workroot.in/api/health.json` returns `{"status":"ok"}`
- [ ] Homepage loads correctly
- [ ] Contact form accessible
### Short-term (1560 minutes)
- [ ] No spike in error logs
- [ ] PM2 showing stable process count (VPS only)
- [ ] Nightly E2E suite runs clean
### Verification Commands (VPS)
```bash
# Check PM2 status
pm2 status
pm2 logs workroot-website --lines 50
# Check Nginx logs
sudo tail -f /var/log/nginx/access.log
sudo tail -f /var/log/nginx/error.log
# Health check
curl -s http://localhost:10000/api/health.json | python3 -m json.tool
```
---
## Pipeline Files Reference
| File | Purpose |
|------|---------|
| `.github/workflows/deploy.yml` | Main deployment pipeline |
| `.github/workflows/e2e-tests.yml` | Test suite (smoke, critical, API, chaos, cross-browser, mobile, security) |
| `.github/workflows/sitemap-ping.yml` | Pings Google/Bing after content changes |
| `ecosystem.config.cjs` | PM2 cluster configuration |
| `server.mjs` | Express wrapper for Astro SSR |
| `.env.example` | Environment variable template |
---
## Adding a New Deployment Target
1. Add a new job block in `deploy.yml` after the existing deploy jobs
2. Add the condition: `vars.DEPLOY_TARGET == 'your-target'`
3. Add required secrets to this document
4. Update the `post-deploy-verify` job's `needs` array to include the new job
5. Test with a manual `workflow_dispatch` trigger
---
*Last updated: 2026-03-21 | Created by: devops-engineer agent*