28 KiB
AgMission SaaS Platform Software Architecture
Version: 3.2.x
Last updated: April 2026
Author: AgNav Engineering
Table of Contents
- AgMission SaaS Platform Software Architecture
- Table of Contents
- 1 Product Overview
- 2 System Components
- 3 High-Level Architecture
- 4 Component Details
- 5 Data Architecture
- 6 Message Queue Architecture
- 7 Partner Integration Architecture
- 8 Billing and Subscription Architecture
- 9 Authentication and Authorization
- 10 Infrastructure and Deployment
- 11 Key Data Flows
- 12 Repository Layout
1 Product Overview
AgMission is a cloud-based SaaS platform for precision aerial agriculture management. It serves agricultural aviation operators (applicators), their clients (growers/farmers), and integrated partners with console navigation aid systems (such as AgNav—Platinum and Titanium—and SatLoc).
The platform manages the complete lifecycle of an aerial application job:
- Mission planning — create jobs, define treatment areas, assign pilots and jobs to aircraft
- Job distribution — push assigned jobs to guidance console systems, in aircraft, on the field
- Real-time tracking — live GPS monitoring of aircraft during operations
- Post-flight processing — parse binary GPS/spray logs from console systems, compute coverage statistics
- Reporting and billing — generate application reports, manage invoices, and handle SaaS subscriptions
Supported languages: English, Portuguese (pt), Spanish (es)
2 System Components
| Component | Technology | Purpose |
|---|---|---|
| Web Client | Angular 9.1.13, NgRx 9, Leaflet 1.9, StimulSoftJS 2020.3.2 | Browser-based management UI and report viewer |
| API Server | Node.js 16.20.2 LTS, Express 4, Mongoose 6 | Core REST API, business logic |
| GPS Server | Node.js, TCP sockets | Receives GPS data from AgNav (Platinum, Titanium) and RAP devices |
| Track Server | Node.js, Express, SSE | Real-time GPS tracking feed to browser |
| SatLoc Service | Node.js | Partner integration with SatLoc Cloud |
| Job Worker | Node.js, RabbitMQ | Async processing of uploaded job files |
| Invoice Worker | Node.js, Cron | Job Invoicing—manages applicator invoices for jobs performed |
| Partner Sync Worker | Node.js, RabbitMQ | Partner job upload and log processing |
| Partner Polling Worker | Node.js, Cron | Polls partner systems for new flight data |
| Cleanup Worker | Node.js, Cron | Purges soft-deleted data |
| Maintainer | Node.js, Cron | Scheduled database maintenance |
3 High-Level Architecture
graph TD
subgraph "Field Devices"
AGN["AgNav Guidance<br/>System"]
RAP["RAP Guidance<br/>System"]
SLC["SatLoc Cloud<br/>Partner"]
end
subgraph "Browser"
UI["Angular SPA<br/>(Web Client)"]
end
subgraph "AgMission Backend (agnav.com server)"
NGINX["Nginx<br/>Reverse Proxy"]
API["API Server<br/>Node.js / Express"]
GPS["GPS Server<br/>TCP :6080 / :6082"]
TRK["Track Server<br/>HTTP/SSE"]
MNT["Maintainer<br/>Cron Service"]
JW["Job Worker"]
IW["Invoice Worker"]
PSW["Partner Sync Worker"]
PPW["Partner Polling Worker"]
CW["Cleanup Worker"]
end
subgraph "Data Layer"
MDB["MongoDB<br/>Replica Set"]
RBT["RabbitMQ<br/>Message Broker"]
RDS["Redis<br/>Cache"]
end
subgraph "External Services"
STR["Stripe<br/>Billing"]
SLC2["SatLoc Cloud API<br/>satloccloudfc.com"]
SMTP["Email / SMTP"]
end
AGN -- "TCP :6080" --> GPS
RAP -- "TCP :6082" --> GPS
UI -- "HTTPS" --> NGINX
NGINX -- "/" --> API
NGINX -- "/track" --> TRK
GPS -- "AMQP gdata queue" --> RBT
RBT -- "consume gdata" --> TRK
TRK -- "SSE" --> UI
API -- "AMQP jobs / partner_tasks" --> RBT
RBT -- "consume jobs" --> JW
RBT -- "consume partner_tasks" --> PSW
API --> MDB
JW --> MDB
IW --> MDB
PSW --> MDB
PPW --> MDB
CW --> MDB
MNT --> MDB
API --> RDS
JW --> RDS
API --> STR
PSW -- "REST" --> SLC2
PPW -- "REST / cron" --> SLC2
PPW -- "AMQP partner_tasks" --> RBT
4 Component Details
4-1 Web Client Angular SPA
Location: trunk/Development/client/
Version: 2.6.15
The frontend is a single-page application built with Angular 9 and served by Nginx. It communicates with the API Server over HTTPS and receives real-time GPS updates from the Track Server via Server-Sent Events (SSE).
Module structure
graph TD
ROOT["AppModule<br/>(app.module.ts)"]
ROOT --> AUTH["AuthModule<br/>Login, signup, password reset"]
ROOT --> DASH["DashboardModule<br/>Overview metrics"]
ROOT --> JOBS["JobModule<br/>Mission management<br/>Map editing, file upload"]
ROOT --> TRACK["TrackModule<br/>Live GPS tracking map"]
ROOT --> CUST["CustomerModule<br/>Client / grower management"]
ROOT --> BILL["BillingModule<br/>Subscription and invoices"]
ROOT --> INV["InvoicesModule<br/>Invoice listing and detail"]
ROOT --> PART["PartnersModule<br/>Partner system users"]
ROOT --> ADM["AdminModule<br/>Platform admin tools"]
ROOT --> SET["SettingsModule<br/>User and account settings"]
ROOT --> REP["ReportComponent<br/>PDF report viewer"]
ROOT --> SIGN["SignupModule<br/>Self-service subscription signup"]
State management NgRx
The app uses NgRx (Redux pattern) for global state:
- Store — single source of truth for session, entities, and UI state
- Effects — side-effects (HTTP calls) triggered by dispatched actions
- Entities — normalized collections (jobs, customers, pilots, vehicles, etc.)
- Reducers — pure state transitions
Key features
| Feature | Description |
|---|---|
| Job map editor | Leaflet map for defining treatment areas, waypoints, and obstacles |
| Live tracking | Real-time aircraft position overlay via SSE |
| Data playback | Replay completed flight paths from application logs |
| Invoicing | Create, send, and track invoices |
| Subscription management | Self-serve plan selection, trial, and upgrade; manage billing information; integrate with Stripe |
| Multi-language | English / Portuguese / Spanish via Angular i18n |
| Partner customers | View and manage SatLoc partner-linked customer accounts; support Satloc console systems, G4, Falcon in automated workflows |
4-2 API Server
Location: trunk/Development/server/
Entry point: server.js
Port: AGM_PORT (default 7000 in production)
The central Express application. All browser requests pass through Nginx which proxies to this server. It handles authentication, all business logic REST endpoints, file uploads, Stripe webhooks, and report generation.
Request lifecycle
sequenceDiagram
participant C as Client (Browser)
participant N as Nginx
participant S as API Server
participant MW as Middlewares
participant R as Routes
participant CTL as Controller
participant DB as MongoDB
C->>N: HTTPS request
N->>S: HTTP proxy (X-Forwarded-*)
S->>MW: Rate limiter
MW->>MW: JWT checkUser
MW->>R: Router dispatch
R->>CTL: Handler function
CTL->>DB: Mongoose queries
DB-->>CTL: Documents
CTL-->>C: JSON response
Route groups
| Route prefix | Controller | Description |
|---|---|---|
/api/users |
user.js | User account CRUD |
/api/customers |
customer.js | Applicator / client management |
/api/jobs |
job.js | Mission lifecycle |
/api/upload |
upload_job.js | Job file upload (ZIP/KML/SHP) |
/api/pilots |
pilot.js | Pilot management |
/api/vehicles |
vehicle.js | Aircraft management |
/api/billing |
billing.js | Stripe subscription billing |
/api/subscription |
subscription.js | Subscription plans |
/api/invoices |
invoice.js | Invoice management |
/api/invoice_settings |
invoice_settings.js | Invoice templates |
/api/partners |
partner.js | Partner org and system users |
/api/dlq/:queue |
dlq.js | Dead Letter Queue management |
/api/export |
export.js | Data export (CSV/IIF) |
/api/v1 |
api_pub.js | Public data export API (API-key auth) |
/api/health |
health.js | Health check endpoint |
/stripe_webhooks |
subscription_webhooks.js | Stripe event webhook |
Key server-side helpers
| Helper | Purpose |
|---|---|
helpers/constants.js |
Frozen enums (UserTypes, AppStatus, etc.) |
helpers/env.js |
Typed environment variable access |
helpers/subscription_util.js |
Stripe SDK wrappers |
helpers/job_util.js |
Job state machine logic |
helpers/geo_util.js |
Geospatial calculations (turf.js) |
helpers/satloc_log_parser.js |
Binary SatLoc log file parser |
helpers/satloc_application_processor.js |
Spray statistics from parsed logs |
helpers/mailer.js |
Transactional email |
helpers/logger.js |
Pino structured logging |
4-3 GPS Server
Location: trunk/Development/gps-server/
Entry point: gps-server.js
Ports: TCP 6080 (AgNav), TCP 6082 (RAP)
A low-level TCP socket server that receives binary GPS telemetry from field console navigation aid systems (AgNav, RAP) in real-time.
How it works
sequenceDiagram
participant D as AgNav / RAP Console System
participant G as GPS Server (TCP)
participant MDB as MongoDB
participant RBT as RabbitMQ
D->>G: TCP binary packet
G->>G: Parse (AgNavParser / RAPParser)
G->>MDB: Upsert location + location_cache
G->>RBT: Publish to "gdata" queue
Two protocol variants are configured via PROTOCOL env var:
| Protocol | Port | Device type |
|---|---|---|
AGNAV |
6080 | AgNav console system (Platinum, Titanium) |
RAP |
6082 | RAP binary protocol (external tracking devices) |
The GPS Server writes every position to MongoDB (locations + location_cache collections) and simultaneously publishes to a RabbitMQ queue gdata, which the Track Server consumes for live SSE streaming.
4-4 Track Server
Location: trunk/Development/track-server/
Entry point: track-server.js
Protocol: HTTP/2 (via spdy) + Server-Sent Events
The Track Server bridges the real-time GPS queue to browser clients using SSE channels. Each client subscribes to one or more vehicle channels; the server pushes position updates as they arrive from RabbitMQ.
sequenceDiagram
participant RBT as RabbitMQ gdata
participant TS as Track Server
participant BR as Browser (SSE client)
RBT-->>TS: GPS data message
TS->>TS: setVehGpsData(data)
TS->>BR: SSE event (vehicle position)
Authentication is JWT-based — clients obtain a short-lived track token from the API Server, then connect to Track Server with it.
4-5 SatLoc Integration Service
Location: trunk/Development/satloc/
Purpose: Batch job of importing completed flight logs from the SatLoc Cloud partner system.
SatLoc is an aerial guidance hardware vendor. When an applicator uses SatLoc hardware, their flight logs are stored in SatLoc's cloud. This service:
- Authenticates with SatLoc Cloud (
satloccloudfc.com) - Retrieves aircraft log metadata
- Downloads binary log files
- Parses the proprietary binary format
- Creates
ApplicationDetailrecords in AgMission's database
The core C# parsing logic (frmMain.cs, APIObjects.cs) is the original reference implementation; the production path is the Node.js port in satloc-api.js and the server-side helpers/satloc_log_parser.js.
4-6 Background Workers
All workers are independent Node.js processes managed by PM2. They communicate via RabbitMQ queues and share the same MongoDB instance as the API Server.
Worker overview
graph LR
API["API Server"] -- "publish jobs" --> JQ["jobs queue<br/>(RabbitMQ)"]
API -- "publish partner_tasks" --> PQ["partner_tasks queue<br/>(RabbitMQ)"]
JQ --> JW["Job Worker<br/>job_worker.js"]
PQ --> PSW["Partner Sync Worker<br/>partner_sync_worker.js"]
PPW["Partner Polling Worker<br/>(cron every 15 min)"] -- "publish partner_tasks" --> PQ
PPW -- "REST poll" --> SLCAPI["SatLoc Cloud API"]
IW["Invoice Worker<br/>(cron every 1 min)"] --> MDB["MongoDB"]
CW["Cleanup Worker<br/>(cron weekly)"] --> MDB
JW --> MDB
PSW --> MDB
PSW -- "REST" --> SLCAPI
Job Worker
Consumes the jobs RabbitMQ queue. Triggered when a user uploads a job file via the web UI.
Responsibilities:
- Extract ZIP archives containing job data files
- Parse AgNav binary (
.agn), KML, and Shapefile formats - Calculate sprayed area, coverage geometry, application statistics
- Create
Application,ApplicationFile, andApplicationDetailrecords - Use Redis for deduplication and temporary state
Invoice Worker
Cron-driven (every minute). Manages Job Invoicing—the lifecycle of applicator invoices for jobs performed on behalf of clients. Handles invoice state transitions and late-payment notifications.
Note: Job Invoicing is separate from SaaS subscription management (which is handled by Stripe webhooks in the API Server).
stateDiagram-v2
direction LR
[*] --> Draft : invoice created
Draft --> Open : openDate reached
Open --> Overdue : dueDate passed
Open --> Paid : payment received
Overdue --> Paid : late payment
Paid --> [*]
Partner Sync Worker
Consumes the partner_tasks queue. Handles two task types:
| Task type | Action |
|---|---|
UPLOAD_PARTNER_JOB |
Pushes a job (waypoints, boundaries) to SatLoc Cloud for the assigned aircraft |
PROCESS_PARTNER_LOG |
Parses a downloaded SatLoc binary log file and creates ApplicationDetail records |
Partner Data Polling Worker
Cron-driven (every 15 min in production, every 1 min in development).
graph TD
A["Cron trigger"] --> B["Find JobAssigns<br/>status = UPLOADED"]
B --> C["Group by partner + customer"]
C --> D["Call SatLoc: GetAircraftLogs"]
D --> E{"New log<br/>files?"}
E -- No --> F["Done"]
E -- Yes --> G["Download log file<br/>to local storage"]
G --> H["Create PartnerLogTracker<br/>PENDING → DOWNLOADED"]
H --> I["Enqueue PROCESS_PARTNER_LOG<br/>to partner_tasks queue"]
Cleanup Worker
Weekly cron job. Hard-deletes records that have been soft-deleted (markedDelete: true) and older than a retention period. Applies to customers, jobs, pilots, vehicles, and related entities.
4-7 Maintainer Service
Location: trunk/Development/maintainer/
Entry point: index.js
A lightweight cron-based utility for database maintenance tasks not suitable for the main server. Scheduled tasks:
| Task | Schedule (prod) | Description |
|---|---|---|
cleanMarkedDeleteData |
Weekly (Sunday 01:00 UTC) | Remove soft-deleted customer records |
Connects to MongoDB using the same models as the API Server (shared model/ layer).
5 Data Architecture
MongoDB collections
erDiagram
USER {
ObjectId _id
string kind
string email
string name
string userType
boolean active
ObjectId parent
}
CUSTOMER {
ObjectId _id
string name
ObjectId byPuid
}
JOB {
number _id
string name
ObjectId customer
ObjectId byPuid
number status
Date startDate
}
JOB_ASSIGN {
ObjectId _id
number job
ObjectId user
number status
string extJobId
}
APPLICATION {
ObjectId _id
number jobId
string fileName
Date startDateTime
Date endDateTime
number totalSprayed
}
APPLICATION_DETAIL {
ObjectId _id
ObjectId appId
number lat
number lon
number rate
Date gdt
}
SUBSCRIPTION {
ObjectId _id
ObjectId byPuid
string stripeSubId
string planKey
string status
}
INVOICE {
ObjectId _id
ObjectId byPuid
number status
Date openDate
Date dueDate
}
PARTNER_LOG_TRACKER {
ObjectId _id
string status
ObjectId jobAssignId
string localFilePath
}
USER ||--o{ JOB : "creates (byPuid)"
CUSTOMER ||--o{ JOB : "associated"
JOB ||--o{ JOB_ASSIGN : "assigned to"
JOB_ASSIGN }o--|| USER : "pilot/device"
JOB ||--o{ APPLICATION : "contains"
APPLICATION ||--o{ APPLICATION_DETAIL : "detail records"
USER ||--o{ SUBSCRIPTION : "holds"
USER ||--o{ INVOICE : "receives"
JOB_ASSIGN ||--o{ PARTNER_LOG_TRACKER : "tracks"
User type hierarchy
The User model uses a Mongoose discriminator pattern to represent multiple actor types from one collection:
userType code |
Kind | Description |
|---|---|---|
0 |
ADMIN | Platform administrator |
1 |
APP | Applicator (main operator account) |
2 |
APP_ADM | Applicator admin |
3 |
CLIENT | Client / grower (read-only) |
4 |
OFFICER | Field officer |
5 |
PILOT | Pilot |
6 |
INSPECTOR | Inspector |
9 |
DEVICE | Aircraft / guidance unit |
20 |
PARTNER | Partner organization (e.g., SatLoc) |
21 |
PARTNER_SYSTEM_USER | Customer account in partner system |
6 Message Queue Architecture
RabbitMQ is used for all async work. Queue names are auto-prefixed with dev_ in non-production environments.
graph LR
subgraph "Producers"
API["API Server"]
PPW["Partner Polling Worker"]
GPS["GPS Server"]
end
subgraph "Queues (RabbitMQ)"
JQ["jobs"]
PQ["partner_tasks"]
PDLQ["partner_tasks_failed<br/>(DLQ)"]
GQ["gdata"]
end
subgraph "Consumers"
JW["Job Worker"]
PSW["Partner Sync Worker"]
TRK["Track Server"]
end
API --> JQ
API --> PQ
PPW --> PQ
GPS --> GQ
JQ --> JW
PQ --> PSW
PSW -- "on max retries" --> PDLQ
GQ --> TRK
The Dead Letter Queue (partner_tasks_failed) is managed through the /api/dlq/:queueName/* API endpoints, which provide list, retry, and purge operations.
7 Partner Integration Architecture
sequenceDiagram
participant UI as Web Client
participant API as API Server
participant PSW as Partner Sync Worker
participant PPW as Partner Polling Worker
participant SLC as SatLoc Cloud
UI->>API: Assign job to SatLoc device
API->>API: Create JobAssign (status=NEW)
API->>PSW: Enqueue UPLOAD_PARTNER_JOB
PSW->>SLC: POST /api/Satloc/UploadJobData
SLC-->>PSW: extJobId
PSW->>API: Update JobAssign (status=UPLOADED, extJobId)
Note over PPW: Cron: every 15 min
PPW->>API: Find JobAssigns status=UPLOADED
PPW->>SLC: GET /api/Satloc/GetAircraftLogs
SLC-->>PPW: Log list
PPW->>SLC: GET /api/Satloc/GetAircraftLogData
SLC-->>PPW: Binary log file
PPW->>PPW: Store file locally (SATLOC_STORAGE_PATH)
PPW->>API: Create PartnerLogTracker (DOWNLOADED)
PPW->>PSW: Enqueue PROCESS_PARTNER_LOG
PSW->>PSW: Parse binary log (SatLocLogParser)
PSW->>API: Create ApplicationDetail records
Partner credential model
Each customer that uses a SatLoc device has a dedicated PartnerSystemUser record (userType=21) that stores their SatLoc companyId, partnerUserId, and API key. This isolates customer data within the partner system.
8 Billing and Subscription Architecture
sequenceDiagram
participant UI as Web Client
participant API as API Server
participant STR as Stripe
UI->>API: Select subscription plan
API->>STR: Create SetupIntent or Subscription
STR-->>API: Client secret
UI->>STR: Confirm card (3DS if needed)
STR->>API: POST /stripe_webhooks (subscription events)
API->>API: Update Subscription record
Note: SaaS subscription management (tiers, billing cycles) is handled through Stripe webhooks. Job Invoicing (applicators invoicing clients for jobs performed) is a separate function managed by the Invoice Worker.
SaaS Subscription tiers (mapped to Stripe price IDs via env vars):
| Tier | Env key prefix | Description |
|---|---|---|
| Essential | ESS_1 … ESS_5 |
Entry-level operator plans |
| Enterprise | ENT_1 … ENT_4 |
High-volume operator plans |
| Add-on | ADDON_1 |
Additional features, refer to Live Tracking service |
9 Authentication and Authorization
JWT authentication
All API Server endpoints (except signup and Stripe webhooks) require a JWT Bearer token:
Authorization: Bearer <token>
Tokens are issued on login and carry userType, byPuid (applicator ID), and userId. The checkUser middleware validates the token and attaches the user to req.user.
API key authentication Public Export API
The /api/v1/ public export endpoints use an X-API-Key header instead of JWT. Keys are bcrypt-hashed and stored in the ApiKey collection. Each key is scoped to a specific applicator (byPuid), so data access is automatically isolated.
Authorization model
ADMIN — full platform access
APP — manages own organization (pilots, vehicles, jobs, customers)
APP_ADM — same as APP within parent organization
CLIENT — read-only access to own job results
PILOT — limited: download job assignments
OFFICER — field oversight
INSPECTOR — read-only job inspection
PARTNER — manages partner organization
PARTNER_SYSTEM_USER — customer credentials for a specific partner
10 Infrastructure and Deployment
Production server topology
graph TD
INT["Internet"] --> NX["Nginx<br/>SSL termination<br/>port 443"]
NX -- "/ → :7000" --> API["agmission-prod<br/>(PM2)"]
NX -- "/track → :4200" --> TRK["track_server<br/>(PM2)"]
API --> MDB["MongoDB<br/>Replica Set<br/>rs0"]
API --> RBT["RabbitMQ"]
API --> RDS["Redis"]
GPS1["gps_server-agnav<br/>TCP :6080 (PM2)"] --> MDB
GPS1 --> RBT
GPS2["gps_server-rap<br/>TCP :6082 (PM2)"] --> MDB
GPS2 --> RBT
RBT --> JW["job_worker<br/>(PM2)"]
RBT --> PSW["partner_sync_worker<br/>(PM2)"]
PPW["partner_data_polling_worker<br/>(PM2)"] --> MDB
PPW --> RBT
IW["invoice_worker<br/>(PM2)"] --> MDB
CW["cleanup_worker<br/>(PM2)"] --> MDB
PM2 managed processes
| PM2 name | Entry point | Description |
|---|---|---|
agmission-prod |
server.js |
Main API server |
track_server |
track-server.js |
Live tracking |
gps_server-agnav |
gps-server.js |
AgNav TCP receiver |
gps_server-rap |
gps-server.js |
RAP TCP receiver |
job_worker / job-importer |
workers/job_worker.js |
Job file processing |
invoice_worker |
workers/invoice_worker.js |
Invoice automation |
cleanup_worker |
workers/cleanup_worker.js |
Soft-delete cleanup |
partner_sync_worker |
workers/partner_sync_worker.js |
Partner job/log sync |
partner_data_polling_worker |
workers/partner_data_polling_worker.js |
Partner log polling |
Deployment flow
Deployments are performed using trunk/Others/scripts/deploy/agm-deploy.sh. See DEPLOYMENT.md for full instructions.
graph LR
DEV["Local dev machine<br/>(SVN trunk or branch)"] -- "rsync over SSH<br/>agm-deploy.sh" --> PROD["Production server<br/>agmission-1.agnav.com:22222"]
PROD --> PM2["pm2 reload<br/>agmission-prod"]
11 Key Data Flows
Job creation and assignment
graph TD
A["Applicator creates job<br/>in Web UI"] --> B["POST /api/jobs"]
B --> C["Job record created<br/>in MongoDB"]
C --> D["Upload job file<br/>(ZIP / KML / SHP)"]
D --> E["POST /api/upload"]
E --> F["File stored on disk<br/>job-uploads/"]
F --> G["Job message published<br/>to 'jobs' queue"]
G --> H["Job Worker consumes<br/>message"]
H --> I["Unzip and parse files"]
I --> J["Calculate spray statistics"]
J --> K["Create Application +<br/>ApplicationDetail records"]
K --> L["Applicator assigns job<br/>to pilot / device / partner"]
L --> M{"Partner?"}
M -- "No (internal)" --> N["JobAssign created<br/>status=NEW"]
M -- "Yes (SatLoc)" --> O["UPLOAD_PARTNER_JOB<br/>enqueued"]
O --> P["Partner Sync Worker<br/>uploads to SatLoc Cloud"]
P --> Q["JobAssign status=UPLOADED<br/>+ extJobId stored"]
Real-time GPS tracking
graph LR
HW["AgNav Device"] -- "binary TCP" --> GPS["GPS Server"]
GPS --> MDB["MongoDB<br/>locations"]
GPS --> RBT["RabbitMQ gdata"]
RBT --> TRK["Track Server"]
TRK -- "SSE push" --> UI["Browser Map"]
12 Repository Layout
AgMission/
├── trunk/
│ ├── Development/ ← Active source code (see below)
│ ├── Documents/ ← Architecture, requirements, design docs
│ └── Others/
│ ├── configs/ ← PM2 JSON configs for deployment target
│ └── scripts/ ← Operations scripts
│ ├── deploy/ ← Deployment automation (agm-deploy.sh)
│ ├── backup_agm.sh ← MongoDB backup + rsync to NAS
│ └── start_pm2_apps.sh
│
├── branches/ ← Feature branches (SVN layout)
│ ├── subscription-invoicing/
│ ├── subscription-signup/
│ ├── job-invoicing/
│ ├── data-export-api/
│ └── satloc-resume/
│
└── tags/ ← Release snapshots
└── release-3.2.1/
trunk/Development/
├── client/ Angular SPA
├── server/ Express API server + workers
│ ├── controllers/
│ ├── helpers/
│ ├── middlewares/
│ ├── model/
│ ├── routes/
│ ├── services/
│ └── workers/
├── gps-server/ TCP GPS receiver
├── track-server/ SSE live tracking
├── satloc/ SatLoc integration (batch import)
├── maintainer/ Scheduled DB maintenance
├── shared/ Shared DB utilities and models
└── libs/ Bundled third-party libs (shapefile, etc.)
For deployment instructions see DEPLOYMENT.md.
For the server-side REST API reference see server/docs/API_SPECIFICATION.md.
For partner integration details see server/docs/PARTNER_INTEGRATION_ARCHITECTURE.md.