Bypasses bid workflow
Click any step to open detail panel →
Data Flow — what runs today
Which system holds which record, and what moves between them, for a bid that is being worked right now. Everything drawn here is built and deployed. Steps done by hand are marked as such rather than left out — they are the honest picture, and they are where the planned work goes. Nothing planned or agreed-but-unbuilt appears on this page; that lives in Gap Analysis.
The two routes differ because commercial work goes through the Salesforce sales cycle and E-Rate does not.
NetSuite customer — created from the CS Order form
Since Sep 28 2026 the CS Order form’s New Client Setup creates or links the NetSuite customer and writes the NS ID back to Accounts #1. The Sep 29 check that found no NetSuite code had read the Sep 24 copy of vtg-cs-form; the Sep 28 build calls /api/ns-customer, which reaches vtg-ns-so-backfill over a service binding.
Salesforce stage map — settled
Read from the live code (version dc33a840): Bid Building → Stage 3, Awaiting Results → Stage 6, plus Post-Sale, Post-Monday and Lost. Folder Creation, Deal Reg, Bid Compilation, Bid Submittal and the other stages send no stage — that is the open stage-map gap.
The UID is reference only now
Salesforce issues the UID and it is stamped on the monday account, but as of Sep 28 2026 it is no longer the match key — the NetSuite Customer Internal ID is. The UID had not held stable, Salesforce had been duplicating accounts, and it never matched NetSuite’s own custentity_acs_unique_entity_identifier anyway. New NS customers created from the CS form carry externalId mon-<monday item id> instead. One dependency is left: vtg-ns-so-backfill’s auto-sync still links project to account by UID. See the UID gap.
Where the hand-keyed steps go
Two by-hand steps are left — sales order and invoice. They are the target of the planned monday → NetSuite order push and the Ready-for-Invoicing invoice flow, both coded in vtg-ns-mcp-sync, whose cron currently fails on every run; the invoice flow also waits on the NetSuite service item ID from finance. Gap Analysis carries the detail.
backfill.mjs, run by hand. No monday automation triggers it (checked Oct 1 2026). When it does run, vtg-sf-account-sync upserts both the Account and Contact objects into Salesforce using Monday_Item_ID__c as the external ID — creating new SF records or updating existing ones idempotently. After the SF upsert, the Worker writes the Salesforce Account ID back to the UID column (text_mm6s8adk) on the monday.com Accounts board, completing the cross-system link. A backfill script (backfill.mjs) ran against all 791 existing accounts to populate Salesforce and stamp the UID column. Complements vtg-monday-sf-sync which syncs Bids — this Worker handles the CRM Account/Contact layer.numeric_mm5w3j).POST /lead-created compares the lead name (the bare 470 number) against Bids #3 470__. One 470 never covers two separately-bid RFPs — so a 470 already on a live bid means this lead is an addendum, not a new opportunity, and working it produces a duplicate bid. On a match the Worker attaches the addendum document to the bid’s Addenda column, increments Addendum #, stamps Last Addendum Date and sets Addendum Status to Received - Unreviewed, then posts a courtesy update on the lead so nobody clicks accept_470 on it. The bid’s stage never moves — it stays where it is and gets flagged. If a district cancels a 470 it issues a whole new one, which is a genuine new opportunity (old bid → Lost); and by law no addendum can arrive after the submittal date, so there is no post-submittal path. Currently running with ADDENDUM_DRY_RUN = true: matches are logged, nothing is written.POST /lead-files-changed checks whether the lead’s 470 belongs to exactly one live bid; if so, only the new files are copied to the bid’s Addenda column, the bid is flagged, the bid owner and the lead’s Sales Executive are notified, and the lead goes back to Accepted Leads — no second intake form. vtg-sp-folders then copies the addendum into the bid’s SharePoint folder. Leads with no live bid are left alone. Dylan’s two “Accepted Leads → New Leads” addendum automations were deactivated Oct 1.link_mm591mdg, and creates a bond subitem + email if bond is required. The accept also sends a trigger to El Nova, which creates the Accepted Monitor board item.link_mm6vbks) to the bid item.cust_ERATE{FY}RFPs: named after the bid without the colon, the Base Bid Docs folders copied in with their files, and the Lead’s 470, RFP and Customer Summary in the folder root. It writes the SharePoint Link column and sets both Folder Creation subitems to Complete. If anything fails, the subitem goes to Stuck with an update explaining why. Bids that already have a SharePoint Link are skipped.Base Bid Docs/3 -SOV). SOV payload includes vendorPOs array pre-grouped by vendor for future NS PO creation.date_mm39fh8x) equal to the end of the project Timeline. When the stage reaches Ready for Invoicing or Closed, it stamps that day’s date and ticks Revenue Month Locked (boolean_mm7a4044), so later timeline edits no longer move it. A daily cron re-syncs unlocked projects that have drifted.numeric_mm7d9sf4), Remaining to Bill (numeric_mm7db7yk = Total Project Amount − invoiced), Last Invoice Date and Billing Match. Invoiced only — no AR, no credit memos. Projects that SO Check flags as Duplicate project, Mismatch or Cannot verify are skipped until they are cleaned up.transaction). vtg-ns-compare was deleted Oct 1 2026; customer mapping is now the NS Customer Internal ID on Accounts #1, which this Worker does not read yet.VTG_Salesforce_SOP.html, v2.1 — Sep 9 2026).⚠ Revised Sep 24 2026 — Salesforce is a reporting layer, not a link in this chain. It exists to give the sales team a view of pipeline; it is not part of the order-to-invoice flow, and no step below should depend on it. Salesforce integration work is stopped until Salesforce settles its final product. The replacement direction: the monday client form creates the new customer directly in NetSuite, taking Salesforce out of the middle. The existing sync Workers keep running — they are how the UID gets written back — but nothing new is being built on them.
Account creation order, agreed Sep 28 2026: the account is created in monday first, then the customer is created in NetSuite, then Salesforce, and the Salesforce UID comes back to both monday and NetSuite. The NetSuite customer is created at won/order, not at lead — no NS record for something that may never become an order. Salesforce still receives the data, but last and for reporting; that is also what satisfies Bill’s new-client checklist automation. This reconciles the two positions above: Salesforce is not in the critical path, but it is not cut off either. Worth knowing why it matters — sales reps do not want to create accounts in Salesforce and only do it when forced to, which is non-E-Rate jobs; an automated flow is what keeps SF populated at all.
date3 Task Due Date, which nothing used to fill — monday formula columns cannot fire automations. The Worker now writes date3 on every new subitem, counting business days back from Bid Due Date and skipping weekends and federal holidays. Applies to bids created after Sep 24 2026 21:07 UTC; older bids were deliberately left alone. Verified on Kent ISD and Lincoln Township.CloseDate came from deal_creation_date, so every Opportunity was created already closed in the past. New column date_mm7dfkx Actual Close Date on Bids #3; the Worker stamps it with today’s date when the bid reaches Post-Sale, and that value then wins. Precedence: Actual Close Date → Bid Due + 65 days → Creation + 65 (logged as a warning) → the old 2027-06-30 fallback. One-way monday → Salesforce, never read back.The obvious fix would have broken it. Switching to the existing
date_mm2c6t1k Expected Award Date column was the first suggestion — measurement killed it: 0 of 500 bids have that column set, so the sync would have sent a null to a required Salesforce field. 498 of 500 have Bid Due Date, which is why the fallback chain is built on it. Amount still comes straight from Bid Value and is unchanged — a placeholder bid value still becomes a real forecast number.dc33a840. monday’s "send a webhook" automation sends no signature at all, so signature checking was the wrong mechanism. The Worker now requires a shared key in the webhook URL (?key=), checked before anything else — requests without it get 401. It also rejects non-numeric item IDs and any item that is not on Bids #3. Both Bids #3 automations were switched to the keyed connection.The original check had two independent reasons it could never pass: the header never arrives, and the code read
WEBHOOK_SECRET while the deployed secret was named MONDAY_WEBHOOK_SECRET. Either alone was fatal. Verified with a 401 on an unkeyed request and a live sync of Clinton Macomb Public Library.e6d28b50. /sync/:itemId and /backfill had no authentication at all, and /webhook checked an Authorization header that monday never sends — the same class of mistake as vtg-monday-sf-sync, found while fixing it. Every route except /health now requires ?key=. /webhook accepts numeric IDs only, and a sync by ID runs only for Accounts #1 items. backfill.mjs reads the key from ACCOUNT_SYNC_KEY. The misnamed secret binding and the old WEBHOOK_SECRET were both deleted. Verified with a 401 on an unkeyed request.backfill.mjs, run by hand. No monday automation was found that triggers the Worker: the Accounts #1 board’s only two webhooks were created Jul 28 and both feed the logo Worker, and vtg-sf-account-sync recorded zero invocations in the last seven days (checked Oct 1 2026). So an account created or edited today sits in monday until someone remembers to run the backfill. Low priority only because Salesforce integration work is paused — it is not a small gap if that changes.StageName: "Stage 3: Bid Building", but Folder Creation, Deal Reg and Bid Compilation send no stage at all — they log active: false and the field is omitted. So the Opportunity keeps reporting the last mapped stage while monday has moved on. If sales reads stage off Salesforce, they are looking at a bid one or more steps behind reality. Separately, skip: true only suppresses StageName; the Opportunity is still written on every column change.The write volume has a cause, found Sep 30 2026. The "any column changes" webhook fires on
subitems too, so every subitem creation is another Salesforce write: one Post-Sale transition produces 8, and creating a bid with its 22 subitems produces roughly 22. That — not users editing columns — is what the 414-run count was. The fix is a one-line early return on event.columnId === "subitems". (An earlier single-column test came back 1:1 and the conclusion drawn from it, that there was no amplification, was wrong.)color_mm7f9qc2) — Working on it, then Done, or Stuck with the reason posted as an update — and the doubled district name in the SOW filename is stripped. Generate Proposal already worked this way. Still open: neither generator closes its own Create SOW / Create SOV subitem, so both are ticked by hand.link_mm6vbks (…/?item=<itemId>) when it creates the bid. Every bid created Sep 30 – Oct 1 2026 carries it.text_mm7m8z67), which vtg-ns-mcp-sync does not read yet.transaction (the same limit was recorded again Sep 30). That is roughly 96 failures a day, and none of the six coded flows reaches a monday write. The source has not changed since Sep 17. An older build, vtg-ns-mcp-sync-staging, still runs its own 15-minute cron (Sep 19 2026 snapshot).N/A, n.a., N / A, TBD, pending, XXXX and 0000 are all refused. A PO of "N/A" is worse than an empty one — it looks like a value and verifies nothing. The PO is the human-readable key finance reconciles the NetSuite order against, alongside UID matching.UID__c auto-number) was adopted as the cross-system key. Salesforce duplicates contacts — 69 SF duplicate accounts sent to Merlin for review — the UID has not been stable, and SF requirements keep changing. Two problems: legacy Accounts, Bids and Projects rows carry a blank or stale UID (17 Projects #4 rows "Cannot verify" as of Sep 28; fuzzy-name fallback is off), and a newly issued UID can’t be trusted either. The UID also does not match NetSuite’s custentity_acs_unique_entity_identifier — different numbering.Current state: the NS Customer Internal ID is the matching key. New NS customers created from the CS form use
externalId mon-<monday item id>, live since Sep 28. Remaining dependency: vtg-ns-so-backfill’s auto-sync still links project → account via UID.UID__c values (the Worker writes UID__c, not the Account ID) were written back and that no items were skipped due to MONDAY_TOKEN auth issues (backfill.mjs requires MONDAY_TOKEN env var set explicitly before running).ctx.waitUntil, so Cloudflare may cancel it once the form response has been returned. The call still runs on every CS Order submit.vendorPOs grouped by vendor.text_mm7m8z67), filled by vtg-ns-so-backfill.vtg_sov_import_v4.py, and there are three copies of that file in a OneDrive-synced folder — so they are replicated to every machine the folder syncs to and to OneDrive’s version history. Rotate all four, move them to environment variables or wrangler secret, and delete the stale copies rather than editing them.ADDENDUM_DRY_RUN is "false", so matches are written. Notifications are built on the Oct 1 path: when a lead that already has a live bid gets a new RFP Documents or Form 470 file, the bid owner and the lead's Sales Executive are notified. Still to see: the first real addendum end to end.API-Version: 2024-01. Current is 2026-07. Deprecated versions are retired on monday’s schedule, not VTG’s — when it goes, every intake PDF, bond form and addendum attachment fails at once, in season. Bump and re-test the upload path.npx wrangler delete --name vtg-logo-probe.<img src>-only scraper that found 6 logos in two months; vtg-account-logo moved to the new extractor on Sep 20. It runs on a 2-minute cron. The backfill of the 331 addressable accounts with the new extractor is still open (Sep 2026 sweep), as is the KV progress being written only after a whole batch.PO-XXXX, normalises to poxxxx, which is not in the reject list — so a rep who types the placeholder they are being shown sails through the check that exists to stop exactly that. One word in the reject list closes it./lead-files-changed, Leads webhooks 645545831 / 645545840): only the new files go to the bid's Addenda, the bid is flagged, the owner and Sales Executive are notified, and the lead goes back to Accepted Leads. Dylan's two "Accepted Leads → New Leads" addendum automations (493350968, 493351900) were deactivated Oct 1. To confirm on the first real addendum.file_mm6wm4hn). The vtg-cs-form half is done — all 6 PM task subitems (Project Kickoff Meeting, Site Access Coordination, Installation Scheduling, Weekly Status Updates, Project Documentation, Project Closeout) are live in the Worker, verified Sep 17 2026.mon-<account id>, so a retry cannot duplicate — and writes the NS ID to Accounts #1 text_mm7m8z67. A similar-name hit goes to Review instead of creating. A requested credit limit of $1M or more flags the account and does not block. Salesforce is not in this path.numeric_mm7d9sf4), Remaining to Bill (numeric_mm7db7yk), Last Invoice Date and Billing Match, filled by vtg-ns-so-backfill's billing sync every 4 hours. Invoices are found by Customer PO, else by the project's SO; Remaining = Total Project Amount − invoiced. Invoiced only — no AR, no credit-memo netting. 89 projects carry values as of Oct 1 2026; projects that SO Check flags as Duplicate project, Mismatch or Cannot verify are not filled until they are cleaned up.file_mm79y1x5, pulled from SharePoint Customers\<customer>\Accounting Documents. vtg-cs-form attaches the account's certificate to the CS Order automatically.file_mm7get0y) is copied to the bid folder root, next to the RFP and the 470, via webhook 645561102 → /addenda on vtg-sp-folders. Files added to Addenda by hand are copied the same way, and re-runs leave existing files alone. The route takes no key by design: it accepts only a Bids #3 item ID and can only re-copy files already on that bid into its own folder./api/lookup live. That half shipped Sep 3 2026. The consuming half never did: vtg-sov-builder declares the [[services]] TDSYNNEX binding and never calls it. Verified Sep 17 against worker-combined.js — zero references to tdsynnex, TDSYNNEX or /api/price, and no LIVE badge exists. Step 6 of the vtg-tdsynnex deploy guide ("Update vtg-sov-builder") is the outstanding work; prefer env.TDSYNNEX.fetch() over the public URL that guide suggests.file_mm5bhcw7, writes the Intake Form link to link_mm591mdg and the SOV Builder link to link_mm6vbks, and creates a bond subitem + email if required. Patched Sep 19–20 2026: the Account/Contact lookup declared its GraphQL variable as [ItemsQuery!] where monday expects [ItemsQueryRule!] — every lookup failed validation, an empty catch swallowed it, and bids were created with both relations blank. Contact selection was then rewritten to draw candidates from the Account's own Contacts relation, drop billed_entity placeholders, collapse duplicate emails keeping the most recently updated, and score the rest. The E-Rate Primary Contact dropdown now reads its options live from the Bids #3 column instead of a hardcoded list.cust_ERATE{FY}RFPs, with FY from the first two digits of the 470# (2026 maps to cust_ERATE2026RFP). Folder name is the bid name with the colon removed, e.g. Noblesville Schools - 470# 270000673. The folders of 1- STANDARD BID FORMS AND DOCS/Base Bid Docs (1-Cover Page … 9-Product Support Info) are copied with their files into a Base Bid Docs subfolder; the Lead's Form 470, RFP Documents and Customer Summary go in the bid folder root. Fills the SharePoint Link column and sets both Folder Creation subitems to Complete. Bids that already have a SharePoint Link are left alone, and a re-run reuses the folder and leaves existing files alone. Since Oct 1 2026 it also copies the Addenda column and every SOV version into the folder.date3) by counting business days back from the bid's Bid Due Date, skipping weekends and US federal holidays only; the offset is the subitem's Days to Subtract (numbers0). date3 is the column the due-today notification, the three row highlights and the auto-assign automations watch, so those now fire. Re-dates a subitem when its offset changes, and every subitem on a bid when the Bid Due Date changes. Runs on subitems after creation, so Dylan's subitem-creation automation is unchanged.?item={monday_item_id}. Supports multi-tab buildings, ADD-ALTS tab, Summary tab, section type picker (Wired/Wireless/Firewall/UPS/Cable/MIBS/BMIC/Fiber/Other), SKU dropdown, per-row labor, markup overrides, and bond toggle. Save & Submit generates the SOV as a PDF and an Excel workbook, versioned _V<n>, and uploads both to the Bids #3 SOV PDF column (file_mm749nna), keeping the newest two versions there; vtg-sp-folders copies every version to the bid's SharePoint folder. Saved payload includes a vendorPOs array pre-grouped by vendor — ready for future NetSuite PO creation.document_status_changed webhook when a SOW finishes generating, downloads the .docx, and routes by template name — routes the "Vector eRate SOW" template (ID 7085) to the Bids #3 SOW Document column (file_mm6wm4hn); anything else goes to El Nova Leads Customer Summary (file_mkw7hy4z). Endpoint 2 (POST /generate): triggered by a "Generate SOW" button click on a Bids #3 item — reads the 470# from the item, finds the matching ScopeStack project, and triggers programmatic SOW generation; the webhook then auto-delivers the doc. 470# extracted from filename or via project API lookup when filename is null. ⚠ Pending: template routing update to V3; vtg-cs-form needs 6 PM task subitems added (Project Kickoff, Site Access, Install Scheduling, Weekly Status, Documentation, Closeout).file_mm739vxe). Updates a Proposal Status column (orange → green/red) so reps can see progress without re-clicking.Trigger: button_mm732fyx → automation 636065801 → POST /generate
Logo box: 192×144pt, centered between district name and "Statement of Work" on cover
Status column: color_mm74qsfe ("Working on it" / "Done" / "Stuck")
Vector logo: hardcoded base64 JPEG in Worker — no network dependency
SOV PDF: uploads to file_mm749nna via SOV Builder submit | Phase 3: SharePoint standard docs + data sheets
?key=, checked before anything else; unkeyed requests get 401. Non-numeric item IDs and items that are not on Bids #3 are rejected. Version dc33a840, Oct 1 2026. Syncs Bids #3 items to Salesforce as an Opportunity upsert, using Monday_Item_ID__c as the external ID for idempotent creates/updates. SF token cached in KV.Fired by two Bids #3 automations — "when an item is created, send a webhook" and "when any column changes, send a webhook". It is not limited to deal_stage, deal_value or deal_creation_date; any column change on the item reaches it, which is why subitem activity amplifies the write count.
Stage map, read from the live code (version dc33a840): only Bid Building → "Stage 3: Bid Building", Awaiting Results → "Stage 6: Awaiting Results", plus Post-Sale, Post-Monday and Lost. Folder Creation, Deal Reg, Bid Compilation, Bid Submittal, Bidding and Wins Archive send no stage at all — see the stage-map gap.
text_mm7m8z67); project → account still goes through the UID (see the UID gap) and the fuzzy-name fallback is off. A 4-hour cron runs SO auto-sync (one SO per project, Customer PO cross-check), SO Check, and the billing sync that fills Invoiced to Date, Remaining to Bill and Last Invoice Date. Also creates or links new NetSuite customers for vtg-cs-form's New Client Setup (live Sep 28 2026).text_mm76antg) and PO Status (color_mm766mdj) on the Projects #4 item. (Customer PO, text_mm7dxvwd, is a separate column written by vtg-cs-form.)date_mm39fh8x) on Projects #4 equal to the end date of the project Timeline (timerange_mm1q29se). When the Project Stage reaches Ready for Invoicing or Closed, it stamps Revenue Month with that day's date and ticks Revenue Month Locked (boolean_mm7a4044), so later timeline edits no longer move it. A daily cron re-syncs any unlocked project whose Revenue Month has drifted from its timeline.numeric_mm5w3j). Runs when a file lands in Customer Summary (file_mkw7hy4z). This is the score extraction described at SOP step 1.1.logo file column, setting logo_status to Logo Found / Needs Manual Logo / No Website. Fires on Account creation and when website_url changes, so an account that arrives without a website gets a second attempt once El Nova fills it in. Rewritten Sep 20 2026 — the original only read <img src>, which Finalsite and ParentSquare sites never emit (the URLs sit in data-image-sizes as percent-encoded JSON), and its Clearbit fallback had been dead since 8 Dec 2025. In two months it had found 6 logos. The replacement reads lazy-load attributes, scores candidates, prefers a wordmark over an icon mark, and only writes at 70+ — anything less confident is flagged Needs Manual Logo rather than guessed at.color_mm5phbaj). Progress — cursor, processed IDs, stats and a done flag — is kept in KV so each run resumes where the last one stopped. The deployed copy (Jul 28 2026) still uses the original <img src>-only scraper that vtg-account-logo replaced on Sep 20.UID__c auto-number (not the Account ID) back to the UID column (text_mm6s8adk) on the Accounts board. A backfill script (backfill.mjs) ran against all 791 existing accounts to populate Salesforce and stamp the UID column. Complements vtg-monday-sf-sync which syncs Bids — this Worker handles the CRM Account/Contact layer./api/inventory/all and displays all NS locations: 41 Cabling Warehouse (blue), 42 Secondary Warehouse (green), 4 Grand Rapids Office (yellow). Password protected (VTG2026 — Azure AD SSO planned). Features: search, location filter pills, sortable columns, light/dark mode toggle, CSV export.config/tools.json is source of truth for tool entries. Docs backed by GitHub markdown files.sso.us.tdsynnex.com, caches the token in KV with auto-refresh, and exposes a /api/lookup?pn=PARTNUMBER endpoint. Handles both numeric part numbers (synnexSKU) and alphanumeric (mfgPN). Falls back to SKU_CATALOG KV for VTG-specific items (labor, Cloudpath). vtg-sov-builder declares a [[services]] TDSYNNEX binding to it, but nothing calls it yet (checked Oct 1 2026 against worker-combined.js) — see the TD Synnex gap. Key bug fixed at build: TD Synnex returns HTTP 200 with status: "Not found" for unknown SKUs (not a 404), requiring an explicit status-string check to trigger the KV fallback.remote ap-cli <MAC> "get lldp neighbors" on each via SSH, parses output to extract switch hostname, port, chassis MAC, and management IP, displays as a formatted console table, exports to a timestamped CSV, and optionally writes LLDP data back to each AP's description field via controller CLI. Built to run locally because remote sites lack public-facing IPs on the controller. Uses prompt-based SSH waiting (_wait_for()) rather than blind sleeps. Added to VTG portal as tool #23.text_so_number, text_invoice, text_po_number …), and its monday route checks x-monday-signature, which monday's "send a webhook" automations do not send./lead-created endpoint (webhook 642139356); an addendum flags the existing bid and never moves its stage.UID__c auto-number (not the Account ID) written back to the monday.com Accounts board UID column (text_mm6s8adk) by the vtg-sf-account-sync Worker after a successful Account upsert. Intended as the permanent cross-system identifier linking a monday.com Account to its Salesforce counterpart; the external ID field Monday_Item_ID__c on the SF Account object is the join key used for idempotent upserts — UID is what comes back. Superseded as a key, Sep 28 2026: the UID is reference only now. Salesforce had been duplicating accounts (69 sent to Merlin for review), the value did not hold stable, and it never matched NetSuite’s custentity_acs_unique_entity_identifier. The NS Customer Internal ID (text_mm7m8z67 on Accounts) is the matching key; new NS customers from the CS form carry externalId mon-<monday item id>. See the UID gap.wrangler deploy from Command Prompt (not PowerShell — blocked by Norton). Source files at OneDrive\VTG Flows\<worker-name>\.https://{accountId}.suitetalk.api.netsuite.com/…/oauth2/v1/token.wrangler deploy), manage KV keys (wrangler kv key put/get/delete), and set secrets (wrangler secret put). Must be run from Command Prompt (not PowerShell — blocked by Norton AV)./admin/skus route — and the vtg-sku-catalog project folder is empty, so the serving source has not been located. Lets Jon manage the product catalog without touching code or running wrangler commands: browse all vendor SKUs, add individual parts, upload JSON catalog files, and see the wrangler CLI commands for bulk pushes. Vendor catalogs loaded: Ruckus switches/APs, N1C UPS (62 SKUs at 2026-27 Platinum pricing), VTG cabling (shared with Materials Log).query (the GraphQL mutation), variables (JSON with {"file": null}), map (JSON with {"0": ["variables.file"]}), and the file itself as field "0". The simpler variables[file] form-append approach silently returns a 200 OK but does not actually persist the file. Endpoint: https://api.monday.com/v2/file (not the standard /v2 endpoint). Used by vtg-scopestack-doc-sync to attach SOW .docx files to board items.text_mm7m8z67). The match key between monday and NetSuite since Sep 28 2026 — written by vtg-ns-so-backfill (auto match or New Client Setup) or by a person resolving a Review. New customers created from monday carry externalId mon-<account id>.color_mm7m1x6z) set by vtg-ns-so-backfill after comparing the project with its NetSuite sales order: Verified, Customer only, Review amount, Duplicate project, Mismatch or Cannot verify. Billing figures are filled only for Verified / Customer only projects or a Customer PO match.numeric_mm7db7yk = Total Project Amount (monday, the source of truth for contract value) − Invoiced to Date (from NetSuite invoices). Invoiced only — no AR, no credit memos. Filled every 4 hours by vtg-ns-so-backfill.boolean_mm7a4044) that vtg-revenue-month ticks when a project reaches Ready for Invoicing or Closed. Once locked, Revenue Month no longer follows Timeline edits.numeric_mm5w3j). The Leads board also has a separate Opp Score column (numeric_mm5wkd7d).date3 by vtg-bid-task-dates for bids created after Sep 24 2026.| ID | Trigger | Action | Notes |
|---|---|---|---|
| 615242921 | When an item is created | Send a webhook | Fires vtg-account-logo Worker on Account creation to scrape + upload district logo |
| 615244207 | When column text_mkxpgyv6 (website URL) changes | Send a webhook | Re-triggers logo fetch when El Nova website URL is updated on an existing Account |
| SF sync webhook | When Account created or updated | Send webhook → vtg-sf-account-sync | ⚠ NOT WIRED — checked Oct 1 2026. This automation could not be found. The Accounts #1 board’s only two webhooks were created Jul 28 and both feed the logo Worker, and vtg-sf-account-sync had zero invocations in the last seven days. Kept on the map because it was recorded as LIVE Sep 8 2026 and the Worker does do this work — upserting Account + Contact via Monday_Item_ID__c and writing the SF Account ID back to text_mm6s8adk — but only when something calls it, which today is backfill.mjs by hand. |
| ID | Trigger | Action | Notes |
|---|---|---|---|
| 7920733007 | When "Accept 470" button clicked | Set Status column (color_mm599ptd) → Pending Intake | First step of the accept chain — Pending Intake fires webhook 632506055 to vtg-bid-intake |
| 608965294Inactive | When Status → Accepted (color_mm599ptd) | Send webhook | Deactivated. Was the vtg-bid-intake trigger; replaced by 632506055 below. vtg-bid-intake now sets Status → Accepted itself on submit. |
| 632506055 | When Status → Pending Intake (color_mm599ptd index 6) | Send webhook → vtg-bid-intake | vtg-bid-intake writes the 📋 Intake Form link (link_mm6vnxwq) onto the lead; the rep opens the form from it |
| 642139356 | El Nova Leads · create_item (webhook) | POST /lead-created on vtg-bid-intake — addendum screen | Live Sep 24 2026 — matches lead name (470#) against Bids #3 470__; on a single live-stage match attaches the addendum, stamps the addendum columns and posts a courtesy update. Never moves the bid stage. Behind ADDENDUM_DRY_RUN |
| 645545831 / 645545840 | RFP Documents (file_mkw3ykdq) / Form 470 (file_mkw3w1z6) changes (webhook) | POST /lead-files-changed on vtg-bid-intake | Live Oct 1 2026 — a new file on a lead whose 470 has one live bid is copied to that bid’s Addenda, the bid is flagged, owner + Sales Executive notified, lead returned to Accepted Leads |
| 615218876 / 615223909 | When "Accept 470" button (button_mkw37e4e) changes | Send webhook (×2) | El Nova integration webhooks registered via API (source: API, app 1573784) — El Nova listens for these to update its own system on accept |
| 617748761 | When file column (file_mkw7hy4z) changes | Send webhook | vtg-lead-score — reads the Opportunity Score out of the Customer Summary PDF and writes Opportunity Score (numeric_mm5w3j) |
| 490861922 | When "Accept 470" button clicked | Move item to group (Accepted group) | Austin's original El Nova automation — physically moves the lead item to the Accepted group on the board |
| 490862005 | When "Reject 470" button clicked | Move item to Rejected group | Routes rejected leads off the active list — rejected leads do NOT go to Accepted Monitor |
| 493350968 / 493351900Inactive | Form 470 / RFP Documents changes + item is in Accepted Leads | Move item to New Leads + notify Sales Executive | Deactivated Oct 1 2026 — sent accepted leads back to New Leads on an addendum, forcing a second intake. vtg-bid-intake /lead-files-changed handles these now. |
| 493355183 / 493355373 | Form 470 / RFP Documents changes + item is in the Rejected group | Move item to New Leads + notify Sales Executive | Still active — a rejected lead that gets an addendum comes back to New Leads: "New addendum for {District} - 470#: {name}" |
| 566810401 / 566810403 | When item created / When item name changes | AI: extract "470 #" from item name → text_mm2f36c column | monday AI automation — parses the 470# out of the lead item name and writes it to a dedicated text column for downstream useAI |
| ScopeStack webhook (Sep 8) | ScopeStack document_status_changed (status=finished, type=sow) | Download .docx → upload to Bids #3 file_mm6wm4hn or El Nova Leads file_mkw7hy4z | vtg-scopestack-doc-sync · LIVE Sep 8 2026 |
| ID | Trigger | Action | Notes |
|---|---|---|---|
| 482374702 | New item created | Set Bid Creation Date (deal_creation_date) to today | Timestamps every new bid automatically |
| 482374703 | New item created | Set Bid Stage → Folder Creation | All new bids start at stage Folder Creation (index 15) |
| 482374765 | New item created | Create 23 subitems (full bid lifecycle task list) | The backbone of the bid task system — creates all tasks from Folder Creation through Awaiting Results in one shot, each pre-tagged by stage and pre-dated from Bid Due Date |
| 483152942 | New item created | Mirror Bid Due Date to subitem "Bid Due Date Mirror" column | Keeps subitem task due date formula in sync from the parent bid due date |
| 483296416 | New item created | Refresh Bid Name Formula column (formula_mkwrhcw) | Forces the formula "District - 470#: XXXXXXXXX" to populate on creation |
| 482374704 | Stage → Deal Reg | Create linked item on Deal Reg board (18176632827) | Auto-creates the Deal Reg record when stage changes; links back via connect_boards1 relation |
| 482374714 | Stage → Deal Reg | Move item to Deal Reg group | Group = physical location of the item in the board view |
| 482374721 | Stage → Bid Building | Move item to Bid Building group | |
| 482374719 | Stage → Bid Compilation | Move item to Bid Compilation group | |
| 482374720 | Stage → Bid Submittal | Move item to Bid Submittal group | |
| 482374739 | Stage → Awaiting Results | Move item to Awaiting Results group | |
| 482374746 | Stage → Post-Sale | Create 6 Post-Sale subitems + move to Post-Sale group | LOI, CW contract (dead task), FCDL/SPI tasks, PO, SOV update |
| 482374740 | Stage → Post-Monday | Move item to Post-Monday group | |
| 559103546 | Item enters Post-Monday group | Create item on E-Rate Deals board (18406412794) | The active Post-Monday handoff — replaces the inactive 482374713 (Projects #4) and 482374738 (CS/PM notification) |
| 482374717 | Stage → Wins Archive | Post completion update + move to Wins Archive group | Message: "This Bid has been completed and billed in full! Congrats! Bid Creation Date: {date} Bid Close Date: {date}" |
| 482374723 | Stage → Lost | Post update + move to Lost group + rename item | Message: "This Bid was lost. Please update all attached Boards, and fill in final amounts and results." |
| 562741747 | Stage → Post-Sale (status index 12) | Send webhook to vtg-cs-form | One of two vtg-cs-form webhook triggers |
| 483153616 | Stage → Post-Sale (secondary trigger) | Send webhook to vtg-cs-form | Redundant webhook for vtg-cs-form reliability |
| 482374706 | Subitem status → ARCHIVE | Archive the subitem | Manual archive — hides completed/irrelevant tasks from the active subitem view |
| 482374707 | Subitem status → You're Up! | Notify assignee | "You're Up! {task} is due {date} for {bid name}. You're not waiting on anyone." |
| 482374711 | Subitem status → N/A | Clear assignee, due date, and Bid Stage Subitem | Effectively removes the task from the active queue; used for inapplicable BEAR/SPI tasks |
| 482374715 | Subitem due date set + Sales Rep = Jake | Auto-assign Jake to subitem | Watches deal_owner column — assigns Jake (92155649) to his subitems automatically |
| 482374716 | Subitem due date set + Sales Rep = Alan | Auto-assign Alan to subitem | Watches deal_owner column — assigns Alan (92155651) to his subitems automatically |
| 482374722 | Subitem due date = today (noon ET) | Notify subitem assignee | "Task due today: {task} is due {date} for {bid name}" |
| 482374728 / 482374735 / 482374751 | Subitem due date = today (11am ET) + not complete | Set parent status (Jake/Alan/Dylan Subitem Status) → Due Today | Three automations, one per person — highlights bids that need same-day attention on the parent item view |
| 482374745 / 482374748 / 482374755 | Subitem status → Complete + assignee = Dylan/Alan/Jake | Clear parent Subitem Status column (remove Due Today) | Clears the parent highlight once the person's task is done |
| 482374724Inactive | Bid Due Date - 5 days | Notify assigned reps | "Bid due in 5 days: {bid name} is due {date}. Delivery Method: {method}" |
| 482374730Inactive | Subitem due date + 3 days (overdue) | Notify subitem assignee | 3-day overdue task reminder — currently off |
| 482374713Inactive | Item enters Post-Monday group | Create item on Projects #4 + link via connect_boards6 | Replaced by 559103546 (E-Rate Deals creation). Left inactive as reference. |
| 482374738Inactive | Stage → Post-Monday | Notify CS/PM team | "Hello CS and PM, this project now has a PO and is ready for processing." Replaced by E-Rate Deals flow. |
| 7917794784 (workflow) | When Bid Stage status changes to something | Create a subitem | General-purpose workflow used to add subitems on specific stage transitions beyond the initial 23-task creation |
| 7917866595 (workflow) | When subitem column changes | Change parent item Bid Stage column to match | Keeps parent Bid Stage in sync when a subitem's Bid Stage Subitem column is manually changed |
| 566854668 / 566856009 / 566856718 (integrations) | Blueprint column → Wireless/Fiber Optic/BMIC | Overwrite item with matching item template | Three project-type templates applied when Blueprint is set on Bids #3 itemsApp |
| 545905802 / 545905803 (AI) | New item created / Item name changes | AI: extract "470#:" from item name → text_mkqz3hww | monday AI extraction automationAI |
| 578063979 / 578063986 (AI) | Item created (if Project Year empty) / text_mkqz3hww changes | AI: categorize into Project Year dropdown (dropdown_mkqz1ay) | Sets Project Year dropdown by AI-categorizing the 470# text columnAI |
| 591750313 | Stage → Ready for Invoicing (lead_status index 3) | Send webhook to vtg-billing-ready | Triggers billing notification email to eratebilling@vtgus.com |
| 628087115 | NS Sales Order # column (text_mm6hv20b) changes | Send webhook to vtg-po-sync | Live Aug 25 2026 — triggers PO sync back from NetSuite |
| Generate SOW button (Sep 8) | Generate SOW button (button_mm70vvrb) clicked on Bids #3 item | Send webhook to vtg-scopestack-doc-sync /generate endpoint | Triggers programmatic SOW generation in ScopeStack; webhook auto-delivers the .docx back to Bids #3 SOW Document column (file_mm6wm4hn) |
| 622380216 / 622381001 | Item created / any column changes | Send webhook to vtg-monday-sf-sync (keyed connection) | Salesforce Opportunity upsert · switched to the keyed connection Oct 1 2026 |
| 641680795 / 641680804 | Item created / Bid Stage (deal_stage) changes | Send webhook to vtg-sp-folders | Live Sep 24 2026 — creates the SharePoint bid folder at Folder Creation, writes SharePoint Link, closes both Folder Creation subitems |
| 645561102 | Addenda (file_mm7get0y) changes | Send webhook to vtg-sp-folders /addenda | Live Oct 1 2026 — copies addenda into the bid’s SharePoint folder root |
| 645821765 | SOV PDF (file_mm749nna) changes | Send webhook to vtg-sp-folders /sov | Live Oct 1 2026 — copies each SOV version to Base Bid Docs/3 -SOV (60 s delay) |
| 642315663 / 642315682 / 642315687 | Subitem created / subitem column changes / Bid Due Date changes | Send webhook to vtg-bid-task-dates | Live Sep 24 2026 — writes business-day due dates into subitem date3 |
| ID | Trigger | Action | Notes |
|---|---|---|---|
| 482368826 | New item created | Set Project Stage → New (index 6) | All new Projects #4 items start at New stage automatically |
| 482368825 | Stage → Kick Off | Move to Kick Off group | |
| 482368827 | Stage → All Products Received | Move to All Products Received group | |
| 482368829 | Stage → Pre-Install Staging (index 7) | Move to Construction Hold / Phased Install group | Group is "Construction Hold or Phased install" — covers hold and staging scenarios |
| 482368831 | Stage → Pre-Install Staging (index 11) | Move to Equipment Only group | Equipment-only projects route to the Equipment Only group on pre-install staging |
| 482368832 | Stage → Installing (index 8) | Move to Installing group | |
| 482368830 | Stage → Closeout (index 9) | Move to Closeout group | |
| 482368834 | Stage → Ready for Invoicing (index 3) | Move to Ready for Invoicing group | |
| 482368833 | Stage → Closed (index 4) | Move to Closed group | |
| 482368828Error | Stage → Waiting for Product | Move to Waiting for Product group | Error: "missing_group" — target group no longer exists. Group was likely deleted or renamed. |
| 591750313 (Projects webhook) | Stage → Ready for Invoicing | Send webhook to vtg-billing-ready | Fires billing notification email to eratebilling@vtgus.com via vtg-billing-ready Worker |
| 628087115 (Projects PO webhook) | NS Sales Order # column (text_mm6hv20b) changes | Send webhook to vtg-po-sync | Live Aug 25 2026 — fires vtg-po-sync when SO# is manually entered or backfilled |
| 639640003 / 639640004 | Timeline (timerange_mm1q29se) / Project Stage changes | Send webhook to vtg-revenue-month | Keeps Revenue Month equal to the Timeline end; stamps and locks it at Ready for Invoicing / Closed |
| 545905802 / 545905803 (AI) | New item created / Item name changes | AI: extract "470#" from item name → text_mkqz3hww | AI extracts 470# for reporting and linkingAI |
| 545919569 / 545919570Error | New item / name change | AI: extract Company → lead_company column | Error: "The chosen column no longer exists." Column was deleted; automations broken.AI |
| 578063979 / 578063986 (AI) | Item created (if Project Year empty) / text changes | AI: categorize into Project Year dropdown | Sets dropdown_mkqz1ay (Project Year) by AI categorization of the 470# textAI |
| 566854668 / 566856009 / 566856718 (integrations) | Blueprint column (color_mm2frt9j) → Wireless / Fiber Optic / BMIC | Overwrite item with matching item template | Three blueprint templates: "Wireless deployment - VectorFi - Wired", "Fiber Optic Cabling", "BMIC"App |
| 7917221940 (workflow) | Stage → Accept (index 6) | Move item to Construction Hold / Phased Install group | |
| 7917971701 (workflow) Inactive | Subitem status → Done (from anything) | Move parent item to Ready for Invoicing group | An older subitem-driven billing trigger — now superseded by vtg-materials-log stage advancement |
| 7917999463 (workflow) | Stage → Ready for Invoicing | Notify Accounting team | "This project is complete and ready to bill in full" — notifies the Accounting team (team ID 1424500) in monday.com |
| 7918015674 (workflow) | Blueprint column changes + contains BMIC | Create subitem assigned to Engineer team | "Insert the first row here" + "This might be a spot for the task" — a partially-configured placeholder; may need refinement |
| 7918629648 (workflow) | Stage → Equipment Only (index 11) | Move to Equipment Only group | |
| 7918731761 (workflow) | Blueprint column changes + Blueprint = Equipment Only (label 8) | Move to Equipment Only group | Routes equipment-only projects to the correct group when Blueprint is selected |
| 7920172789 (workflow) | Stage → Ready for Invoicing | Set Actual Revenue Month (date_mm4tatyy) = today | Stamps the revenue date for Forecast vs. Actual dashboard |
| 7920172818 (workflow) | Stage → Closed | Set Actual Revenue Month (date_mm4tatyy) = today | Also stamps revenue date on Closed — covers projects that skip Ready for Invoicing |
| 7920230690 (workflow) | Stage → Closed | Notify Branden Sumerix + Dylan Lindhout | "Performance Bond Complete — notify the bonding company that this project is complete." |
| 7920569056 (workflow) | Stage → Ready for Invoicing | Set Ready for Invoicing Date (date_mm54qwps) = today | Timestamps the Ready for Invoicing date for billing SLA tracking |
| 7922447604 (workflow) | Stage → Installing | Set Materials Log link column (link_mm6mhdcx) = vtg-materials-log URL for this item | Live Aug 27 2026 — auto-populates the PM's one-click link to the materials log tool |
| backfill (Sep 3) | One-time | Populate new 📊 SOV Builder column (link_mm6vbks) for all 156 existing bids | Manual backfill completed Sep 3 2026; vtg-bid-intake now stamps both link_mm6vbks and link_mm591mdg on new bid creation going forward |
config/tools.json. Admin is currently password-gated; Azure AD SSO is planned.DECK_DATA) and the browser builds the PowerPoint with PptxGenJS. The deployed copy (Sep 19 2026 snapshot) makes no monday.com calls — the figures are what each lead enters. Used for monthly leadership reviews.Changelog
A record of all process changes, new Workers, and infrastructure updates to the VTG Lead → Invoice system.
| Date | Version | Type | Change |
|---|---|---|---|
| October 1, 2026 | |||
| Oct 1 | v2.14 | UI | Gap Analysis filters — chips at the top of Gap Analysis turn cards on and off by priority (High / Medium / Low), Paused, and Resolved / Done (which includes Live and Retired), and by section (Active gaps / Planned). Each chip shows its count, "Show all" resets, and the choice is remembered in your browser. |
| Oct 1 | v2.13 | Update | Map checked against what is built — Every gap and Worker card compared with the current VTG Flows source, monday webhooks and automations, and live board data. Thirteen cards that showed planned or open work were already built; twelve Worker cards had wrong details. All corrected here, and seven deployed Workers that were missing are added. |
| Oct 1 | v2.13 | New | vtg-sp-folders live since Sep 24 — Bid folders are created automatically at Folder Creation: Base Bid Docs copied with files, Lead files in the root, SharePoint Link filled, both Folder Creation subitems closed. 12 of 13 bids created Sep 24 – Oct 1 were done by the Worker; the 13th (a test bid with an invalid 470#) went Stuck as designed. Addenda and SOV copy added Oct 1. |
| Oct 1 | v2.13 | Gap Resolved | Subitem reminders now fire — vtg-bid-task-dates live since Sep 24 — Due dates are written into date3 in business days, so the due-today notification, highlights and auto-assign automations finally have a date to act on. |
| Oct 1 | v2.13 | New | NetSuite customer created from the CS Order form (Sep 28) · Remaining to Bill live · tax certificates done — New Client Setup creates or links the NetSuite customer through vtg-ns-so-backfill and writes the NS ID to Accounts #1. Invoiced to Date / Remaining to Bill fill every 4 hours (89 projects). 85 accounts carry their tax-exempt certificate. The Sep 29 entry saying vtg-cs-form does not create the NetSuite customer had checked the Sep 24 copy. |
| Oct 1 | v2.13 | Gap Resolved | Addenda attach to the live bid (Oct 1) — vtg-bid-intake handles addendum files added to an existing lead with a live bid; reps no longer re-do the intake form. Dylan’s two Accepted → New Leads addendum automations were deactivated. Addendum detection runs live (dry run off). |
| Oct 1 | v2.13 | Process Change | ConnectWise Sell / CPQ paused (Sep 29) — Six CPQ cards moved to Paused, and the diagram decision point is now a paused step. vtg-cs-form still calls vtg-monday-cpq on every CS Order submit. |
| Oct 1 | v2.13 | New | Seven deployed Workers added to the map — vtg-revenue-month, vtg-lead-score, vtg-meeting-sync, vtg-logo-backfill, vtg-deck-builder, vtg-ns-mcp-sync-staging and vtg-ns-test — added to the Workers tab and, where they act, to the diagram, SOP, Data Flow, Automations and Glossary. |
| Oct 1 | v2.13 | Infrastructure | vtg-ns-compare deleted — Deleted Oct 1 2026. Customer mapping is now the NetSuite Customer Internal ID on Accounts #1. |
| Oct 1 | v2.13 | Fix | Corrections — vtg-po-sync writes Vendor PO #, not Customer PO #. vtg-sf-account-sync writes UID__c, not the Account ID. vtg-bid-intake is triggered by Status → Pending Intake (632506055); 608965294 is deactivated. The TD Synnex binding is not called — the duplicate Planned TD Synnex card is removed. vtg-ns-so-backfill card rewritten for v18. The Data Flow stage-map note is settled from the live code. The deck builder makes no monday calls. |
| Oct 1 | v2.13 | UI | Diagram columns line up again — cells now stack their steps vertically, so every step sits under its own phase header instead of pushing later phases sideways. |
| Oct 1 | v2.12 | Infrastructure | The UID is reference only — NetSuite Customer Internal ID is the match key — The UID (Salesforce UID__c auto-number) was adopted as the cross-system key and has been demoted. Salesforce duplicates accounts — 69 duplicates sent to Merlin for review — the value has not been stable, SF requirements keep moving, and it never matched NetSuite’s custentity_acs_unique_entity_identifier, which uses different numbering. Legacy rows carry blank or stale UIDs: 17 Projects #4 rows read "Cannot verify" as of Sep 28, and the fuzzy-name fallback is now off rather than papering over them. In its place the NS Customer Internal ID (text_mm7m8z67 on Accounts) is the matching key, and new NS customers created from the CS form carry externalId mon-<monday item id> — live since Sep 28. One dependency remains: vtg-ns-so-backfill’s auto-sync still links project → account by UID. The Data Flow note, the glossary entry and the order-push card were all updated to match. |
| Oct 1 | v2.11 | Resolved | Both Salesforce Workers are now key-protected — vtg-monday-sf-sync (version dc33a840) and vtg-sf-account-sync (version e6d28b50). monday’s "send a webhook" automation sends no signature, so signature checking was never going to work; both Workers now require a shared key in the URL (?key=), checked before anything else, with 401 on anything unkeyed. They also narrowed what they accept: non-numeric item IDs are rejected, vtg-monday-sf-sync takes Bids #3 items only, vtg-sf-account-sync’s sync-by-ID takes Accounts #1 items only, and every route but /health is keyed. Both Bids #3 automations were switched to the keyed connection, and backfill.mjs now reads ACCOUNT_SYNC_KEY. Verified with a 401 on an unkeyed request and a live sync of Clinton Macomb Public Library. |
| Oct 1 | v2.11 | Infrastructure | The old check failed twice over · secrets deleted — Worth recording because it explains why nothing caught it: the signature check on vtg-monday-sf-sync had two independent reasons it could never pass. The header never arrives, and the code read WEBHOOK_SECRET while the deployed secret was named MONDAY_WEBHOOK_SECRET. Fixing either one alone would have left it broken and looking fixed. On vtg-sf-account-sync the same pattern appeared again — /webhook checking an Authorization header monday never sends, while /sync/:itemId and /backfill had no check at all. The misnamed secret binding and the old WEBHOOK_SECRET have been deleted, and the binding name no longer appears on this map. It remains in this repo’s git history; the secret itself no longer exists. |
| Oct 1 | v2.11 | Gap | The Account → Salesforce webhook cannot be found — The automations table has carried "SF sync webhook → vtg-sf-account-sync · LIVE Sep 8 2026" since it was built. Checked Oct 1: the Accounts #1 board has exactly two webhooks, both created Jul 28, and both feed the logo Worker. vtg-sf-account-sync recorded zero invocations in the preceding seven days. The row is kept and marked NOT WIRED rather than deleted — the Worker does the work it claims, but only when called, and today the only caller is backfill.mjs run by hand. SOP step 0.3 and the Account Sync detail panel were reworded to match; a new Low gap records the consequence, that a new or edited account sits in monday until someone runs the backfill. Low only because Salesforce integration work is paused. |
| Oct 1 | v2.10 | Infrastructure | An addendum was making reps decline the lead — Found in the field at Kent ISD. When an addendum arrived, the automation sent the lead back to New Leads, so a rep had to complete a whole new intake form to re-accept a bid they were already working — and faced with that, reps declined those leads instead. The addendum screen exists to stop a second bid; this path was creating a second intake. Direction set: the Worker handles addendum files added to existing leads that already have a live bid, and Dylan’s two "Accepted Leads → New Leads" addendum automations are turned off. One of the few changes that touches Dylan’s automations rather than routing around them. |
| Oct 1 | v2.10 | Update | Addenda to be copied into the bid’s SharePoint folder — Same treatment the RFP already gets, placed in the bid folder root next to the RFP and the 470 rather than a separate Addenda subfolder. Driven by a Bids #3 Addenda webhook. The route is /addenda on vtg-sp-folders and is key-less because the existing WEBHOOK_KEY could not be recovered; every other route keeps its key. Logged plainly because it is a second unauthenticated endpoint on this map. |
| Sep 30 | v2.10 | Resolved | Salesforce CloseDate fixed — and the obvious fix would have broken it — Shipped 21 Sep, both paths verified in production. New date_mm7dfkx Actual Close Date column on Bids #3, stamped when the bid reaches Post-Sale; precedence Actual Close Date → Bid Due + 65 days → Creation + 65 (warned) → old fallback. One-way monday → Salesforce. The first suggestion was to use the existing Expected Award Date column — measurement killed it: 0 of 500 bids have it set, so the sync would have sent a null to a required Salesforce field, while 498 of 500 have Bid Due Date. Amount is unchanged and still takes a placeholder bid value as a real forecast number. |
| Sep 30 | v2.10 | Infrastructure | Why the Salesforce endpoint can never authenticate — Established from the source rather than inferred. The Worker reads x-monday-signature, which monday does not send for a "send a webhook" automation, and verifySignature returns false on an empty signature — so the check can never pass and the secret is irrelevant. It was written against a header that never arrives. Fixing it means a scheme monday actually sends, or a shared secret in the URL. Separately, the write volume now has a cause: the "any column changes" webhook fires on subitems, so every subitem creation is another Salesforce write — 8 for a Post-Sale transition, ~22 for a bid creation. That is what the 414-run count was, not user edits. One-line early return fixes it. |
| Sep 30 | v2.10 | Update | Two corrections: the SOW and SOV generators were never broken — Both were called broken during the walkthrough and both were working. Generate SOW simply takes ~3.5 minutes with no status column, which is indistinguishable from a failure; the SOV export had never been run on the bids being checked. The gap stands, but as a reporting gap. Likewise the two CS Order subitems are not an automation duplicate — vtg-cs-form creates the linked one and dedupes via KV, Dylan’s automation creates the plain checklist row. Nothing to raise there. |
| Sep 30 | v2.10 | Update | The PO validator accepts its own placeholder — The hard block rejects N/A, TBD, all-x and all-zero, and a PO needs no particular format beyond being filled in. But the form’s own hint, PO-XXXX, normalises to poxxxx, which is not in the reject list — so typing the placeholder the form shows you passes the check meant to stop exactly that. One word closes it. Also: the Ionia walkthrough is finished and its records are deleted — bid 13089254247, test bids 13087066256 and 13089189680, and deal reg 13093685203 are all gone. |
| September 29, 2026 | |||
| Sep 29 | v2.9 | New | Data Flow tab added — Connectors carry real arrowheads, so the direction each record moves is readable at a glance rather than inferred from a caption. A system-level view of what actually runs: which system holds which record and what moves between them, for E-Rate and for Commercial, switchable. It shows only built and deployed behaviour — the three hand-keyed steps (NetSuite customer, sales order, invoice) are drawn as by-hand rather than omitted, and nothing planned appears on it, so it cannot drift from Gap Analysis by repeating it. Built for readers outside the team, which is why it sits second rather than behind the Changelog. |
| Sep 29 | v2.9 | Infrastructure | vtg-cs-form does not create the NetSuite customer — Checked while building the Data Flow tab, because the new-client setup had been drawn elsewhere as live. Searched the deployed worker.js (Sep 24 copy, 130 KB): the only two occurrences of "NetSuite" in the whole file are the PO-number comment and its matching toast string. No SuiteTalk call, no customer create, no NS ID write-back, no custentity reference. So the NetSuite customer is still created by hand, the Planned entry for the monday client form stands, and the intake-vs-win question about when the NS customer gets created is moot until something builds it. Caveat: that copy predates Sep 25, and Cloudflare is the source of truth — if it shipped after Sep 24 this needs revisiting. |
| Sep 29 | v2.9 | Infrastructure | Two accounts of the Salesforce stage map — unresolved — The Workers tab documents vtg-monday-sf-sync with a six-entry stage map (Folder Creation→1 … Awaiting Results→6), while the Sep 21 walkthrough recorded that Folder Creation, Deal Reg and Bid Compilation send no stage at all. Both statements are on this site and they cannot both be right — most likely the map exists in code but the send is conditional. Flagged on the Data Flow tab rather than silently picking one. Worth an hour with wrangler tail. Separately, the absence of any Post-Sale or Won entry in that map is what supports "Won is not sent". |
| September 28, 2026 | |||
| Sep 28 | v2.8 | Infrastructure | ⚠ The UID has not proved stable — reversal — The UID (Salesforce Account ID) was adopted as the cross-system source of truth on the understanding that the monday ↔ Salesforce sync was 100% reliable. It has not held: Salesforce duplicates contacts, the UID has not been stable, and Salesforce’s requirements keep changing. That leaves two problems where the map previously recorded one — legacy records with blank or stale UIDs, and newly-issued UIDs that cannot simply be trusted. The gap is raised to High and the glossary entry now carries the caveat. It also sharpens the case for the monday → NetSuite order push and the direct NS customer create: an identity minted where the record is created does not depend on a third system staying still. |
| Sep 28 | v2.8 | New | Account creation order settled: monday → NetSuite → Salesforce — Account created in monday first, then the customer in NetSuite, then Salesforce, with the SF UID returned to both monday and NS. The NetSuite customer is created at won/order, not at lead. This reconciles the Sep 24 position (Salesforce out of the flow) with Bill’s new-client checklist automation: SF still gets the data, last, for reporting. Context for why the automation matters at all — sales reps do not want to create accounts in Salesforce and only do so when forced, on non-E-Rate work. Build notes: NetSuite API work runs under "VTG API Sync", an integration identity with no GUI login but full API access, whose keys an existing Worker already holds; and on the new-client form a requested credit limit over the threshold flags but does not block the NS create. SOP step 1.0 updated. |
| Sep 25 | v2.8 | New | Bid bond workflow rebuilt — live — VTG’s surety is Alliant, and they confirmed system-generated requests are fine and that a lost-bid notice is enough to release a bond; the only real gap was delivery instructions. So the intake form now requires a delivery choice when the bond toggle is on: Electronic (Surety2000 / BidExpress / Other) or Physical, the default, with ship-to defaulting to the VTG office, editable, plus an instructions field. Bond emails go To CHC-Surety@alliant.com + bonds@vtgus.com, Cc Danny Rose, Nicholas Manning and the sales rep, all on one send. Bond Type is fixed at Surety bond — VTG uses surety bonds only. Needed-by defaults to 7 business days after submission, editable. Requesting sets the bid’s "Get bid bond - TOTAL = $" subitem to Requested; a bid set to Lost auto-cancels its bond, and a new Not Needed status sends the same cancellation. Pushed live Sep 25, pending Jon’s own live test. |
| Sep 25 | v2.8 | Update | Intake contacts section replaces the single delivery field — Three role relations to Contacts #2 — board_relation_mm7gf0s2 End User, board_relation_mm7g1dbz Consultant, board_relation_mm7g72h8 eRate — plus text_mm7gb8eg Additional Recipients. Contacts are linked to Contacts #2, not duplicated as bid columns. Suggestions: consultant = best-scoring contact that looks like one, end user = best that does not, eRate = whoever filed the 470. "+ Add someone else" needs name and email, matches on email first to reuse a record, links it to the Account and types it Customer / Consultant so the scorer improves each bid — and a failed CRM write never fails the bid. Additional recipients are deliberately not written back. Bid delivery now takes multiple recipients as checkboxes across the three roles plus "a different address"; nothing is pre-ticked so the confirmation gate stays deliberate, and addresses de-duplicate since the consultant is often also the eRate contact. monday’s email column holds one address, so email_mm7gr1ce keeps the first recipient and text_mm7gt2na Bid Delivery Recipients holds the full list. A Billing contact field and the proposed Optional 1–5 fields were both dropped as excessive. |
| Sep 28 | v2.8 | Update | Tax-exempt certificates to be pulled into monday · Design Desk bypassed — Customer tax-exempt certificates live in the SharePoint All Company Documentation library under Customers\<customer>\Accounting Documents; the library is synced but not downloaded (too large), so it has to be read through Graph. Logged as a Medium planned item — it back-fills what vtg-cs-form already captures at order time. Separately, the Design Desk dependency stays open but is being bypassed by routing orders monday → NetSuite directly. |
| September 25, 2026 | |||
| Sep 25 | v2.7 | New | ScopeStack customer summary now written by Claude, from monday — The team used to log into ScopeStack and write each project’s Customer Summary there. It now runs inside vtg-scopestack-doc-sync, which already held the ScopeStack API credentials. ScopeStack’s own generator was enabled first (Generate Executive Summary: Create on the Admin role) and produced poor output — it leaked "missing the JSON" text into the summary — so the writing is done by Claude via the Anthropic API, with a VTG organization key stored as ANTHROPIC_API_KEY on the Worker. It runs as part of the existing Generate SOW button; a separate "Write Summary" button was built and then removed, so there is one button, not two. One constraint worth remembering: ScopeStack’s SOW template prints Markdown symbols literally, so summary text written back must be plain text. |
| Sep 24 | v2.7 | New | vtg-bid-task-dates approved — business-day subitem scheduling — The subitem plan counts back from Bid Due Date in calendar days with no weekend or holiday logic. New Worker converts the automation’s existing calendar-day offsets into equivalent business days (keeping the plan about the same length rather than reusing the numbers), skipping federal holidays only — no special Christmas–New Year handling. It works on subitems after creation so Dylan’s subitem-creation automation is untouched, and applies going forward only; existing bids are left alone. Delivery rules pinned: email bids can compile the day before sending; mailed bids go out 5 days before due, with Appendix C on the day of or the day after SOV/SOW. Mail transit is already in the offsets. If it proves out, the date3 "Task Due Date - Manual" column comes out entirely — which also closes the dead-reminder gap. |
| Sep 24 | v2.7 | Infrastructure | Salesforce comes out of the flow · client form writes to NetSuite directly — Salesforce integration work is stopped until Salesforce settles its final product. It stays as the sales team’s pipeline reporting layer, not a link in the order-to-invoice chain, and nothing new gets built on it — the existing sync Workers keep running because that is how the UID is written back. In its place, the monday client form will create the new customer directly in NetSuite, carrying Cari’s required new-client fields (the same set Wendy is adding to the CSOP) so finance has what it needs at intake instead of chasing it at invoice time. Same principle as the planned monday → NS order push: create the record in NS when it exists rather than reconciling afterwards. SOP step 1.0 revised to match. |
| Sep 24 | v2.7 | Update | "Remaining to invoice" wanted on Projects #4 — VTG progress-bills heavily on that board and nothing shows how much of a project is still uninvoiced. Capture invoiced amounts from NetSuite, subtract from Total Project Amount. Source-of-truth split is deliberate: monday.com owns the contract value (the sales proposal originates there and the team checks it there), NetSuite reports invoiced actuals against it. Scope is invoiced only — no collections, no AR, no credit-memo netting. Logged under Planned. |
| Sep 24 | v2.7 | Infrastructure | Group-wide quote-to-cash consolidation in play — Bigger than this map but it will reshape what sits under it. Bill Loiacano ran a Quote-to-Cash discovery across the group (Comm Core, VTG logistics, Quotient, JJ’s), now moving from discovery into decision and execution, with Kevin F. wanting Jon, Bill and Radde on the group’s Q2C processes. Open feasibility question: drop Rev.io (Comm Core) in favour of NetSuite billing with monday for PM — can it be done and at what cost. The VoIP business stays and gets integrated rather than retired. |
| Sep 24 | v2.7 | Update | Bid subitems should be created from intake selections, not pruned by hand — Every bid is created with the full subitem set and the team deletes what does not apply, on every bid, all season. The intake form already captures what decides it — delivery method, bond required, blueprint selection. Logged as a Medium gap; queued behind the date engine. |
| September 22–24, 2026 | |||
| Sep 24 | v2.6 | New | vtg-bid-intake — RFP addendum detection live — An addendum used to arrive on the Leads board looking like a brand-new opportunity and get worked as a second bid. New POST /lead-created endpoint, monday webhook 642139356 on Leads create_item, matches the lead name (the bare 470) against Bids #3 470__: one 470 never covers two separately-bid RFPs, so a repeat is an addendum. It attaches the document, stamps the new addendum columns and posts a courtesy update on the lead so nobody clicks Accept 470 — and never moves the bid’s stage. Guards: acts only on exactly one match in a live stage; zero, closed-stage and multiple-live matches log and do nothing. Dedupe strips monday’s <assetId>- prefix, without which the same certified 470 re-copies on every lead. Errors are swallowed so a new lead is never held up. Shipped behind ADDENDUM_DRY_RUN. Two API notes worth keeping: compare_value takes the CompareValue scalar, not [String!]; and only all-digit 470 values are matchable, which excludes the CBR4… / Non ERATE / No 470 bids. |
| Sep 24 | v2.6 | New | Bid Delivery Contact confirmation on the intake form — The form pulls the contact email, asks whether that is who the bid should be delivered to, keeps it editable, and hard-blocks submit until it is confirmed — required whatever the delivery method, because that contact is also who bid questions go to. Three states: suggestion with Yes/No radios, consultant suggestion with a warning, no contact on file (radios gone, email required). contactCandidates() split out of pickContact() so the suggestion and the contact linked at submit use one scorer; candidate fetch is single-pass with no retries so a missing account record cannot hang the form. Validated in the browser and again in /submit. Confirmed address lands in the archived intake PDF. A free-text delivery-instructions field was considered and declined for this phase. |
| Sep 24 | v2.6 | Infrastructure | Six new Bids #3 columns — file_mm7get0y Addenda (holds addendum 1, 2, 3 …), numeric_mm7gj7zz Addendum #, date_mm7gbfs7 Last Addendum Date, color_mm7ghh94 Addendum Status (Received - Unreviewed / Reviewed), email_mm7gr1ce Bid Delivery Email, date_mm7gj5zp Delivery Contact Confirmed. |
| Sep 23 | v2.6 | Update | vtg-sp-folders design settled — Built as a Cloudflare Worker calling Microsoft Graph off a monday webhook, not Zapier/Make or a marketplace app. Folder name is the bid name with the colon removed (SharePoint rejects ":"). Standard subfolders come from the Base Bid Docs template (1-Cover Page … 9-Product Support Info) and are copied with their files, so each bid folder opens with VTG’s standard bid documents already in it. The Worker fills the SharePoint Link column, completes both Folder Creation subitems and uploads the Lead’s 470/RFP PDFs. Blocked on an Entra app registration + site grant from the M365 administrator; request email drafted. |
| Sep 22 | v2.6 | Infrastructure | Pricing scope corrections · SOV Builder — Three facts worth pinning because they shape the discount-tier work: the top-level bidder/driver discount model applies only to Ruckus parts, not to every manufacturer; VTG does not sell Ruckus vSZD (virtual SmartZone Data Plane); and the TP-Link/Omada price list is now in hand — TP-Link is a carried line, so that half of the pending-catalogs gap is unblocked. Vertiv is still outstanding. |
| Sep 22 | v2.6 | Infrastructure | Credential rotation flagged — Four credentials are hardcoded in vtg_sov_import_v4.py, across three copies of the file in the OneDrive-synced VTG Flows folder. Logged as a High gap: rotate, move to env vars or wrangler secret, delete the stale copies. |
| September 21, 2026 | |||
| Sep 21 | v2.5 | Fix | SOV Builder — a building could not be renamed — Renaming was implemented, as a double-click on the tab label, but nothing advertised it: no tooltip, no pencil, no affordance. The only tab control carrying a title was the harmless duplicate button; the × that deletes a building had none. Worse, the handler called window.prompt(), which browsers suppress in sandboxed and embedded contexts and which Chrome disables for the rest of a page's life once "prevent additional dialogs" is ticked — so for some users the double-click did nothing at all. It now reuses the in-page modal that Add building already used, prefilled and selected, with the mode and heading reset on cancel. Both tab buttons gained tooltips. |
| Sep 21 | v2.5 | Infrastructure | vtg-sov-builder deploys worker-combined.js, not index.js — Recorded because three patch attempts changed nothing before this was noticed. wrangler.toml sets main = "worker-combined.js" in the folder root (~108 KB); index.js is a dead file from 14 Aug that nothing deploys, and two further stale copies of worker-combined.js sit under files\ (20 Aug) and Archive\files\ (14 Aug). Patch scripts for this worker must resolve the target from wrangler's main rather than guessing filenames. The first failure was initially misread as a line-ending problem, which cost four no-op deploys. |
| Sep 21 | v2.5 | Update | Bid Building walked end to end on a real bid — Ionia Public Schools (470# 270000574, bid 13089254247) taken from Folder Creation through Bid Compilation with a live tail running. SharePoint folder linked, deal reg created by automation 482374704, and all three artifacts produced: SOW (asset 3261375108), SOV PDF (3261392198) and Proposal PDF (3261481236). Fourteen Bid Building subitems closed. Every finding below came out of that walk. |
| Sep 21 | v2.5 | Gap | The subitem task schedule is computed and then ignored — formula8 "Task Due Date Formula" correctly derives each subitem's due date (FORMAT_DATE(SUBTRACT_DAYS({date},{numbers0}))), but date3 "Task Due Date - Manual" is empty on every subitem — and date3 is what seven active automations trigger on: the due-today notification, the three per-person row highlights, and the three auto-assign rules. monday formula columns cannot trigger automations, so the whole subitem reminder system is inert, which is almost certainly why the overdue reminder was switched off rather than fixed. Autoboost recipe 483152942 already writes a formula result into a real date column, so one more recipe of the same shape fixes it without editing anyone's automations. Caution: the three auto-assigns fire on that column changing, so a bulk backfill would trigger a wave of reassignments. |
| Sep 21 | v2.5 | Gap | Salesforce receives almost nothing, fourteen times — One morning's walkthrough produced 14 updates to Opportunity 006aZ00000jC0OvQAK, every payload identical but for the timestamp. None of the work reached Salesforce: not the SOW, the SOV, the Proposal, the SharePoint folder, the deal reg, the 470 number, the account or the contact. Three separate problems sit behind that. skip: true only suppresses StageName — the Opportunity is still written on every column change at every stage. The stage map is incomplete, so Folder Creation, Deal Reg and Bid Compilation send no stage at all and Salesforce reads one or more steps behind monday. And CloseDate is populated from deal_creation_date, so every E-Rate Opportunity is created with a close date already in the past — Bids #3 has an unused date_mm2c6t1k "Expected Award Date" column that is the correct source. |
| Sep 21 | v2.5 | Gap | vtg-monday-sf-sync accepts unsigned requests — Every invocation logs HMAC mismatch — sig received: <empty> and then processes the request anyway, so the public endpoint will write to a Salesforce Opportunity for anyone who knows the URL. The signature arriving empty has two plausible causes: monday's plain "send a webhook" action does not HMAC-sign its body, so the check may be for something that never arrives; or the secret is unreachable. The second is worth checking first — vtg-sf-account-sync carries a misnamed secret binding (deleted Oct 1 2026) that looks like a secret value pasted into the name field, leaving WEBHOOK_SECRET undefined and the comparison unable to succeed. |
| Sep 21 | v2.5 | Gap | Generate SOW runs silently for three and a half minutes — Generate Proposal sets its status column to Working on it, produces the PDF and sets Done, the whole run taking nine seconds. Generate SOW has no status column at all: it goes quiet and a file appears some minutes later, which is indistinguishable from a failure and was in fact mistaken for one during this walkthrough. It needs a SOW Status column and the same pattern. Its filename also doubles the district name — Ionia-Public-Schools-Ionia-Public-Schools-470_-270000574-… — because the account name is prepended to a bid name that already starts with it. Separately, neither generator closes its own Create SOW / Create SOV subitem, so the artifact exists while the task still says it does not. |
| Sep 21 | v2.5 | Gap | The SOV Builder link is not written at bid creation — link_mm6vbks is described on the board as auto-populated, but nothing in the current creation path writes it. Ionia arrived through vtg-bid-intake with its Customer Intake Form link set and no SOV Builder link; the ten older bids that have one most likely got it from a one-off backfill. Every new bid this season will arrive without it. The format is https://vtg-sov-builder.vectorfi-admin.workers.dev/?item=<itemId> — note ?item=, where vtg-cs-form uses ?bid=. The intake worker already writes the intake link at the same moment, so this is a couple of lines in a function that is already running. |
| Sep 21 | v2.5 | Infrastructure | Board mechanics worth knowing before touching a bid — There is no group-move automation for Bid Stage → Folder Creation; every other stage has one, because the first stage was only ever reached at item creation. Sending a bid back to the start leaves stage and group disagreeing until someone drags it. Subitem status Create Item is the starting state for the five steps that produce an artifact, not a decoration. Setting a subitem's Status to N/A triggers automation 482374711, which clears its columns and deletes it — the intended way to strip Post-Sale subitems off a bid that was sent back. And monday's API will not return webhook target URLs, so a worker's name has to come from wrangler or the automation UI. |
| September 20, 2026 | |||
| Sep 20 | v2.4 | Gap Resolved | Customer PO # is now required on the CS Order form — Closes the Medium gap logged Sep 18. A hard block: no PO, no submission. Placeholders are refused too — the value is normalised to letters and digits, so N/A, n.a., TBD, pending, XXXX and 0000 all bounce, because a PO of "N/A" looks like a value and verifies nothing against NetSuite. Both required fields on the form now show an asterisk; previously nothing indicated that Target / Deadline Date was mandatory either. |
| Sep 20 | v2.4 | Fix | vtg-bid-intake — every bid was being created with no Account and no Contact — The lookup declared its GraphQL variable as [ItemsQuery!] where monday expects [ItemsQueryRule!], so the query failed validation before it ever ran. An empty catch (_) {} swallowed the error, the function retried four times with 5-second sleeps and returned nulls, and the bid was created successfully with both relations blank. The tell was a consistent 17-second gap between form submit and the bid appearing — three sleeps of five seconds. Reproduced on two controlled runs, fixed, and verified in production on bid 13089254247. |
| Sep 20 | v2.4 | Update | Contact selection rewritten and scored — Candidates now come from the Account's own Contacts relation rather than a board-wide name search, which had been returning the USAC billed_entity placeholder — a record named after the district, with no email and no person behind it. Duplicate emails collapse to the most recently updated record (El Nova creates a fresh contact per bid instead of updating the existing one, so 8% of accounts carry duplicates). Survivors are scored on email domain vs the Account website, Customer status, USAC technical type and job title, with consultants penalised heavily. Below the bar the field is left blank on purpose — a blank gets noticed, a confidently wrong contact does not. |
| Sep 20 | v2.4 | Fix | Automatic district logos — 6 found in two months, now 242 of 331 — vtg-account-logo and vtg-logo-backfill shared a scraper that only read <img src>. Finalsite, ParentSquare and similar K-12 platforms emit no src at all in served HTML; the real URLs sit in data-image-sizes as percent-encoded JSON. Its Clearbit fallback had been dead since HubSpot shut the free Logo API on 8 Dec 2025, and its favicon guard didn't work — a favicon scored 14 and passed. The replacement reads lazy-load attributes, scores candidates by filename, alt text, CSS class and position, prefers a wordmark over an icon mark, and writes only at 70+. Measured read-only across all 331 addressable accounts before anything was written. |
| Sep 20 | v2.4 | New | Completed Intake Form PDF on Bids #3 — The intake form now builds a PDF of everything submitted and attaches it to file_mm5bhcw7 on the new bid, using the same client-side jsPDF approach as vtg-cs-form. PDF generation can never block a submission; if it fails the bid is still created and the failure is logged. Note add_file_to_column appends rather than overwrites, so a future resubmit path would stack PDFs. |
| Sep 20 | v2.4 | Fix | E-Rate Primary Contact dropdown and the blueprint mirror — The intake form's contact dropdown was a hardcoded ['Jake','Alan','Ruckus'] that had drifted from the monday column, so "John" could never be selected. It now reads the column's labels live and honours deactivated ones, meaning the list is managed in monday and cannot drift again. Separately, blueprint_name on Bids #3 was a mirror pointing at a Leads column that no longer exists (dropdown_mkw331zh); repointed to ScopeStack Blueprint(s). The Worker was never at fault there — it links the lead correctly. |
| Sep 20 | v2.4 | Infrastructure | Silent failure treated as the real defect — Every bug above shared one cause: the failing path was the only one with no logging. The Account/Contact lookup, the logo scraper and the logo upload all swallowed their errors into empty catch blocks, which is why a 100%-reproducible bug survived months of production. Each now emits a tagged line — [contact-match], [intake-pdf], [logo-match] — naming what it chose, what it scored and why. vtg-account-logo already has observability with persisted logs enabled, so its output is visible in the Cloudflare dashboard, not only in a live tail. |
| September 18, 2026 | |||
| Sep 18 | v2.3 | Infrastructure | monday → NetSuite order push adopted as the direction — The monday ↔ NS record link is today reconstructed after the fact (UID-exact match with a fuzzy-name fallback in vtg-ns-so-backfill, read-back in vtg-po-sync). That is now formally a stopgap. The direction of travel is to create the order in NetSuite from monday at order time, so the NS record carries the monday/UID identity from creation and matching is accurate by construction. Added as a High item under Planned; the customer ID mapping blocker on the invoice flow is expected to fall out of it. |
| Sep 18 | v2.3 | Update | Customer PO # to be required on the CS Order form — The form and the Projects #4 item it creates already carry a customer PO number, but it is optional. Plan: make it required and use it as the verification key against the NetSuite order, alongside UID matching. Logged as a Medium gap. |
| Sep 18 | v2.3 | Infrastructure | UID confirmed as the cross-system source of truth · two new gaps logged — The UID (Salesforce Account ID, produced by the reliable monday ↔ Salesforce sync) is the standard going forward for every cross-system link; name matching is fallback only. Two consequences written onto the map: legacy monday records predate the standard and still need cleanup (Medium), and NetSuite data cleanup has no owner (Medium) — NS needs significant cleanup but is not a program Jon owns, so it needs an owner on the finance/NS side. |
| Sep 18 | v2.3 | Update | Salesforce system-of-record rule added to the Commercial track — New step 1.0: Salesforce is the system of record for commercial (non-E-Rate) pipeline — "if it's not in Salesforce, it didn't happen." Routing rule documented: no E-Rate/FCC funding → Salesforce; E-Rate → monday.com; the non-E-Rate portion of a split-funded deal is tracked in Salesforce separately. vtg-sf-account-sync and vtg-monday-sf-sync are what keep reps from double-entering. Source: VTG Salesforce SOP v2.1 (Sep 9 2026). |
| September 17, 2026 | |||
| Sep 17 | v2.2 | Update | vtg-cs-form — tax exemption certificate capture — Section 1 gains a Tax Exempt Yes/No radio (defaults Yes) with certificate upload. New Tax Exempt Certificate file column on 🏢 Accounts #1 (file_mm79y1x5): an existing cert is auto-pulled and attached to the order and the email; a cert uploaded through the form replaces the Account copy (column cleared first, since add_file_to_column appends). Status and cert state land in the monday update body and the CSOP PDF. Blank-mode orders email the cert but write nothing to Accounts. |
| Sep 17 | v2.2 | Update | vtg-cs-form — Licensing Order email prefill + bug fix — The Licensing Order checkbox handler read sm7 ("Create work order with the attached SOW") instead of sm9, so the email field could never be revealed. Fixed. New Licensing Email column on 📡 Controller Serials (email_mm799qya) prefills the field from a prior order once the box is checked; the address is only submitted when Licensing Order is actually selected. Both new columns are resolved by title and type, so a rename does not silently break the lookup. |
| Sep 17 | v2.2 | Infrastructure | Process map accuracy audit — Every hardcoded column ID, status label and board ID on this map checked against the live monday boards and the deployed Worker source. Corrections: TD Synnex live pricing moved from Resolved back to an open High gap (binding declared, never called); SOV Builder trigger column corrected to link_mm6vbks; /admin/skus and the category filter bar removed from the SOV Builder card (neither exists in that Worker); TOKEN_CACHE removed from its KV list; CSOP recipients corrected to erateops@vectortechgroup.com + Sales@vtgus.com, both TO; Projects #4 stage list replaced with the board’s live labels; 8 Windows paths repaired where a literal \v had been eaten by escaping. Confirmed accurate: the UID stamp chain, all 6 PM subitem names, vtg-set-project-year’s label map, vtg-po-sync columns, both SOV KV IDs, and every board ID. |
| Sep 17 | v2.2 | Infrastructure | E-Rate Deals → Projects handoff is not running — Live counts make gap #7 concrete: 📁 E-Rate Deals holds 102 items while E-Rate Projects holds 1. Automation 7917669964 only fires on Status → Awarded, and nobody sets it, so the downstream board is effectively empty. Also noted: five Workers on this map (vtg-portal, vtg-sow-builder, vtg-inventory, vtg-logo-backfill, vtg-sku-catalog) have no local source folder, so there is no redeploy path for them. |
| September 14–16, 2026 | |||
| Sep 16 | v2.1 | Update | vtg-materials-log v4 — NS SO writeback live — On submit, cabling lines PATCHed onto the NS Sales Order and an Item Fulfillment created. Drop-ship SOs skip fulfillment and leave a warehouse note. Re-push to NS button on locked page for retries. NS result (IF# or lines-added confirmation) stored in KV as materials_ns_result:{item_id} and posted to monday thread. NS role perms added: Transactions → Sales Order / Fulfill Orders / Item Fulfillment (Full). |
| Sep 16 | v2.1 | Infrastructure | 621 missing NS inventory items bulk-written — vtg-ns-sku-writer.mjs wrote 621 items to NetSuite as InvtPart using template item C-101017BK (ID 23323). 96% SKU match rate achieved between vtg-sku-catalog and NS. 40 partial matches remain for review (10 need catalog SKU updates, 25 false matches correctly created, 5 need Mark's review). vtg-sku-compare.mjs and vtg-sku-partial-review.mjs used for analysis. |
| Sep 14 | v2.0 | Infrastructure | Cloudflare Workers plan upgraded to Workers Paid — $5/month. Cron limit raised from 5 (free) to 1,000 workers. All existing cron jobs now within limits. |
| Sep 14 | v2.0 | Update | vtg-ns-so-backfill v2 live — Rewritten with UID-exact matching as primary strategy: Projects #4 UID (text_mm76zvbz) → NS customer.custentity_acs_unique_entity_identifier → salesOrder.entity → tranId written to text_mm6hv20b. Fuzzy name as fallback. First sync wrote 43 SO numbers. Cron every 4h. HTML tool has Run Auto-Sync Now button, filter pills, score badges. |
| Sep 14 | v2.0 | Infrastructure | Projects #4 UID column added — text_mm76zvbz created on Projects #4 board (18176626554). backfill-project-uid.mjs ran Sep 14 2026 — name-matched to Accounts board UID (text_mm6s8adk). 6 active E-Rate projects stamped manually. Remaining blanks: commercial/non-eRate (no Account in system) and closed projects. |
| Sep 14 | v2.0 | Fix | vtg-cs-form: UID stamp on Projects #4 creation — /api/submit-pdf handler now reads Account UID (text_mm6s8adk from board_relation3 on Bid item) and writes to text_mm76zvbz on the new Projects #4 item at creation time. Going-forward fix — all new projects get UID stamped automatically. Deployed Sep 14 2026. |
| Sep 14 | v2.0 | Infrastructure | vtg-proposal-builder v4.1 live — Bid due date y-position fixed (y=540, below district/470# line). SOV PDF column: file_mm749nna. Status column: color_mm74qsfe. Deployed at vtg-proposal-builder.vectorfi-admin.workers.dev. |
| Sep 14 | v2.0 | Infrastructure | ScopeStack Template V5 fixes — Rate Adjustments section font corrected from Times New Roman to Calibri (36 occurrences). current_version.name merge field removed (was crashing generator). Blank page after Scope of Work is a ScopeStack limitation — not fixable. |
| Sep 14 | v2.0 | Infrastructure | vtg-sov-builder PDF updates — Meta bar removed from PDF pages. Summary tab header "Location" → "Bid Item". Section headers full-width. Type column: IC for most sections, BMIC for BMIC section. SOV PDF uploads to file_mm749nna on Bids #3 (was wrong column). |
| September 13, 2026 | |||
| Sep 13 | v1.9 | Infrastructure | vtg-materials-log copper SKU catalog complete & in use — 951 copper SKUs (C- prefix) loaded from Mark's inventory list; catalog now 1,031 total (+ 80 fiber F- prefix); all SKUs merged into vtg-sku-catalog KV key. Gap closed. |
| Sep 13 | v1.9 | Fix | vtg-monday-sf-sync patched — RecordTypeId hardcoded to Erate record type (012aZ00000BHkT7QAL); Cross_Sell_Opp__c set to "NO" on all records; stage logic finalized: SKIP stages (no SF upsert, fields-only update if record exists) = New Bid Folder Creation, Folder Creation, Deal Reg, Email, Bid Compilation, Bid Submittal, Bidding, Wins Archive; ACTIVE stages (full upsert incl. StageName) = Bid Building, Awaiting Results, Post-Sale, Post-Monday, Lost. Worker.js moved to VTG Flows\vtg-monday-sf-sync\. |
| Sep 13 | v1.9 | Infrastructure | Salesforce Opportunity record types confirmed — Erate: 012aZ00000BHkT7QAL, Commercial: 012fo000000XSojAAG, RFP: 012fo000000XSqLAAW, VTG RFP: 012fo000000XSrxAAG. Cross_Sell_Opp__c picklist confirmed: --None--, NO, YES. |
| September 10, 2026 | |||
| Sep 10 | v1.8 | Infrastructure | SKU Catalog architecture revised — vtg-sku-catalog is now the single master key containing all vendors merged into one JSON array. Worker reads only this key. Separate vendor keys remain in KV as backups but are not read by loadSKUs(). Fixes disappearing-catalog bug where pushes to individual vendor keys weren't appearing in the SOV Builder. |
| Sep 10 | v1.8 | Infrastructure | Ruckus catalog rebuilt from full Sep 2026 price list — 3,631 SKUs (692 wireless, 1,389 switches, 1,415 licensing, 89 transceivers, 46 accessories). All 4 Ruckus discount tiers now stored per SKU: Bidder VAR (RKS-0436), Driver VAR (RKS-0437), RSD VAR (RKS-0438), E-Rate Takeout (IDC017). Bidder VAR is the default; others selectable at bid time. Actual AP hardware units (R370, R670, R750, R770, T350, T670, T750, etc.) now in catalog with correct pricing. |
| Sep 10 | v1.8 | Infrastructure | vtg-sku-catalog total: 5,042 SKUs — Ruckus 3,631 · VTG Cabling 1,031 · Fortinet 318 · N1C 62. Juniper/Mist excluded (single-customer, not worth catalog maintenance). Vertiv and TP-Link Omada pending price lists. |
| Sep 10 | v1.8 | Infrastructure | ScopeStack eRate SOW Template V3 built — updated company branding (Vector Powered by VTG), FY2027 labor rates (Cabling $110, L1 $195, L2 $225, L3 $265, L4 Negotiated), five office locations in footer. New "Project Management — E-Rate" service (ID 471786) and blueprint (PM-ERATE, ID 6702) created in ScopeStack under eRate > Professional Services. PM blueprint applies to all installation bids; skip for equipment-only. vtg-scopestack-doc-sync template routing still hardcoded to V2 — needs update when V3 is uploaded. |
| September 8, 2026 | |||
| Sep 8 | v1.7 | UI | Slide-out detail panel — replaced bottom-of-page detail section with a slide-in drawer. Click any step card in the diagram to open the panel from the right. Close with ✕, Escape, or clicking the overlay. |
| Sep 8 | v1.6 | New Worker | vtg-sf-account-sync — syncs monday.com Accounts (#1) and Contacts (#2) to Salesforce as Account and Contact objects using Monday_Item_ID__c as external ID. Writes SF Account ID back to UID column (text_mm6s8adk) on Accounts board. Backfill ran against all 791 existing accounts. |
| Sep 8 | v1.6 | New Worker | vtg-scopestack-doc-sync — two-endpoint Worker. Endpoint 1: catches ScopeStack document_status_changed webhook, downloads .docx SOW, routes by template to Bids #3 SOW Document column (file_mm6wm4hn) or El Nova Leads. Endpoint 2: triggered by Generate SOW button (button_mm70vvrb) on Bids #3 to programmatically trigger SOW generation. First confirmed delivery: North Branch Area Schools, 470# 260005778. |
| Sep 8 | v1.6 | Infrastructure | Fortinet catalog added to SKU_CATALOG KV — 318 SKUs (54 HW, 132 UTP bundles, 132 UTP licenses) covering FortiGate FG-30G through FG-900G at MSRP. Added via vtg-sov-builder /admin/skus. |
| Sep 8 | v1.6 | Infrastructure | Live on vtg-process-map.pages.dev — process map deployed to Cloudflare Pages via GitHub (vtg-portal/vtg-process-map). Auto-redeploys within ~30 seconds of any push. URL is permanent and shareable. |
| September 4–5, 2026 | |||
| Sep 4 | v1.5 | New Tool | vsz-lldp-neighbors.py — local Python script that SSHes into Ruckus SmartZone, runs LLDP neighbor discovery across all APs in a zone, exports to timestamped CSV, optionally writes back to AP description. Added to vtg-portal as tool #23. |
| September 3, 2026 | |||
| Sep 3 | v1.4 | Process Change | Intake form redesigned — Sales Executive and ScopeStack Blueprint(s) are now entered inside the vtg-bid-intake form (after accept_470), not before. Blueprint selection in the form triggers ScopeStack proposal creation. Eliminates the pre-accept manual entry step. |
| Sep 3 | v1.4 | Bug Fix | vtg-bid-intake patched — fixed Account/Contact lookup (replaced unreliable items_by_multiple_column_values with items_page + contains_text). Fixed SOV Builder link not being written on form submit. Bond section redesigned with Surety bond read-only. Retries bumped 3→4. |
| Sep 3 | v1.4 | New Worker | vtg-tdsynnex — TD Synnex Partner API OAuth 2.0 integration. Exposes /api/lookup for live contracted pricing. Called internally by vtg-sov-builder via service binding. Falls back to SKU_CATALOG KV for non-TD Synnex items. TOKEN_CACHE KV with auto-refresh. |
| Sep 3 | v1.4 | Update | vtg-sov-builder enhanced — [corrected v2.2: the TD Synnex live pricing, LIVE badge and category filter bar described here were planned but never shipped — see the TD Synnex gap] /admin/skus catalog admin UI. Sep 10 2026: SKU catalog rebuilt — 5,042 SKUs across Ruckus (3,631), VTG Cabling (1,031), Fortinet (318), N1C (62). All 4 Ruckus discount tiers (Bidder/Driver/RSD/Takeout VAR) stored per SKU. Full AP hardware catalog now loaded. |
| Sep 3 | v1.4 | Process Change | Bids #3 column restructure — new 📊 SOV Builder column (link_mm6vbks) created; all 156 existing bids backfilled. Customer Intake Form column (link_mm591mdg) now dedicated to intake form links only. vtg-bid-intake stamps both columns on new bid creation. |
| August 25–30, 2026 | |||
| Aug 30 | v1.3 | Doc | Process map published — initial 7-tab HTML document covering E-Rate, Commercial, and E-Rate Op System tracks. Includes Flow Diagram, Written SOP, Gap Analysis, Workers, Glossary, Automations, and Dashboards tabs. |
| Aug 27 | v1.2 | Update | |
| Sep 15 2026 | vtg-ns-mcp-sync — inventory cache endpoints live — /api/inventory (location 41, feeds vtg-materials-log On Hand column) and /api/inventory/all (all locations, feeds vtg-inventory dashboard) added. INVENTORY_CACHE KV (ID: 0233a14225194cbd81a49601f448963b) shared between both consumers. Cron refreshes both keys every 15 min. NS VTG API Sync role permissions added: Lists → Items (Full), Lists → Locations (View), Reports → Inventory (View). | ||
| Sep 15 2026 | vtg-inventory dashboard live — Company-wide NS inventory dashboard at vtg-inventory.pages.dev (Cloudflare Pages, GitHub repo vtg-portal/vtg-inventory). Password protected (VTG2026, Azure AD SSO planned). All NS locations: 41 Cabling Warehouse, 42 Secondary Warehouse, 4 Grand Rapids Office. Features: search, location filter pills, sortable columns, light/dark mode toggle, CSV export. Fetches live from vtg-ns-mcp-sync /api/inventory/all. | ||
| Sep 15 2026 | vtg-materials-log v3 — NS Inventory On Hand column added to parts table; color-coded badges (green/yellow/red) from NS location 41 (Cabling Warehouse) via shared INVENTORY_CACHE KV; UID (text_mm76zvbz) and NS Sales Order # (text_mm6hv20b) added to project card; On Hand loading from KV — no direct NS API call on page load. | ||
| Aug 27 | v1.2 | New Worker | vtg-revenue-month-sync — fires on Projects #4 Timeline column change, extracts end date, writes to Revenue Month (date_mm39fh8x). Skips Closed items and cleared timelines. |
| Aug 27 | v1.2 | New Worker | vtg-msp-csop — Commercial/non-E-Rate CSOP form deployed. Bypasses Bids #3 and El Nova entirely. Creates Projects #4 item directly with task list subitems built from form fields. |
| Aug 27 | v1.2 | Infrastructure | Cabling Install Scheduler board — new monday.com board (ID 18427983069) for 10-person crew scheduling. 4 stage groups, 33 jobs pre-loaded, 2 automations (tomorrow reminder + crew assignment notification). |
| Aug 25 | v1.1 | New Worker | vtg-po-sync — syncs NetSuite PO numbers and approval status back to Projects #4. Webhook on NS SO# column change + cron every 4h. KV: PO_SYNC_KV. |
| Aug 25 | v1.1 | New Worker | vtg-ns-so-backfill v2 — ongoing sync Worker (cron every 4h) for NetSuite Sales Order numbers into Projects #4. v2 uses UID-exact matching (text_mm76zvbz → NS custentity_acs_unique_entity_identifier) as primary strategy; fuzzy name fallback. First sync wrote 43 SO numbers on Sep 14 2026. |
| Aug 25 | v1.1 | Gap Resolved | NS process documentation — vtg-ns-audit Node.js tool built. First-ever NetSuite process documentation for VTG via OAuth 2.0 M2M + SuiteQL. Generated self-contained HTML report tying NS data to each process step. |
| Prior to August 25, 2026 | |||
| Aug 13 | v1.0 | New Worker | vtg-monday-sf-sync — Bids #3 stage changes sync to Salesforce as Opportunity upserts via Monday_Item_ID__c external ID. First SF record: Shaker Heights City School District. |
| Aug 13 | v1.0 | Infrastructure | vtg-ns-mcp-sync auth live — NetSuite production OAuth 2.0 M2M auth established. Six bidirectional sync flows coded. Blocked on customer ID mapping (vtg-ns-compare) and NS service item ID. |
| Ongoing | v1.0 | New Worker | vtg-cs-form — CS Order Processing form generated and emailed to erateops@vectortechgroup.com when Bids #3 moves to Post-Sale. KV-based deduplication. monday subitem auto-created. |
| Ongoing | v1.0 | New Worker | vtg-sov-builder — SOV quoting tool for sales. Multi-tab buildings, SKU catalog, section types, per-row labor, markup overrides, jsPDF generation, upload to Bids #3 Files column. |
| Ongoing | v1.0 | New Worker | vtg-bid-intake — triggered by accept_470. Creates Bids #3 item, auto-links Account/Contact, serves intake form, handles bond creation. Core of the E-Rate lead intake flow. |
| Ongoing | v1.0 | New Worker | vtg-materials-log — cabling materials accounting for Projects #4. PM submits fiber/copper parts on stage → Installing. Auto-advances to Ready for Invoicing and fires billing notification email. |
| Ongoing | v1.0 | New Worker | vtg-account-logo — scrapes district website for logo, falls back to Clearbit, uploads to Accounts board logo column. Backfill ran against 786 existing accounts. |