# AgMission SaaS Platform Software Architecture **Version:** 3.2.x **Last updated:** April 2026 **Author:** AgNav Engineering --- ## Table of Contents - [AgMission SaaS Platform Software Architecture](#agmission-saas-platform-software-architecture) - [Table of Contents](#table-of-contents) - [1 Product Overview](#1-product-overview) - [2 System Components](#2-system-components) - [3 High-Level Architecture](#3-high-level-architecture) - [4 Component Details](#4-component-details) - [4-1 Web Client Angular SPA](#4-1-web-client-angular-spa) - [Module structure](#module-structure) - [State management NgRx](#state-management-ngrx) - [Key features](#key-features) - [4-2 API Server](#4-2-api-server) - [Request lifecycle](#request-lifecycle) - [Route groups](#route-groups) - [Key server-side helpers](#key-server-side-helpers) - [4-3 GPS Server](#4-3-gps-server) - [How it works](#how-it-works) - [4-4 Track Server](#4-4-track-server) - [4-5 SatLoc Integration Service](#4-5-satloc-integration-service) - [4-6 Background Workers](#4-6-background-workers) - [Worker overview](#worker-overview) - [Job Worker](#job-worker) - [Invoice Worker](#invoice-worker) - [Partner Sync Worker](#partner-sync-worker) - [Partner Data Polling Worker](#partner-data-polling-worker) - [Cleanup Worker](#cleanup-worker) - [4-7 Maintainer Service](#4-7-maintainer-service) - [5 Data Architecture](#5-data-architecture) - [MongoDB collections](#mongodb-collections) - [User type hierarchy](#user-type-hierarchy) - [6 Message Queue Architecture](#6-message-queue-architecture) - [7 Partner Integration Architecture](#7-partner-integration-architecture) - [Partner credential model](#partner-credential-model) - [8 Billing and Subscription Architecture](#8-billing-and-subscription-architecture) - [9 Authentication and Authorization](#9-authentication-and-authorization) - [JWT authentication](#jwt-authentication) - [API key authentication Public Export API](#api-key-authentication-public-export-api) - [Authorization model](#authorization-model) - [10 Infrastructure and Deployment](#10-infrastructure-and-deployment) - [Production server topology](#production-server-topology) - [PM2 managed processes](#pm2-managed-processes) - [Deployment flow](#deployment-flow) - [11 Key Data Flows](#11-key-data-flows) - [Job creation and assignment](#job-creation-and-assignment) - [Real-time GPS tracking](#real-time-gps-tracking) - [12 Repository Layout](#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: 1. **Mission planning** — create jobs, define treatment areas, assign pilots and jobs to aircraft 2. **Job distribution** — push assigned jobs to guidance console systems, in aircraft, on the field 3. **Real-time tracking** — live GPS monitoring of aircraft during operations 4. **Post-flight processing** — parse binary GPS/spray logs from console systems, compute coverage statistics 5. **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 ```mermaid graph TD subgraph "Field Devices" AGN["AgNav Guidance
System"] RAP["RAP Guidance
System"] SLC["SatLoc Cloud
Partner"] end subgraph "Browser" UI["Angular SPA
(Web Client)"] end subgraph "AgMission Backend (agnav.com server)" NGINX["Nginx
Reverse Proxy"] API["API Server
Node.js / Express"] GPS["GPS Server
TCP :6080 / :6082"] TRK["Track Server
HTTP/SSE"] MNT["Maintainer
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
Replica Set"] RBT["RabbitMQ
Message Broker"] RDS["Redis
Cache"] end subgraph "External Services" STR["Stripe
Billing"] SLC2["SatLoc Cloud API
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 ```mermaid graph TD ROOT["AppModule
(app.module.ts)"] ROOT --> AUTH["AuthModule
Login, signup, password reset"] ROOT --> DASH["DashboardModule
Overview metrics"] ROOT --> JOBS["JobModule
Mission management
Map editing, file upload"] ROOT --> TRACK["TrackModule
Live GPS tracking map"] ROOT --> CUST["CustomerModule
Client / grower management"] ROOT --> BILL["BillingModule
Subscription and invoices"] ROOT --> INV["InvoicesModule
Invoice listing and detail"] ROOT --> PART["PartnersModule
Partner system users"] ROOT --> ADM["AdminModule
Platform admin tools"] ROOT --> SET["SettingsModule
User and account settings"] ROOT --> REP["ReportComponent
PDF report viewer"] ROOT --> SIGN["SignupModule
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 ```mermaid 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 ```mermaid 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. ```mermaid 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: 1. Authenticates with SatLoc Cloud (`satloccloudfc.com`) 2. Retrieves aircraft log metadata 3. Downloads binary log files 4. Parses the proprietary binary format 5. Creates `ApplicationDetail` records 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 ```mermaid graph LR API["API Server"] -- "publish jobs" --> JQ["jobs queue
(RabbitMQ)"] API -- "publish partner_tasks" --> PQ["partner_tasks queue
(RabbitMQ)"] JQ --> JW["Job Worker
job_worker.js"] PQ --> PSW["Partner Sync Worker
partner_sync_worker.js"] PPW["Partner Polling Worker
(cron every 15 min)"] -- "publish partner_tasks" --> PQ PPW -- "REST poll" --> SLCAPI["SatLoc Cloud API"] IW["Invoice Worker
(cron every 1 min)"] --> MDB["MongoDB"] CW["Cleanup Worker
(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`, and `ApplicationDetail` records - 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). ```mermaid 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). ```mermaid graph TD A["Cron trigger"] --> B["Find JobAssigns
status = UPLOADED"] B --> C["Group by partner + customer"] C --> D["Call SatLoc: GetAircraftLogs"] D --> E{"New log
files?"} E -- No --> F["Done"] E -- Yes --> G["Download log file
to local storage"] G --> H["Create PartnerLogTracker
PENDING → DOWNLOADED"] H --> I["Enqueue PROCESS_PARTNER_LOG
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 ```mermaid 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. ```mermaid 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
(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 ```mermaid 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 ```mermaid 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 ``` 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 ```mermaid graph TD INT["Internet"] --> NX["Nginx
SSL termination
port 443"] NX -- "/ → :7000" --> API["agmission-prod
(PM2)"] NX -- "/track → :4200" --> TRK["track_server
(PM2)"] API --> MDB["MongoDB
Replica Set
rs0"] API --> RBT["RabbitMQ"] API --> RDS["Redis"] GPS1["gps_server-agnav
TCP :6080 (PM2)"] --> MDB GPS1 --> RBT GPS2["gps_server-rap
TCP :6082 (PM2)"] --> MDB GPS2 --> RBT RBT --> JW["job_worker
(PM2)"] RBT --> PSW["partner_sync_worker
(PM2)"] PPW["partner_data_polling_worker
(PM2)"] --> MDB PPW --> RBT IW["invoice_worker
(PM2)"] --> MDB CW["cleanup_worker
(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](DEPLOYMENT.md) for full instructions. ```mermaid graph LR DEV["Local dev machine
(SVN trunk or branch)"] -- "rsync over SSH
agm-deploy.sh" --> PROD["Production server
agmission-1.agnav.com:22222"] PROD --> PM2["pm2 reload
agmission-prod"] ``` --- ## 11 Key Data Flows ### Job creation and assignment ```mermaid graph TD A["Applicator creates job
in Web UI"] --> B["POST /api/jobs"] B --> C["Job record created
in MongoDB"] C --> D["Upload job file
(ZIP / KML / SHP)"] D --> E["POST /api/upload"] E --> F["File stored on disk
job-uploads/"] F --> G["Job message published
to 'jobs' queue"] G --> H["Job Worker consumes
message"] H --> I["Unzip and parse files"] I --> J["Calculate spray statistics"] J --> K["Create Application +
ApplicationDetail records"] K --> L["Applicator assigns job
to pilot / device / partner"] L --> M{"Partner?"} M -- "No (internal)" --> N["JobAssign created
status=NEW"] M -- "Yes (SatLoc)" --> O["UPLOAD_PARTNER_JOB
enqueued"] O --> P["Partner Sync Worker
uploads to SatLoc Cloud"] P --> Q["JobAssign status=UPLOADED
+ extJobId stored"] ``` ### Real-time GPS tracking ```mermaid graph LR HW["AgNav Device"] -- "binary TCP" --> GPS["GPS Server"] GPS --> MDB["MongoDB
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](DEPLOYMENT.md).* *For the server-side REST API reference see [`server/docs/API_SPECIFICATION.md`](../Development/server/docs/API_SPECIFICATION.md).* *For partner integration details see [`server/docs/PARTNER_INTEGRATION_ARCHITECTURE.md`](../Development/server/docs/PARTNER_INTEGRATION_ARCHITECTURE.md).*