Overview

NS Customers
…
NS Invoices
…
NS Items
…
NS Vendors
…
NS Farm Fields
…
NS Soil Tests
…
NS Sales Orders
…
AG365 Accounts
…
AG365 Fields
…
AG365 Zones
…
Entity Links
…
Pending Writes
…
Scheduler
…
Sync Health
EntityStatusRowsLast SyncAction
Loading…
Scheduler Heartbeat
JobStatusLast RunDurationFailuresNext RunAction
Loading…

Data Flow

Live Operations — watchers, sync & activity —
Scheduler
—
—
Mirror rows
—
across all entities
Pending writes
—
awaiting approval
Watcher errors
—
late / failing jobs
Watchers
WatcherStatusLast runDurFailsNext
Loading…
Live activity audit feed
Loading…
1 · Ingest — upstream systems → mirror DB

27 registered watchers pull every upstream on its own cadence and write into the mirror. Nothing downstream ever calls an upstream directly — so a vendor outage costs us freshness, never availability. Cadences shown are the registered job intervals; live run state, failures and next-run are in the Watchers table above.

🏢 NetSuiteRESTlet + SuiteQL
12 jobs · every 5 min
30 s staggered start
👤
Customers
—
🧾
Sales Orders
—
🌾
Farm Fields
—
🧪
Soil Tests
—
📦
Items
—
➕
7 more entities
vendors · invoices · POs · payments
txn lines · inventory · sales reps
🌱 AG365public API v1 · 76 endpoints
6 jobs · 30 min (accounts 6 h)
filter[updated_at] cursor
🏡
Accounts
—
6 h
🗺️
Fields
—
30 min
🧫
Samples
—
30 min
📋
Baseline Rx
—
30 min
🎯
Zones
—
30 min
📬 AG365 webhookspush, not poll
HMAC-SHA256 over {t}.{body}
300 s tolerance · idempotent
🌱
AG365
event fires
→
POST /webhooks/ag365
🔐
Signature gate
every v1 checked
timestamp before HMAC
→
event_id dedupe
🗃️
webhook_events
at-least-once safe
receiver live · subscription pending
📊 Monday.comGraphQL API
2 jobs · every 5 min
transient faults retried
🗂️
Board cache
refresh stale boards
per-board resilient
→
diff
👁️
Change watcher
detect board edits
→
column labels
🏷️
Label snapshot
status text, not ids
🛰️ Raven / AgSynccompleted orders
every 15 min
🛰️
Completed Orders
disposition rules apply
→
mirror
🔌
AgSync API
OAuth · share level
dormant until AgSync is connected
2 · Resolve — identity, links & derived tables

Mirrored rows are only useful once the same grower in three systems is known to be the same grower. Auto-link takes the certain matches; anything short of certain becomes a suggestion a human accepts or rejects. Derived tables are rebuilt from the raw payloads, never hand-maintained.

🔗 IdentityNS ↔ AG365 ↔ Monday
🗄️
Mirror DB
—
rows across 18 tables
→
autoLink · exact
🔗
Entity Links
—
linked pairs
→
fuzzy · hourly
💡
Suggestions
—
awaiting a human
🧬 Derivedrebuilt from raw JSON
📐
ag365_field_geo
geometry · bbox · acres
one row per field
🧾
qualifying_items
the SO-line → service bridge
(ns_items does not join)
🏷️
ns_list_labels
internal ids → text
hourly
🔒
record_locks
edit conflicts
expired swept hourly
3 · Store — Postgres + Cloudflare R2

Structured data lives in Postgres; anything large, binary or long-lived lives in R2 behind our own endpoints, so a consumer never depends on a vendor URL and we can move storage without breaking an integration.

🐘
Postgres
—
mirror · links · audit · queue
→
nightly, encrypted
💾
DB Backups
R2 · verified restore
↘
after backup
📚
Audit Archive
R2 · cold audit rows
hourly poll, backup-gated
→
hourly drain
🖼️
Field Images
—
stored in R2

