Loading...
Loading...
Deployment & Operations Expert responsible for securely, rollbackable, and observably deploying builds that pass Reviewer and QA gates to servers (PM2 3-process cluster + Nginx reverse proxy + BT Panel). Adheres to engineering baselines including zero-downtime deployment, health checks, rollback within ≤3 minutes, and post-release smoke testing. Handles deployment orchestration, configuration management, traffic management, and monitoring & alerting. Applicable when receiving task cards from the Deploy department or needing to release to production.
npx skill4agent add lpding888/aiygw4.0 codebuddy-deploydeploy/pm2.config.cjsdeploy/release.shdeploy/rollback.shdeploy/nginx.confdeploy/release-checklist.mdtests/e2e/smoke/post-release.spec.ts/health/healthnpm i -gshared/.env/srv/apps/cms/
releases/
2025-10-30-1500/ # Current release
2025-10-28-1100/ # Previous stable version
shared/
.env # Environment variables (production)
logs/
uploads/
current -> releases/2025-10-30-1500/deploy/pm2.config.cjsmodule.exports = {
apps: [
{
name: 'cms-api',
script: 'dist/src/app.js',
instances: 3,
exec_mode: 'cluster',
env: { NODE_ENV: 'production', PORT: 8080 },
out_file: '../shared/logs/api.out.log',
error_file: '../shared/logs/api.err.log',
merge_logs: true,
max_memory_restart: '500M'
},
{
name: 'cms-web',
script: 'node_modules/next/dist/bin/next',
args: 'start -p 3000',
instances: 1,
env: { NODE_ENV: 'production' },
out_file: '../shared/logs/web.out.log',
error_file: '../shared/logs/web.err.log'
}
]
};deploy/nginx.confserver {
listen 80;
server_name cms.example.com;
client_max_body_size 50m;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $remote_addr;
}
location /api/ {
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_read_timeout 60s;
}
location /health {
proxy_pass http://127.0.0.1:8080/health;
}
}NODE_ENV=production
PORT=8080
MYSQL_HOST=127.0.0.1
MYSQL_PORT=3306
MYSQL_USER=cms
MYSQL_PASSWORD=***
MYSQL_DB=cms
REDIS_URL=redis://127.0.0.1:6379
JWT_SECRET=***.envshared//health// src/api/health.js
app.get('/health', (req, res) => {
res.json({
status: 'ok',
timestamp: new Date().toISOString(),
uptime: process.uptime(),
memory: process.memoryUsage()
});
});deploy/release-checklist.mdnpm run build/srv/apps/cms/releases/YYYY-MM-DD-HHMM/ln -s ../../shared/.env .envnpm cinpm run buildpm2 start deploy/pm2.config.cjs/healthrm -f /srv/apps/cms/current
ln -s /srv/apps/cms/releases/YYYY-MM-DD-HHMM /srv/apps/cms/current
pm2 reload deploy/pm2.config.cjsnpm run test:smoke/health.envshared/release.sh/rollback.sh/health#!/bin/bash
set -e
RELEASE_DIR="/srv/apps/cms/releases/$(date +%Y-%m-%d-%H%M)"
SHARED_DIR="/srv/apps/cms/shared"
CURRENT_DIR="/srv/apps/cms/current"
echo "=== Step 1: Create release directory ==="
mkdir -p "$RELEASE_DIR"
echo "=== Step 2: Upload build artifact ==="
scp build.tar.gz user@server:"$RELEASE_DIR/"
echo "=== Step 3: Extract and install dependencies ==="
ssh user@server << EOF
cd "$RELEASE_DIR"
tar -xzf build.tar.gz
ln -s "$SHARED_DIR/.env" .env
ln -s "$SHARED_DIR/logs" logs
npm ci --production
EOF
echo "=== Step 4: Health check ==="
ssh user@server << EOF
cd "$RELEASE_DIR"
pm2 start deploy/pm2.config.cjs
sleep 10
curl -f http://localhost:8080/health || exit 1
EOF
echo "=== Step 5: Switch current link ==="
ssh user@server << EOF
rm -f "$CURRENT_DIR"
ln -s "$RELEASE_DIR" "$CURRENT_DIR"
pm2 reload deploy/pm2.config.cjs
EOF
echo "=== Step 6: Post-release smoke test ==="
npm run test:smoke
echo "=== Step 7: Record release ==="
echo "$(date) - Released $RELEASE_DIR (commit: $(git rev-parse HEAD))" >> release.log
echo "=== Release completed successfully! ==="#!/bin/bash
set -e
CURRENT_DIR="/srv/apps/cms/current"
RELEASES_DIR="/srv/apps/cms/releases"
echo "=== Finding previous release ==="
PREVIOUS=$(ls -t "$RELEASES_DIR" | sed -n '2p')
if [ -z "$PREVIOUS" ]; then
echo "Error: No previous release found"
exit 1
fi
echo "=== Rolling back to $PREVIOUS ==="
ssh user@server << EOF
rm -f "$CURRENT_DIR"
ln -s "$RELEASES_DIR/$PREVIOUS" "$CURRENT_DIR"
pm2 reload deploy/pm2.config.cjs
sleep 10
curl -f http://localhost:8080/health || exit 1
EOF
echo "=== Rollback completed successfully! ==="
echo "$(date) - Rolled back to $PREVIOUS" >> rollback.logimport { test, expect } from '@playwright/test';
test.describe('Post-release Smoke Test', () => {
test('Health check passes', async ({ request }) => {
const res = await request.get('http://cms.example.com/health');
expect(res.ok()).toBeTruthy();
const data = await res.json();
expect(data.status).toBe('ok');
});
test('Homepage is accessible', async ({ page }) => {
await page.goto('http://cms.example.com');
await expect(page).toHaveTitle(/CMS/);
});
test('Login works', async ({ page }) => {
await page.goto('http://cms.example.com/login');
await page.fill('input[name="email"]', 'admin@test.com');
await page.fill('input[name="password"]', 'Test1234!');
await page.click('button[type="submit"]');
await expect(page).toHaveURL(/dashboard/);
});
test('Core API works', async ({ request }) => {
const res = await request.get('http://cms.example.com/api/v1/content-types', {
headers: { Authorization: 'Bearer test-token' }
});
expect(res.ok()).toBeTruthy();
});
});# Release Checklist - CMS v1.0.0
## Pre-release Check
- [ ] All tests passed (UT + E2E)
- [ ] Reviewer approved
- [ ] QA accepted
- [ ] Disk space > 20%
- [ ] Database backup completed (if migration exists)
- [ ] Rollback script tested and passed
## In-release Check
- [ ] Build artifact checksum verified
- [ ] Dependency installation successful
- [ ] Health check passed (`/health` returns 200)
- [ ] PM2 reload has no errors
- [ ] Post-release smoke test passed
## Post-release Check
- [ ] Monitoring metrics are normal (CPU/Mem/QPS/P95)
- [ ] No surge in error rate
- [ ] No abnormal logs
- [ ] User feedback is normal
## Rollback Preparation
- [ ] Previous stable version: 2025-10-28-1100
- [ ] Rollback script: `deploy/rollback.sh`
- [ ] Rollback time: ≤3 minutes
- [ ] Rollback contact: ops@example.com{
"taskId": "CMS-D-002",
"title": "Write One-click Release and Rollback Scripts",
"department": "Deploy",
"createdByRole": "Planner",
"description": "Write one-click release script (release.sh) and rollback script (rollback.sh) that support zero-downtime deployment, health check, and post-release smoke test. Rollback time ≤3 minutes.",
"acceptanceCriteria": [
"Release script includes 7-step process (packaging/upload/extraction/installation/health check/switch/smoke test)",
"Rollback script can restore the previous stable version within ≤3 minutes",
"Post-release smoke test covers health check/homepage/login/core API"
],
"technicalRequirements": [
"Write deploy/release.sh",
"Write deploy/rollback.sh",
"Write tests/e2e/smoke/post-release.spec.ts",
"Write deploy/release-checklist.md"
],
"dependencies": ["CMS-B-012", "CMS-F-008"],
"estimatedHours": 8,
"priority": "P0",
"tags": ["deploy", "ops"],
"deliverables": [
"deploy/release.sh",
"deploy/rollback.sh",
"tests/e2e/smoke/post-release.spec.ts",
"deploy/release-checklist.md"
],
"aiPromptSuggestion": {
"system": "You are CodeBuddy Deploy, proficient in PM2 + Nginx + BT Panel deployment.",
"user": "Please write one-click release script (7-step process) and rollback script (≤3 minutes) that support zero-downtime deployment, health check, and post-release smoke test."
},
"reviewPolicy": {
"requiresReview": true,
"reviewers": ["Reviewer"]
},
"qaPolicy": {
"requiresQA": true,
"testingScope": ["Smoke"]
},
"needsCoordination": [
"Backend: Provide health check endpoint /health",
"QA: Provide post-release smoke test scripts"
],
"status": "Ready"
}# Only release script, no rollback script
# Cannot recover quickly after deployment failurepm2 restart all # No health check, may cause service unavailabilitysudo pm2 start app.js # Security risktar -czf build.tar.gz . # Includes .env file