# AgMission Deployment Guide **Last updated:** April 2026 --- ## Table of Contents - [1 Prerequisites](#1-prerequisites) - [2 Repository and Directory Layout](#2-repository-and-directory-layout) - [3 Deployment Script Reference](#3-deployment-script-reference) - [4 Configuration](#4-configuration) - [5 Deployment Modes](#5-deployment-modes) - [6 Step-by-Step Production Deployment](#6-step-by-step-production-deployment) - [7 PM2 Process Management](#7-pm2-process-management) - [8 Backup and Recovery](#8-backup-and-recovery) - [9 Environment Variables Reference](#9-environment-variables-reference) --- ## 1 Prerequisites **Developer machine (deploying from):** - SSH access to the production server on port `22222` - `rsync` installed - SVN working copy at `~/work/AgMission` - AGN private libraries at `~/work/@agn` - Angular CLI for frontend builds (`npm install -g @angular/cli`) **Production server:** - Node.js 16.20.2 LTS - PM2 (global): `npm install -g pm2` - MongoDB 4.4.x replica set (`rs0`) - RabbitMQ 3.10.7+ - Redis - Nginx 1.10.x+ --- ## 2 Repository and Directory Layout ### Local developer machine ``` ~/work/AgMission/ ├── trunk/Development/ ← main line source ├── branches// ← feature branches └── tags/release-x.y.z/ ← release snapshots ~/work/@agn/ ← private AGN Node.js libraries ``` ### Remote production server ``` /home/agm/apps/ ├── agmission/ ← API server (server/) ├── client/dist/ ← Angular build output ├── gps-server/ ├── track-server/ ├── satloc/ ├── maintainer/ ├── pm2-apps/ ← PM2 JSON configs └── @agn/ ← private libs (rsync'd from ~/work/@agn) ``` --- ## 3 Deployment Script Reference **Script:** `trunk/Others/scripts/deploy/agm-deploy.sh` ### Usage ```bash ./agm-deploy.sh [run_mode] [branch_name] [fe_mode] ``` | Argument | Values | Default | Description | |---|---|---|---| | `run_mode` | `0`, `1`, `2` | `0` | Deployment scope (see table below) | | `branch_name` | `trunk`, `main`, or branch name | `subscription-invoicing` | Source to deploy from | | `fe_mode` | `run`, `dry-run` | `run` | Frontend deploy behaviour (mode 2 only) | | `run_mode` | Backend | Frontend | Use case | |---|---|---|---| | `0` (or empty) | Dry run | Dry run | Verify what would be synced | | `1` | Deploy | Skipped | Backend-only update | | `2` | Deploy | Deploy | Full production deployment | ### Configuration file recommended ```bash # 1. Copy template cp trunk/Others/scripts/deploy/agm-deploy.conf.template ~/.agm-deploy.conf # 2. Edit values nano ~/.agm-deploy.conf # 3. Use it source ~/.agm-deploy.conf && ./agm-deploy.sh 1 trunk ``` ### Environment variable overrides | Variable | Default | Description | |---|---|---| | `AGM_BASE_DIR` | `~/work/AgMission` | Local AgMission SVN root | | `AGN_LIBS_DIR` | `~/work/@agn` | Local AGN private libraries | | `AGM_DEST_HOST` | `agm@agmission-1.agnav.com` | SSH target (`user@host`) | | `AGM_DEST_PORT` | `22222` | SSH port | | `AGM_DEST_PATH` | `/home/agm/apps` | Remote base directory | --- ## 4 Configuration ### Excluded files `trunk/Others/scripts/deploy/excludes.txt` lists paths excluded from `rsync`. These typically include: - `node_modules/` - `.env` / `environment*.env` (never overwrite production secrets) - `.tmp/`, `job-unzip/`, `job-uploads/` - Log files and rlog crash reports ### Production environment files Environment files are **not** deployed by the script. They must be maintained manually on the production server. See [9 Environment Variables Reference](#9-environment-variables-reference) for key variables. --- ## 5 Deployment Modes ### Dry run mode 0 ```bash ./agm-deploy.sh 0 trunk ``` Shows all files that would be synced without touching the server. Always run this first when deploying after a significant code change. ### Backend only mode 1 ```bash ./agm-deploy.sh 1 trunk ``` Deploys: - `server/` → `/home/agm/apps/agmission/` - `gps-server/` → `/home/agm/apps/gps-server/` - `track-server/` → `/home/agm/apps/track-server/` - `shared/` → `/home/agm/apps/shared/` - `@agn` libraries → `/home/agm/apps/@agn/` After sync, run `pm2 reload` on the server (see [7 PM2 Process Management](#7-pm2-process-management)). ### Full deployment mode 2 ```bash ./agm-deploy.sh 2 trunk ``` Deploys everything in mode 1, plus the Angular frontend `client/dist/` to the Nginx webroot. **Before running mode 2**, build the frontend locally: ```bash cd trunk/Development/client npm install npm run build-prod # builds all locales: en, pt, es ``` --- ## 6 Step-by-Step Production Deployment ```mermaid graph TD A["1. Update SVN working copy
svn update trunk/"] --> B["2. Run tests
cd server && npm test"] B --> C["3. Build frontend
cd client && npm run build-prod"] C --> D["4. Dry run
./agm-deploy.sh 0 trunk"] D --> E{"Review OK?"} E -- No --> F["Fix issues"] F --> D E -- Yes --> G["5. Deploy backend
./agm-deploy.sh 1 trunk"] G --> H["6. SSH to server
ssh agm@agmission-1.agnav.com -p 22222"] H --> I["7. Install dependencies
cd /home/agm/apps/agmission && npm install --production"] I --> J["8. Reload PM2
pm2 reload agmission-prod"] J --> K["9. Check logs
pm2 logs agmission-prod --lines 50"] K --> L{"Errors?"} L -- Yes --> M["Rollback: pm2 reload with previous snapshot"] L -- No --> N["10. Deploy frontend (if needed)
./agm-deploy.sh 2 trunk"] ``` ### Post-deployment checklist - [ ] `pm2 status` — all processes show `online` - [ ] `pm2 logs agmission-prod --lines 20` — no crash errors - [ ] Health check endpoint: `curl https://agmission-1.agnav.com/api/health` - [ ] Login to the web UI and confirm dashboard loads - [ ] If partner workers were updated: `pm2 reload partner_sync_worker partner_data_polling_worker` - [ ] If worker code changed: check `pm2 logs job_worker --lines 20` --- ## 7 PM2 Process Management ### Start all services first time ```bash # SSH into server ssh agm@agmission-1.agnav.com -p 22222 # Start all configured apps /home/agm/apps/pm2-apps/start_pm2_apps.sh ``` ### Reload after deployment ```bash # Reload individual app (zero-downtime) pm2 reload agmission-prod # Reload all at once pm2 reload all # Check status pm2 status pm2 logs agmission-prod --lines 30 ``` ### Process list ```bash pm2 list ``` Expected processes: | Name | Status | |---|---| | `agmission-prod` | online | | `track_server` | online | | `gps_server-agnav` | online | | `gps_server-rap` | online | | `job_worker` | online | | `invoice_worker` | online | | `cleanup_worker` | online | | `partner_sync_worker` | online | | `partner_data_polling_worker` | online | ### Restart a single worker ```bash pm2 restart job_worker pm2 restart partner_sync_worker pm2 restart invoice_worker ``` ### Save current PM2 process list ```bash pm2 save ``` --- ## 8 Backup and Recovery ### Automated backup `trunk/Others/scripts/backup_agm.sh` runs via cron. It: 1. Dumps MongoDB to a gzip archive (`mongodump --gzip`) 2. Retains 11 days of database archives 3. Syncs archives to NAS via `rsync` (`rsync://rsync@data.agnav.com/agm/`) 4. Syncs uploaded job files separately 5. Syncs rsync log files ### Manual MongoDB backup ```bash mongodump \ --archive=/home/agm/backups/manual_$(date +%Y%m%d).gz \ --gzip \ --db agmission \ --username agm \ --authenticationDatabase agmission ``` ### Restore from backup ```bash mongorestore \ --archive=/home/agm/backups/agmdb_YYYYMMDD.gz \ --gzip \ --db agmission \ --username agm \ --authenticationDatabase agmission \ --drop ``` --- ## 9 Environment Variables Reference Environment files live on the production server at `/home/agm/apps/agmission/environment.env` and are **not** managed by the deployment script. ### Core server | Variable | Description | |---|---| | `AGM_PORT` | HTTP port the API server listens on (e.g., `7000`) | | `PRODUCTION` | `true` in production | | `DB_USR` / `DB_PWD` / `DB_NAME` | MongoDB credentials | | `DB_HOSTS` | MongoDB host list (replica set) | | `DB_REPLSET` | Replica set name (`rs0`) | | `REDIS_PWD` | Redis password | | `JWT_SECRET` | JWT signing secret | | `MAX_SESSION_SECS` | Session token lifetime (default: 28800) | ### Stripe billing | Variable | Description | |---|---| | `STRIPE_SECRET_KEY` | Stripe secret key | | `STRIPE_PUBLISHABLE_KEY` | Stripe publishable key | | `STRIPE_API_VERSION` | Stripe API version | | `STRIPE_WH_SEC` | Stripe webhook signing secret | | `ESS_1` … `ESS_5` | Stripe price IDs for Essential plans | | `ENT_1` … `ENT_4` | Stripe price IDs for Enterprise plans | | `ADDON_1` | Stripe price ID for add-on | ### File storage | Variable | Description | |---|---| | `UPLOAD_DIR` | Job upload directory | | `UNZIP_DIR` | Temp extraction directory | | `INV_UPLOAD_DIR` | Invoice image upload directory | | `INV_IMG_VIR_DIR` | Virtual URL path for invoice images | | `SATLOC_STORAGE_PATH` | Local storage for downloaded SatLoc log files | ### RabbitMQ | Variable | Description | |---|---| | `QUEUE_HOST` | RabbitMQ host | | `QUEUE_PORT` | RabbitMQ port (default: 5672) | | `QUEUE_USR` / `QUEUE_PWD` | RabbitMQ credentials | | `QUEUE_VHOST` | Virtual host | | `QUEUE_NAME_JOBS` | Job processing queue name | | `QUEUE_NAME_GDATA` | GPS data queue name | | `QUEUE_NAME_PARTNER` | Partner tasks queue name | ### Partner integration | Variable | Description | |---|---| | `SATLOC_API_ENDPOINT` | SatLoc Cloud base URL | | `SATLOC_API_TIMEOUT` | HTTP request timeout (ms) | | `PARTNER_SYNC_INTERVAL` | Partner sync interval (ms) | | `PARTNER_HEALTH_CHECK_INTERVAL` | Health check interval (ms) | | `PARTNER_MAX_RETRIES` | Max retry attempts before DLQ | | `DLQ_CHECK_INTERVAL` | DLQ monitoring interval (ms) | --- *See [ARCHITECTURE.md](ARCHITECTURE.md) for full system design documentation.*