| name | devops-deployment |
| description | Environment configuration, CI/CD conventions, Vercel deployment standards, PM2 process management, Git workflow automation, and environment variable management for TopNetworks properties. Use when configuring deployments, managing environments, running builds, or setting up new projects. |
DevOps / Deployment — TopNetworks, Inc.
This skill governs environment configuration, deployment pipelines, and operational procedures across all TopNetworks properties. Derived from route-genius (Vercel + PR-based promotion), topfinanzas-us-next (PM2 + Apache on GCP Compute Engine), and emailgenius-broadcasts-generator (GCP Compute Engine + PM2).
Scope
Use for: Local development setup, environment variable configuration, build commands, deployment procedures (Vercel and self-hosted), PM2 process management, git workflow automation, and branch promotion strategies.
Not for: Application code (see frontend, backend, database skills), schema migrations (see database skill), or auth configuration (see authentication skill).
Deployment Models by Project
| Project | Host | Method | Branch Strategy |
|---|
| route-genius | Vercel | PR-based promotion | dev → staging → main |
| topfinanzas-us-next | GCP Compute Engine | PM2 + Apache reverse proxy | dev → main → backup |
| uk-topfinanzas-com | GCP Compute Engine | PM2 + Apache reverse proxy | dev → main → backup |
| topfinanzas-mx-next | GCP Compute Engine | PM2 + Apache reverse proxy | dev → main → backup |
| budgetbee-next | GCP Compute Engine | PM2 + Apache reverse proxy | dev → main → backup |
| kardtrust | GCP Compute Engine | PM2 + Apache reverse proxy | dev → main → backup |
| mejoresfinanzas | Netlify / Vercel | Static build (Astro) | main |
| emailgenius-broadcasts-generator | GCP Compute Engine | PM2 | main |
| topAds-main | GCP Compute Engine | Docker + Nginx | main |
| arbitrage-manager-dashboard | Google Cloud Run | Container | main |
Development Environment Setup
Standard Setup (Next.js Projects)
git clone git@github.com:TopNetworks/[repo-name].git
cd [repo-name]
npm install
cp .env.example .env.local
npm run dev
Port Assignments
| Project | Dev Port |
|---|
| topfinanzas-us-next | 3040 |
| uk-topfinanzas-com | 3004 |
| kardtrust | 3005 |
| budgetbee-next | 3007 |
| emailgenius-broadcasts-generator | 3020 |
| route-genius | 3070 |
| mejoresfinanzas (Astro) | 4322 |
When starting a project on its assigned port:
"dev": "next dev --port 3040"
npm run dev -- --port 3040
Astro Projects (mejoresfinanzas, financial-blog-template)
pnpm install
pnpm dev
pnpm build
pnpm preview
Branch Strategy
Route-Genius (Vercel — PR-Based Promotion)
Strict linear promotion pipeline. No shortcuts.
dev ──PR──▶ staging ──PR──▶ main
│ │ │
localhost:3070 route-genius route.topnetworks.co
.vercel.app
Branch roles:
| Branch | Purpose | Who commits | Deploys to |
|---|
dev | Active development | All developers | Local only |
staging | Pre-production QA | PR merge from dev | Vercel preview |
main | Production | PR merge from staging | Vercel production |
Promotion requirements:
dev → staging: PR must pass lint + build checks, ≥1 approving review
staging → main: QA validation documented in PR description, ≥1 approving review
Prohibited:
- Direct commits to
staging or main
- Force-push to
staging or main
- Merging
dev directly into main (skipping staging)
git checkout dev
git pull origin dev
git add [specific files]
git commit -m "feat: description of change"
git push origin dev
Financial Content Platforms (GCP — Automated Script)
These projects use an automated git workflow script. NEVER bypass this script.
bash ./scripts/git-workflow.sh
The script:
- Reads commit message from
lib/documents/commit-message.txt
- Stages all changes and commits to
dev branch
- Optionally merges to
main and backup branches
- Handles merge conflicts automatically
Trigger phrase (when user says "Push and commit our latest changes"):
- Clear
lib/documents/commit-message.txt
- Run
git status to review changes
- Write accurate commit message to
lib/documents/commit-message.txt
- Execute
bash ./scripts/git-workflow.sh
Vercel Deployment Configuration
vercel.json (route-genius)
{
"buildCommand": "npm run build",
"outputDirectory": ".next",
"framework": "nextjs",
"env": {
"NEXT_PUBLIC_APP_URL": "@next-public-app-url"
}
}
Environment variables are configured in the Vercel dashboard per environment (Development, Preview, Production). Never commit actual env values to the repository.
next.config.mjs (Common Configuration)
const nextConfig = {
images: {
remotePatterns: [
{
protocol: "https",
hostname: "storage.googleapis.com",
},
{
protocol: "https",
hostname: "lh3.googleusercontent.com",
},
],
},
experimental: {
turbopack: true,
},
};
export default nextConfig;
PM2 Production Deployment (GCP Compute Engine)
All self-hosted Next.js properties run under PM2 on Ubuntu 22.04 VMs managed as www-data user.
Standard Deployment Procedure
ssh [vm-address]
cd /var/www/html/[project-name]
sudo -u www-data git pull origin main
sudo -u www-data npm install
sudo -u www-data npm run build
sudo -u www-data pm2 restart [app-name]
sudo -u www-data pm2 status
sudo -u www-data pm2 logs [app-name] --lines 50
PM2 ecosystem.config.js
module.exports = {
apps: [
{
name: "topfinanzas-us",
script: "node_modules/.bin/next",
args: "start --port 3040",
cwd: "/var/www/html/topfinanzas-us-next",
env: {
NODE_ENV: "production",
PORT: 3040,
},
instances: 1,
autorestart: true,
watch: false,
max_memory_restart: "1G",
},
],
};
Common PM2 Commands
sudo -u www-data pm2 status
sudo -u www-data pm2 restart [name]
sudo -u www-data pm2 stop [name]
sudo -u www-data pm2 start ecosystem.config.js
sudo -u www-data pm2 save
sudo -u www-data pm2 startup
sudo -u www-data pm2 logs [name] --lines 50
sudo -u www-data pm2 monit
sudo -u www-data pm2 describe [name]
Apache Reverse Proxy Configuration
Apache 2.0 sits in front of PM2 processes and handles SSL termination:
# /etc/apache2/sites-available/topfinanzas-us.conf
<VirtualHost *:443>
ServerName us.topfinanzas.com
SSLEngine on
SSLCertificateFile /etc/letsencrypt/live/us.topfinanzas.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/us.topfinanzas.com/privkey.pem
ProxyPreserveHost On
ProxyPass / http://localhost:3040/
ProxyPassReverse / http://localhost:3040/
# Headers
Header always set X-Content-Type-Options nosniff
Header always set X-Frame-Options DENY
</VirtualHost>
SSL certificates managed by Let's Encrypt (Certbot). Renewal is automatic via cron.
Environment Variable Management
Naming Conventions
NEXT_PUBLIC_SUPABASE_URL=
NEXT_PUBLIC_APP_URL=
NEXT_PUBLIC_GTM_ID=
NEXT_PUBLIC_GA_MEASUREMENT_ID=
SUPABASE_SERVICE_ROLE_KEY=
GOOGLE_CLIENT_SECRET=
BREVO_API_KEY=
DATABASE_URL=
GOOGLE_PRIVATE_KEY=
Required Variables by Project Type
All Next.js financial platforms:
NEXT_PUBLIC_GTM_ID=
NEXT_PUBLIC_GOOGLE_ADS_ID=
BREVO_API_KEY=
NEXT_PUBLIC_ENABLE_LOGGING=
Route-Genius:
NEXT_PUBLIC_APP_URL=
NEXT_PUBLIC_SUPABASE_URL=
SUPABASE_SERVICE_ROLE_KEY=
DATABASE_URL=
GOOGLE_CLIENT_ID=
GOOGLE_CLIENT_SECRET=
GCS_PROJECT_ID=
GCS_CLIENT_EMAIL=
GCS_PRIVATE_KEY=
GOOGLE_DRIVE_CLIENT_ID=
GOOGLE_DRIVE_CLIENT_SECRET=
NEXT_PUBLIC_GOOGLE_PICKER_API_KEY=
NEXT_PUBLIC_FIREBASE_API_KEY=
NEXT_PUBLIC_FIREBASE_PROJECT_ID=
NEXT_PUBLIC_GA_MEASUREMENT_ID=
DISABLE_RATE_LIMITING=
EmailGenius:
GOOGLE_CLOUD_PROJECT=
GOOGLE_SERVICE_ACCOUNT_EMAIL=
GOOGLE_PRIVATE_KEY=
DB_HOST=
DB_PORT=5432
DB_NAME=
DB_USER=
DB_PASSWORD=
CONVERTKIT_API_KEY=
.env File Structure
Every project should have:
.env.example # Template — committed to git (no real values)
.env.local # Local development — gitignored
.env.production # Production values — never committed to git
.env.example format:
NEXT_PUBLIC_APP_URL=https://your-app.example.com
DATABASE_URL=postgres://user:password@host:5432/dbname
NEXT_PUBLIC_ENABLE_LOGGING=false
DISABLE_RATE_LIMITING=false
Build Scripts
Standard Next.js Commands
npm run dev
npm run build
npm run start
npm run lint
npm run format
Important for route-genius (Next.js 16):
npx eslint .
npm run lint
Pre-Deployment Checklist
Before deploying to staging or production:
Google Cloud Platform
Compute Engine VM Management
gcloud compute ssh [instance-name] --zone [zone] --project [project-id]
df -h
node --version
npm cache clean --force
sudo -u www-data pm2 startup systemd -u www-data --hp /home/www-data
Cloud Storage (Media CDN)
Media assets are served from Google Cloud Storage:
- Bucket:
media-topfinanzas-com
- Public URL:
https://storage.googleapis.com/media-topfinanzas-com/
- Path structure:
images/{market}/{filename}.webp
Upload new media assets:
gsutil cp local-image.webp gs://media-topfinanzas-com/images/us/image-name.webp
gsutil acl ch -u AllUsers:R gs://media-topfinanzas-com/images/us/image-name.webp
Docker Deployment (topAds-main)
docker build -t topads-main .
docker run -d \
--name topads \
--restart unless-stopped \
-p 8080:8080 \
--env-file .env \
topads-main
Cloud Run (arbitrage-manager-dashboard — Python FastAPI)
gcloud builds submit --tag gcr.io/[project-id]/arbitrage-dashboard
gcloud run deploy arbitrage-dashboard \
--image gcr.io/[project-id]/arbitrage-dashboard \
--platform managed \
--region us-central1 \
--allow-unauthenticated \
--set-env-vars META_ACCESS_TOKEN=[token]
Troubleshooting Common Issues
Build Failures
rm -rf .next
npm run build
npx tsc --noEmit
rm -rf node_modules package-lock.json
npm install
PM2 Issues
sudo -u www-data pm2 logs [name] --lines 100 --err
sudo lsof -i :[port]
sudo kill -9 [pid]
sudo -u www-data pm2 startup
sudo -u www-data pm2 save
Environment Variable Issues
sudo -u www-data pm2 env [app-id]
sudo -u www-data pm2 reload [name]
Logging (Production)
Pino logger writes to stdout/stderr. PM2 captures and rotates logs automatically.
sudo -u www-data pm2 logs [name]
sudo -u www-data pm2 logs [name] --err
sudo -u www-data pm2 flush [name]
ls /home/www-data/.pm2/logs/
Logger is disabled by default in production. Enable with:
NEXT_PUBLIC_ENABLE_LOGGING=true
sudo -u www-data pm2 reload [name]
Constraints
- Never commit actual environment variable values to git — use
.env.example for templates
- Never use
npm install -g on production VMs — install locally per project
- Never bypass the automated git workflow script (
git-workflow.sh) in financial platform repos
- Never push directly to
main in route-genius — always go through dev → staging → main
- Never use
pm2 kill in production — use pm2 restart or pm2 reload (graceful)
- Never run
npm install or npm run build as root — always sudo -u www-data
- Never force-push to
staging or main branches
- The
GOOGLE_PRIVATE_KEY environment variable contains literal \n characters that must be replaced with actual newlines: .replace(/\\n/g, '\n')
- Vercel preview deployments (from
staging branch) are ephemeral — do not use preview URLs for production testing
- SSL certificates (Let's Encrypt) renew automatically — do not manually renew unless expiry is imminent and auto-renewal has failed