| Entity | Status | Rows | Last Sync | Action |
|---|---|---|---|---|
| Loading… | ||||
| Job | Status | Last Run | Duration | Failures | Next Run | Action |
|---|---|---|---|---|---|---|
| Loading… | ||||||
| Entity | Status | Rows | Last Sync | Action |
|---|---|---|---|---|
| Loading… | ||||
| Job | Status | Last Run | Duration | Failures | Next Run | Action |
|---|---|---|---|---|---|---|
| Loading… | ||||||
| Watcher | Status | Last run | Dur | Fails | Next |
|---|---|---|---|---|---|
| Loading… | |||||
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.
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.
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.
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).
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.
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.
The authoritative NetSuite ↔ AG365 ↔ Monday field map with live implementation status (built / partial / gap) — the standard the build follows.
| ID | Company | Stage | Phone | AG365 Link | Actions | |
|---|---|---|---|---|---|---|
| Loading… | ||||||
| ID | Name | State | Status | Actions | |
|---|---|---|---|---|---|
| Loading… | |||||
| Grower | Field | Season | Status | Bnd | Map | Script | P-Map | Updated |
|---|---|---|---|---|---|---|---|---|
| Loading… | ||||||||
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.
| Name | Contact | City | State | Zip | County | Phone | Rep | Stage | Status | USDA $ | Updated | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Loading… | ||||||||||||
| NetSuite Customer | NS Email | AG365 Account | AG365 Email | |
|---|---|---|---|---|
| Loading… | ||||
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.
| Title | Kind | Grouped by | Fields | Acres | Created by | |
|---|---|---|---|---|---|---|
| Loading… | ||||||
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.
—Authorization: Bearer <key>X-API-Key: <key>| Name | Prefix | Capabilities | Created | Last used | Status | |
|---|---|---|---|---|---|---|
| Loading… | ||||||
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.
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.
—Authorization: Bearer <key>| Name | Prefix | Last used | Status | |
|---|---|---|---|---|
| Loading… | ||||
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.
Exactly what Badger receives for one record: the same answer as GET /badger/v1/<object>/<id>, with today's field switches.
| When | Key | Request | Rows | Status |
|---|---|---|---|---|
| Loading… | ||||
| Order # | Field | Grower | Billing entity | Split | Product / charge | Code | Acres (share) | Qty / amount (share) |
|---|---|---|---|---|---|---|---|---|
| Loading… | ||||||||
| Order # | Grower | Farm | Field | Product | Acres | Completed | NetSuite |
|---|---|---|---|---|---|---|---|
| Loading… | |||||||
| Entity | Status | Rows | Last Sync | Schedule | Action |
|---|---|---|---|---|---|
| Loading… | |||||
| Operation | What it writes | Connects to | Belongs to | Submitted | Status | |
|---|---|---|---|---|---|---|
| Loading… | ||||||
| Operation | Baseline Rx | What it writes | Connects to | Belongs to | Submitted | Status | |
|---|---|---|---|---|---|---|---|
| Loading… | |||||||
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.
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.
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.
| When | Destination | Status | Size | Duration | In Bucket | Object / Error |
|---|---|---|---|---|---|---|
| Loading… | ||||||
| Name | Tier | Role | Active | Actions | |
|---|---|---|---|---|---|
| Loading… | |||||
| Tier | Description | Capabilities | Actions |
|---|---|---|---|
| Loading… | |||
What everyone sees in the header. Users don't rename it.
Applies instantly. Users can still pick their own.
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.
The assistant's tone and any standing instructions. Applies to every conversation.
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.
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.
Until an endpoint is set, the assistant says voice isn't configured rather than falling back to the browser's own speech.