All releases
May 2026 Published May 2026

May 2026 Updates

Dashboard demo mode, Neo4j history projections for reports, invoiced revenue column, inbound/outbound call icons, and more.

Newsletter status: In progress. See README.md for conversion guide.


v2605.27.0 — May 27, 2026

MRs: !2096, !2095, !2094, !2093, !2082, !2079, !2070, !2016

Highlights

New Opportunity locations step: minimal view, auto-scroll, and location validation (!2016) The New Opportunity flow has been refactored to separate customer and location validation, auto-scroll to the location details wizard after address selection, auto-focus the address input, and enforce mandatory field validation. A minimal locations view provides a streamlined experience with clear button support on dropdowns.

AI contact time calculation for outbound calls (!2095, closes #6023) The scheduler now computes reasonable contact-time windows for each customer based on business hours and time zone, preventing too-early or too-late calls. Configurable contact time windows and resolution step settings are added to zone config.

Custom column names for dynamic reports (!2070) Users can now define custom column names in dynamic reports, replacing default headers with user-friendly labels. Custom names are also applied to CSV exports for easier sharing.

NSC calculator v2605.18.0 with elevator type + floor efficiency modifiers (!2082) The new calculator differentiates elevator types (bookable, freight, not-bookable) with per-type-per-floor efficiency modifiers, replacing the flat elevator_any: 0.9 modifier. “Ask for Discount” dynamic pricing is also supported.

Features

  • Separate customer and location validation in New Opportunity steps (!2016)
  • Auto-scroll to location details wizard after address selection (!2016)
  • Auto-focus address input in minimal locations view (!2016)
  • Clear button on customer detail dropdowns and job origin field (!2016)
  • Configurable mandatory Access field for job locations (!2016)
  • Show next step title on navigation button (!2016)
  • Group customer name and company fields; relocate billing address fields (!2016)
  • Persist rows per page setting for dynamic reports (!2079)
  • Custom column names for dynamic reports with CSV export support (!2070)
  • AI contact time calculation with configurable contact windows and resolution steps (!2095, closes #6023)
  • NSC calculator v2605.18.0 with elevator type and floor-based efficiency modifiers (!2082)

Fixes

  • Fixed blank screen when opening job from email link while deauthenticated (!2096, closes #6138)
  • Fixed events not retrieved in booking modal (!2094)

Other

  • Removed dynamic reports fan-out trap: eliminated 300+ lines of duplicated column knowledge from previewReport.ts (!2093)
  • Consolidated preview report types into dedicated file (!2093)

v2605.25.0 — May 25, 2026

MRs: !2092, !2091, !2090, !2089, !2088, !2087, !2086, !2085, !2084, !2083, !2078

Highlights

Ops Readiness dashboard with collapsible detail columns (!2090, !2084, closes #6267) The new Ops Readiness tab shows billed vs. calculated columns for crew, hours, and weight with inline collapsible detail rows (like Google Sheets grouped rows). Totals, mean row, and diff values display in HH:mm format. Charge and location fan-out deduplication ensures accurate totals per event/job.

Sales Leaderboard dashboard with podium, metric switching, and shared-in filter (!2078, closes #6267) A top-3 podium sorted by Booked $$$, 7 metric views (revenue, booked, estimated, net conversion, leads, cancellations, jobs), shared-in event filter, unassigned agent drill-down, hover column highlighting, and period search. Client-side aggregation correctly neutralises shared-in charges.

System Revenue dashboard with shared/internal revenue, drill-down, and export (!2078, closes #6267) Dashboard tab showing Internal Revenue, Net Shared Revenue, and Shared Out Revenue per franchise with drill-down navigation, CSV/Sheets export, and copy. Currency symbols render server-side; near-zero totals round to zero. Shared-out revenue correctly attributed to receiving franchises.

Revenue dashboard Expected Revenue now matches System Revenue (!2092) discountedSubTotal now includes shared-in charges by pre-computing values before shared-in neutralisation. Dashboard Expected Revenue = realized + scheduled + shared. Net Shared Revenue = sharedRevenue − sharedOutRevenue. Snapshot tests guard query shape.

Performance

  • Created index on CalendarEvent.status_booked for faster booked event lookups (!2088)
  • Optimized job filtering for last scheduled event period (!2085)

Features

  • Ops Readiness dashboard tab with billed columns, collapsible detail rows, charge/location dedup, and weight display (!2090, !2084)
  • Sales Leaderboard dashboard with podium, 7 metric views, sorted-column highlight, period search, cancellation count, and shared-in filter (!2078)
  • System Revenue dashboard with Internal/Shared/Shared Out Revenue, franchise drill-down, and data export (!2078)
  • Revenue dashboard: discountedSubTotal includes shared-in charges; Net Shared Revenue display; sharedOutRevenue column (!2092)
  • Collapsible detail columns with expand/contract arrows in ops readiness table (!2090)
  • Weight display shows None for zero, asterisk for calculator-estimated weights with tooltip (!2090)
  • Use actual inventory weight from jobs.inventory field (!2090)
  • Crew columns outside collapsible section; diff inline under total columns (!2090)
  • Pay button added to booking modal (!2089)
  • Shared events filter dropdown and aligned accordion headers (!2087 parts)
  • Use artifact signedByCustomer for estimate signed column (!2087 parts)
  • Franchise drill-down linking from dynamic reports (!2087 parts, !2077 parts)
  • Split Labor value into flat fee and bonus potential in OTR Ops (!2077)
  • FP Labor Information moved to OTR Ops section (!2073)
  • Calendar remarks: UI to set and display remarks on schedule, booking modal, and job overview (!2086)
  • PandaDoc document.completed handling fix (!2091, closes #6266)
  • Single-click job code opens details panel, double-click opens in new tab (!2084 parts)
  • Redirect /job/:id to jobs v4 overview page (!2084 parts)
  • Dashboard auto-reload, mobile podium layout, hover highlight, dark mode (!2090 mobile parts)
  • Working refresh button on all dashboard tabs with mobile layout fixes (!2084 parts)
  • Mobile header padding fix for dashboard shell (!2090 shell fix)
  • Demo mode clears sales leaderboard and system revenue data (!2078 demo parts)
  • Enforce single zone sharing and franchise validation for jobs and events (!2074, closes #6247)

Fixes

  • Fixed discountedSubTotal excluding shared-in charges in revenue dashboard — pre-computed before neutralisation (!2092)
  • Fixed Net Shared Revenue display and sharedOutRevenue 3-path UNION query (!2092)
  • Fixed ROUND(SUM) revenue in RETURN — events with same amount were merged (!2092)
  • Fixed Expected Revenue to compute as realized + scheduled + shared (!2092)
  • Fixed shared-out not appearing in Scheduled Revenue display (!2092 follow-up)
  • Fixed Booked $$$ source alignment and Estimated $$$ showing zeros in leaderboard (!2090 follow-up)
  • Fixed mobile dashboard header padding (!2090 shell fix)
  • Fixed sales leaderboard Booked/Estimated counts and dedup groupBy:job queries (!2078 follow-up)
  • Fixed eslint max-len and duplicate import errors in sales leaderboard (!2078 follow-up)
  • Fixed numeric table cells not converted to strings for app-report-data (!2078 follow-up)
  • Fixed column indexing to use server headers and positional keys (!2078 follow-up)
  • Fixed sales leaderboard sort for non-Revenue/Booked metrics (!2078 follow-up)
  • Fixed =HYPERLINK sales agent name parsing (!2078 follow-up)
  • Fixed charge and location fan-out dedup for groupBy event/job in data mode (!2090)
  • Fixed intermediate rounding on diff values for correct h:mm display (!2090)
  • Fixed refresh button not showing when lastReload is empty (!2084 parts)
  • Fixed hide accordion during loading to prevent stale content (!2084 parts)
  • Fixed aria-labels on icons/checkboxes and semantic button for refresh icon (!2084 parts)
  • Fixed shouldAggregateEventForJob firing when event-agg columns not requested (!2090 backend refactor)
  • Fixed restore sharedStatus in withVariables during event/job neutralisation (!2090 backend refactor)
  • Fixed narrow resolveSharedStatus to revenue columns only (!2090 backend refactor)
  • Fixed pre-compute averageDiscountedSubTotalPerEvent/Job in charge aggregation block (!2090 backend refactor)
  • Fixed zone selector dropdown filtering and shared zones event handler context (!2074)
  • Fixed cross-franchise validation for shared zones (!2074)
  • Fixed GraphQL types alignment with single zone sharing (!2074)
  • Fixed PandaDoc document.completed handling (!2091, closes #6266)
  • Fixed unrecoverable service worker state on iOS (!2083)
  • Fixed remove embedded URL from franchise (!2087)

Other

  • Refactored dynamicReports: extracted utils, formatters, and types from previewReport.ts (!2090)
  • Refactored previewReport.spec.ts: excluded dedicated-spec reports from snapshot loop (!2090)
  • Refactored: gate charge aggregation block on job-dedup or shared-revenue need (!2090)
  • Refactored: split groupBy-job deduplication tests into own spec (!2090)
  • Split SL state into DashboardSalesLeaderboardStore; added DashboardShellComponent (!2078)
  • Dashboard snapshot tests for ops readiness, sales leaderboard, and system revenue (!2078, !2090)
  • Updated DASHBOARD-GUIDE with refresh pattern and reloadKey convention (!2084)
  • Project management wiki tooling, templates, and opencode commands (!internal)
  • Status-email skill for biweekly leadership updates (!internal)

v2605.13.0 — May 13, 2026

MRs: !2075, !2071, !2068, !2067, !2065, !2064, !2060, !2058, !2050

Highlights

AI Activations & Billing dashboards (!de30c30c0, !fc5a2dffe, !a6224e4bf, !14fa799e7) Two new dashboard tabs: Activations tracks AI usage metrics (total tokens, cost per activation, thread modes) across franchises, and Billing provides per-location billing config with inline editing, overage calculations, and total revenue — all with searchable, sortable, paginated tables.

Auto-assign roles on event booking and rescheduling (!2050, closes #6218) When a moving event is booked or rescheduled, the system now auto-assigns the configured roles (e.g., crew, dispatch) to the event based on zone-level defaults. The default event start time is now configurable per zone.

Enhanced location details wizard with context-aware options (!2058) The location wizard now shows context-appropriate building types, size options, and access questions. Townhouse and Duplex ask for bedrooms; Storage Units skips bedroom/sq ft; “Other” offers load-based size choices. A dock-addition config can skip the “add dock” question per zone (!2067).

BestMoveEver calculator scoped to new opportunity steps (!2060, closes #6185) Calculator elements now display on the correct opportunity step instead of all at once. The customer step includes the BestMoveEver question, and the calculator loads conditionally based on the zone’s configured URL.

Performance

  • Parallelized billing config fetches for all franchises (!5ede7445b)
  • Renamed OpenAI metadata to ai_* and added cost tracking to all AI call sites for accurate activation reporting (!a46ee53d3, !923d3050b)
  • Optimized migration 38 with thread_mode index and progress logging (!f4b59035d)
  • Removed area column and dropped area OPTIONAL MATCH for flatter billing table (!22d00ab4d)

Features

  • Configurable default event start time per zone (!2075, closes #6218)
  • Marketing tokens for intake forms (!2064, !38c36cf22)
  • Zone-aware calculator URL auto-set on area change (!4be3cfe17, !04a789e76)
  • Dashboard permissions for Activations tab (!f4f14fb1e)
  • Inbound Call mode in AI conversations (!a6224e4bf)
  • Comment thread performance indexes via migration 39 (!39)
  • Rename OpenAI metadata fields to ai_* via migration 38 (!38)

Fixes

  • Fixed Book Job not prepopulating customer info from the customer page (!2068, closes #6192)
  • Fixed erroneous booked event projection in lockTime causing duplicate/stale events (!2065, !87cb1acce)
  • Fixed incompatible Angular dependencies causing prebundling errors (!2071)
  • Fixed comment sort order: conversations now sort by createdAt DESC, expanded threads by createdAt ASC (!da7fc1a7c, !e6a3395ad)
  • Fixed conversation columns missing mode, threadId, and createdAt in dashboard (!2cefac647)
  • Fixed HTML-formatted job/customer links not rendering in dashboard (!db5e262b5)
  • Fixed sort:null causing AJV validation errors in dashboard requests (!07534b382, !05489de52)
  • Fixed rowExpandable PrimeNG v17 compatibility — replaced with expandedRowKeys (!80d676e9e, !18d185a06)
  • Fixed auto-assign roles effect not dispatching success/error actions (!fd1d4f547)
  • Fixed billing dashboard overage calculations and franchise ancestor filtering (!5a38ddfd4, !084b7fc6f)
  • Fixed NOT IN Cypher syntax for Neo4j compatibility (!18800caaa, !812264a7a)

Other

  • Validation schema and input validation for AI functions (!943b646f0, !a970693f6)
  • Extracted activation report logic into separate module (!73dec0775)
  • CodeRabbit review fixes across activations and billing dashboards (!8c5d58980, !8bedec773, !16b703792)

v2605.06.1 — May 6, 2026

MRs: !2062, !2059, !2054, !2051, !2043

Highlights

Exact email and phone search now bypasses fulltext (!2051, closes #6083, closes #6084) Full email addresses like johnedrinkwater@gmail.com were being treated as broad fulltext queries, dominated by common tokens like “gmail.com” and causing slowdowns. Exact email and phone lookups now use direct match instead, making contact searches deterministic and fast.

Street View maps show the correct location (!2054, closes #6046) The job map component has been switched to use the Google Street View Static API, eliminating cases where indoor views were shown instead of the correct outdoor street view for the address.

Charge reordering now persists correctly (!2043, closes #6100) Reordering charges and clicking save no longer silently drops the new order. The work orders reducer has been fixed to properly track and persist charge ordering changes.

Performance

  • Exact email and phone lookups bypass fulltext search, eliminating slow queries dominated by common tokens like gmail.com (!2051)

Features

  • Added Accountant role scoped to the Turpin franchise with appropriate permissions (!2059, closes #6182)

Fixes

  • Fixed email rules with toSpecificEmails not validating addresses before sending, causing silent failures for malformed recipients (!2062)
  • Fixed Street View map displaying indoor photos instead of the correct outdoor view for an address (!2054, closes #6046)
  • Fixed charge reordering not persisting when saving (!2043, closes #6100)

v2605.06.0 — May 6, 2026

MRs: !2061, !2057, !2056, !2055, !2053, !2052, !2049, !2048, !2047, !2046, !2045, !2044, !2042, !2041, !2039, !2038, !2037, !2035, !2034, !2033, !2032, !2031

Highlights

Dashboard Demo Mode (!2033)

You can now toggle Demo Mode from the user profile menu to view the dashboard with curated fixture data. This is useful for training, presentations, and screenshots without exposing real customer information. Demo data responds to period, currency, and filter controls just like live data.

Invoiced Revenue column in Dynamic Reports (!2031, closes #6160)

A new “Invoiced Revenue” column is available in dynamic reports, giving visibility into finalized invoice amounts alongside realized and scheduled revenue. Documentation for the requirement and calculation logic has been added.

Neo4j history projections for reports (!2045, !2245ab8c0ad)

Reports now use Neo4j history projections instead of live Elasticsearch queries. This improves report query performance and decouples reporting from the main history feed. A resumable backfill CLI has been added to populate projections from ES into Neo4j with progress tracking and resume support.

Distinct icons for inbound and outbound calls (!2039)

The call log now shows different icons for inbound versus outbound calls, making it easy to scan the timeline and identify call direction at a glance.

Performance

  • Reports now read from Neo4j history projections instead of live ES queries, reducing load on Elasticsearch and improving report response times (!2045)
  • Added index on openphoneCallId to prevent delayed processing of call events (!2049)
  • CallRail precall webhook early exit when CallRail integration is disabled (!2030)

Features

  • Dashboard demo mode with curated fixture data that responds to period, currency, and filter controls (!2033)
  • Invoiced revenue column in dynamic reports (!2031, closes #6160)
  • Job start dwelling type available as a group-by option in dynamic reports (!2032)
  • Distinct icons for inbound and outbound calls in the timeline (!2039)
  • Default-long-no-time intake variant for long-form intake without time selection (!2061)
  • Sharing events are now recorded in job history (!2046)
  • Job watchers update in the Business page UI after switching zones (!2047)
  • Improved Quo webhook event handling: resolve call participants for any event order, add parent comments for transcripts, summaries, and recordings (!2041)
  • Email rules can now target a specific email address instead of all job crew and customer (!e883d6d035)
  • setStageEstimateAt now set consistently for jobs entering the estimate stage (!4825e4dc04)

Fixes

  • Fixed QuickBooks export failures caused by missing configuration, undefined item maps, and disabled integration checks (!2056, !2055, !2053)
  • Fixed auth crash and white screen on deauthentication — deferred userId assignment until after refresh token check (!2048)
  • Fixed CalendarEvent history chunking for large related sets (!2052)
  • Fixed “Go to Job” navigation crash when data is invalid (!2038)
  • Fixed total price to customer calculation missing additionalChargePrice (!2037, closes #6149)
  • Fixed adding a custom charge erasing unsaved selected regular charges (!2042)
  • Fixed stale zone responses overwriting the active zone after a zone switch (!2035)
  • Fixed customer billingAddress undefined crash on overview page (!2034)
  • Fixed pipeline row revenues not summing to group total — rows now display “None” as attention placeholder to prevent double-counting (!de76cf662f, !4b176519ca)
  • Fixed demo mode fixtures to respond correctly to period, currency, and filter controls (!aac0421f00)
  • Fixed race condition in Quo webhook event handling — added Redis lock to prevent duplicate parent-level comments (!2044)
  • Fixed role guard and ref-count loading flag issues in dashboard demo mode (!df9aa7c1e6)
  • Fixed frontend.demo-mode incorrectly included in OPERATIONS_PERMISSIONS (!ebed4a1e9f)
  • Fixed guard against undefined currentZone in menu item template (!a1fa99beed)
  • Fixed strict form validation for saving only on new opportunity v4 (!f8e8fa012e)
  • Fixed prompt to discard invalid new opportunity data on job page navigation (!a1d635ecc4)
  • Fixed “OTR Fees” typo in dashboard (!2057, closes #6160)
  • Fixed invoice lifecycle event history preservation (!7fe3b59ee1)

Other

  • Resumable Neo4j backfill CLI for report history projections, replacing ES-based migration 43 (!50a2d6a523, !e980d61349)
  • CodeRabbit review fixes: lock projections, stage timestamps, report queries, and backfill robustness (!e980d61349)
  • Release skill updated to include intake/mr-cli version bumps and auto-publish (!719190b79c, !fde983a1db)
  • Invoice revenue requirement documentation added (!b22228b100, !26c6cb4bca, !da04e5858d)