Field imagery is pulled from AG365 once and served from /dashboard/ag365/field-images/:fieldId/image — re-fetched only when AG365 re-renders the field (its media id changes).

4 · Write — every change meets the approval gate

Two things produce writes: an API caller, and the change router noticing a new record upstream. Both land in the same queue. Nothing reaches an upstream system without either a human click or an explicit per-system Auto switch — and money-spending operations always meet a human, whatever the switch says.

📱
API caller
POST /v1/…
🔀
Change Router
every 5 min
4 flows, watermarked
→
queueWrite
📝
Pending Queue
—
awaiting approval
→
approve · or Auto
🏢
Upstreams
NetSuite · AG365 · Monday
🔀 Change-router flowsnew + unlinked only
first run sets a watermark and
proposes nothing
🌱
AG365 account
→ propose NS customer
carries the id round-trip
👤
NS customer
→ propose AG365 customer
gated on a qualifying service
🧾
Financed SO
→ propose Monday Finance item
🌾
NS farm field
→ propose Monday Agronomy item
5 · Serve — who reads the router

One router, many faces. Every consumer goes through the same capability-checked endpoints, and every action any of them takes lands in the audit feed above.

🖥️
This dashboard
operators · capability-gated
🤖
Assistant
answers over mirrored data
own log + audit trace
🔌
Router API
/v1/… for external callers
🗺️
Field mapping
imagery + geometry endpoints
for a grower-facing module
designed
📋
Audit
router + assistant, merged
Canonical Field Flow — spec (CSV + diagram) ↗ Open full

The authoritative NetSuite ↔ AG365 ↔ Monday field map with live implementation status (built / partial / gap) — the standard the build follows.

NetSuite Customers

🔍
Customers
IDCompanyStageEmailPhoneAG365 LinkActions
Loading…

AG365 Accounts

🔍
AG365 Accounts
IDNameEmailStateStatusActions
Loading…

Baseline Rx

Total
…
Pending
…
Completed
…
No Script Yet
…
🔍
Baseline Prescriptions
GrowerFieldSeasonStatus Bnd Map Script P-Map Updated
Loading…

Field Images

Have Image
…
Stored in R2
…
Outstanding
…
Errors
…

Each image is AG365's rendering of that field's boundary, drawn from the field's GeoJSON. Fields with no boundary on file get AG365's shared placeholder, which we never store — so "No boundary in AG365" below means there is genuinely nothing to fetch, not that we missed it. Images we hold are served from our own R2, so they keep working if AG365 does not.

🔍
Fields
Loading…

Prospects

🔍
Prospects
NameContactCity StateZipCounty PhoneRepStageStatus USDA $Updated
Loading…

Field Mapping

Module switchesOn / Off — a DB override, or the env default
Loading…
Fields on file
—
in the mirror
With a boundary
—
—
No boundary yet
—
ground someone must draw
On live accounts
—
—
Demo maps
—
never reach AG365
Maps group ground however you work

A working map groups real fields — by salesman, by owner, by region, by whatever you actually work in. It holds pointers, so a boundary re-drawn in AG365 is right on every map that includes it. A demo map holds ground you drew for a prospect; it lives in its own tables that no sync job or write path can see, so it can never be pushed upstream or counted in an acreage total.

TitleKindGrouped byFieldsAcresCreated by
Loading…
🔍
📍
USGS imagery · proxied & cached
Fields—
Loading…
Loading map…

Overlays

Imagery: USGS National Map (public domain)
Pick a field on the map or in the list.

API & Keys

Calling this router from another system

Every endpoint below is served from our mirror, so a consumer never depends on NetSuite, AG365 or Monday being up. A key carries only the capabilities it was minted with and is never a SuperAdmin — the same permission model the dashboard itself uses.

Base URL—
Auth headerAuthorization: Bearer <key>
AlternateX-API-Key: <key>
Keys shown once at mint — only a hash is stored
NamePrefixCapabilitiesCreatedLast usedStatus
Loading…

