373 lines
9.8 KiB
Markdown
373 lines
9.8 KiB
Markdown
# 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/<branch-name>/ ← 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<br/>svn update trunk/"] --> B["2. Run tests<br/>cd server && npm test"]
|
|
B --> C["3. Build frontend<br/>cd client && npm run build-prod"]
|
|
C --> D["4. Dry run<br/>./agm-deploy.sh 0 trunk"]
|
|
D --> E{"Review OK?"}
|
|
E -- No --> F["Fix issues"]
|
|
F --> D
|
|
E -- Yes --> G["5. Deploy backend<br/>./agm-deploy.sh 1 trunk"]
|
|
G --> H["6. SSH to server<br/>ssh agm@agmission-1.agnav.com -p 22222"]
|
|
H --> I["7. Install dependencies<br/>cd /home/agm/apps/agmission && npm install --production"]
|
|
I --> J["8. Reload PM2<br/>pm2 reload agmission-prod"]
|
|
J --> K["9. Check logs<br/>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)<br/>./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.*
|