Badger Maps

Connection

Badger reads these records from /badger/v1. A record is live while Badger can read it and gone once it is retired (Badger is told, so it can drop its copy). The feed refreshes by itself about every 10 minutes; Refresh now does it straight away.

Loading…
Key

Badger sends one key with every request. It can read the feed and nothing else. To change keys, create a new one, give it to Badger, then revoke the old one.

Base URL—
Auth headerAuthorization: Bearer <key>
NamePrefixLast usedStatus
Loading…
Fields

Badger sees only the fields switched on here, plus id and lastmodifieddate, which are always sent. A switch changes what counts as a change, so Badger re-reads every record of that object the next time the feed refreshes.

Loading…
Preview

Exactly what Badger receives for one record: the same answer as GET /badger/v1/<object>/<id>, with today's field switches.

Activity Badger's last 50 requests
WhenKeyRequestRowsStatus
Loading…

Entity Suggestions

Auto-accept ≥88% —
✨
Loading suggestions…

Raven — Slingshot / AgSync

—
Mirrored orders
—
Linked to NetSuite
—
Unmatched
—
Last pull
—
Completed orders becomeWhat we do with an order once Raven marks it complete
Loading…
Billing shares
Order #FieldGrowerBilling entitySplitProduct / chargeCodeAcres (share)Qty / amount (share)
Loading…
Completed orders
Order #GrowerFarmFieldProductAcresCompletedNetSuite
Loading…

Sync State

EntityStatusRowsLast SyncScheduleAction
Loading…

Pending Writes — Approval Center

● live
Write modeApproval · New only · Auto — per system
Loading…
Pending
—
Done
—
Error
—
Rejected
—
▾🏢 NetSuite system of record0
OperationWhat it writesConnects toBelongs toSubmittedStatus
Loading…
▾🌾 AG365 agronomy0
OperationBaseline RxWhat it writesConnects toBelongs toSubmittedStatus
Loading…

Active Locks

Records currently open in edit mode. A lock is held while someone has the edit form open. It auto-expires after 4 hours (or up to 24h if extended). Admins can force-release any lock.

🔒
Loading…

Router Audit

Everything the router did · sync is one segment away

Assistant Logging

Assistant v2 · Audit
⚙

Audit Settings

Assistant Logging · Audit Log
Look-ups

Right-click an address → Look up asks ipinfo.io who owns it. The token is stored sealed and only the address is ever sent. Answers are cached for 7 days.

Backups

Nightly pg_dump of the mirror database to off-site object storage. The mirror is the business-continuity copy — these dumps are what survive if this host is lost.

Recent Runs
WhenDestinationStatusSizeDurationIn BucketObject / Error
Loading…

Users & Tiers

Dashboard Users
EmailNameTierRoleActiveActions
Loading…
Permission Tiers
TierDescriptionCapabilitiesActions
Loading…

Assistant Settings

Assistant v2 · Providers & Models
General
Skills
Models & Keys
Prompts
Email
Voice
Assistant
Name

What everyone sees in the header. Users don't rename it.

Default theme

Applies instantly. Users can still pick their own.

Providers & Models

Keys are encrypted on the server and used only to reach the provider — they are never shown here or stored in the clear. Pick a provider, then assign which model crunches your business data and which powers general chat.

Personality & prompts

The assistant's tone and any standing instructions. Applies to every conversation.

Email (SMTP)

Only used to email a conversation from the assistant. Leave blank and that option simply reports it isn't set up — nothing else depends on it.

Voice

Reading answers aloud and taking dictation. Both go through a service you point at below — nothing is hard-coded, so swapping it later is an edit here, not a deploy.

Borrows the key from Models & Keys. Nothing to paste again.

Until an endpoint is set, the assistant says voice isn't configured rather than falling back to the browser's own speech.

Reports

Help Center

The manual for the whole system