Skip to Content

Release Notes

What’s new, fixed, and changed in LawnLedger. Versions follow semantic versioning (major.minor.patch).

Improvements ship continuously — fixes and features go live as they’re finished, not on a release date. This page records the notable batches. A version number marks a milestone worth writing up, not every deploy.

v4.0.0 — 2026-06-09

A large release — roughly a month of work spanning a backend re-architecture, a security and multi-tenancy hardening pass, and several flagship feature epics. No breaking changes to the { data } API envelope or the auth model; all data remains tenant-scoped.

New

Reporting & finance

  • Reports Suite — a redesigned /reports hub with KPI snapshots and sparklines, a flagship Profit & Loss report with three layouts (Statement / Dashboard / Narrative) and period comparison, a drill-down drawer behind any figure, a custom report builder, and a scheduled-reports manager (recurring PDF/CSV email). Charts render from dependency-free SVG primitives.
  • A/R Reconciliation — the Payments page is now an accounts-receivable reconciliation workspace with totals, filters, sort, and CSV export.
  • Purchase Orders — a full PO module (model, RLS, service/routes, Finance page) with “Build draft POs” wired into the new Service Catalog Almanac seasonal planner, plus a v2 catalog (accordion table, vendor SKU linking, photo upload).
  • Billing Studio/estimates/new and /invoices/new rebuilt as a full-viewport composer with a high-fidelity live preview, a lossless Estimate ⇄ Invoice toggle, editable two-line line items, per-line and whole-document discounts/deposits, and a Review & Send drawer.

QuickBooks

  • Sync outbox — QuickBooks sync moved onto a durable outbox with a drain worker, retiring inline auto-sync. Adds per-record sync-status badges across Invoices, Customers, Estimates, Services, and Expenses, a sync-health roll-up card, a Reconnect CTA for expired connections, CDC reconciliation, and proactive single-flight token refresh.

Security & access

  • Two-factor authentication — org-enforced TOTP MFA with a post-login challenge gate.
  • Session & device management — active-session list, new-device sign-in email alerts, and an org-configurable idle-logout timeout that revokes the server session.
  • Role-based access control — a 95-permission catalog across 27 categories, enforced on backend financial/catalog/sub-resource endpoints and mirrored in the UI (greyed nav and lock cards on restricted screens).
  • Row-Level Security — PostgreSQL RLS rolled out across tenant, portal, and public endpoints via a system-context mechanism.
  • Multi-party contracts — a DocuSign-style prepare-and-send editor, per-recipient routing and reminders, per-recipient identity verification (email step-up), and multi-signature rendering on every PDF preset.
  • Link & password hardening — payment and contract links now expire; breached-password (HIBP) check and reset-strength parity on passwords.

Operations

  • Territories — a ZIP-based territory model with auto-assignment, wired across Locations and Settings.
  • Crew — Crew Analytics V2 (leaderboard, on-time, period-aware drill-in), clock-on-behalf-of for tracked-only employees, and printable bilingual crew-onboarding guides.
  • Redesigns — Dispatch (full-bleed map + exception bar), Winter Routes (storm mode), Locations (facets, PM portfolio, compliance docs, heatmap), Customers (KPI list + V1/V2 detail), and Settings (a 6-group information architecture with a discovery-first landing).
  • Bulk operations — CSV bulk-update for customers/properties/services/equipment, bulk import on entity list pages, and bulk job reschedule from the jobs-list multiselect; server-side sorting for the core list pages.

Integrations

  • Zapier — a managed Zapier integration with API-key authentication, a connect/disconnect settings panel, and a webhook surface for outgoing event subscriptions.

Mobile (crew app 1.1.0)

  • A real-time job-costing card (margin, revenue, cost breakdown) and a Today route map (Leaflet/OpenStreetMap via WebView), offline clock-in/out with exactly-once replay, GPS-trail reliability fixes, and complete es-MX localization.

Notifications

  • A block-based transactional-email system with an admin editor and live preview, customer notification preferences with a working unsubscribe link, a SendGrid event webhook, and deep-links from the bell and Notification Center straight to the underlying record.

Changed

  • Backend service layer — ~50 route domains refactored into a services/ layer (thin route adapters over typed-error services) with a matching unit-test suite; backend coverage is now ~4,800 tests.
  • Sequential, human-readable ID numbers added across core entities.
  • BusinessSettings money fields migrated from Float to Decimal.
  • White-label and custom brand-color customization removed in favor of a consistent powered-by footer (brand color remains an ungated org setting).
  • Skeleton loaders expanded across detail, list, dashboard, and map pages.

Fixed

  • Payments & billing — Stripe payments recorded in serializable transactions (no double-record), invoice settlement computed on principal so tips no longer inflate paid status, refunds write a canonical PARTIAL status, idempotency keys forwarded to Stripe, and subscription/feature-gate repairs.
  • Email & calendar — Gmail/Outlook OAuth callback repair, rotated-refresh-token persistence, auto-disable of revoked connections, and SendGrid click-tracking disabled on transactional links.
  • Numerous mobile, accessibility (44px touch targets, semantic headings, keyboard operability), and rendering fixes; full es-MX translation parity with a CI guard.

Security

  • Production-readiness and security-audit remediations across several rounds (estimate-token leak, crew-tracking authorization, CSV-injection, stored-XSS and cross-org foreign-key paths, contract signing-token leak).
  • Circuit breakers and timeouts on Stripe / SendGrid / Twilio / QuickBooks / Storage / Redis, with Sentry alerting on breaker-open.
  • A durable webhook queue with exponential-backoff retry and a dead-letter queue; Stripe and Twilio webhook signature verification.
  • Sentry error tracking wired across the backend with secret scrubbing.

Infrastructure

  • CI/CD: a diff-gated per-side pipeline, 3-way sharded E2E gated to touched sides and skipped on push-to-main, a Lighthouse budget on /login, diff-aware Husky hooks, and a pre-push authenticated smoke. Backend deploys gate on prisma migrate deploy before the traffic cutover.

v3.2.0 — 2026-05-10

A focused day of production-audit followups, render polish, and data-integrity work. No breaking changes.

New

  • Customer + property entity decode helpers (customerName, decodeText) applied across all 18 PDF preset renderers — fixes “null” appearing on entity-customer PDFs and & showing literally in property labels.
  • One-shot DB backfill script (backend/scripts/backfill-html-entities.ts) to clean up any existing & literals in plaintext fields. Idempotent, dry-run by default.
  • skipAuthRedirect option on the API client — for soft auth checks like the token-based portal page that shouldn’t bounce visitors to /login when they aren’t signed in.
  • Decoupled estimate notes/terms parity queued for next release — see handoff for details.

Fixed

  • Dashboard customer count no longer includes soft-deleted records.
  • Customer GET/PATCH/DELETE by-id no longer returns soft-deleted records.
  • Portal user data no longer mirrored into localStorage — removes an XSS exposure surface and avoids a stale auth signal after session expiry.
  • TeamAccessSettings v2 tabs now lazy-load — drops a 604 KB chunk from the initial Settings load.
  • Webhook fan-out failures were silently swallowed; now logged with full context.
  • Payment recording and refund flows now use Serializable transaction isolation — eliminates phantom-read race conditions that could over-pay or over-refund.
  • Dashboard query errors now capture to Sentry before swallowing — graceful “no data” UI preserved but prod outages are visible.
  • Schermerhorn & Co. in form pickers no longer renders as Schermerhorn & Co.decodeEntities applied at every customer/property display site.
  • Property picker label no longer doubles when the operator typed the address into the property name (e.g. "1618 Sheridan Rd Condo" doesn’t show " - 1618 Sheridan Rd" appended).
  • sanitizePlainText now decodes safe HTML entities after sanitize-html runs, so new writes don’t leave & literals in the DB.

Changed

  • Contract form styles seeder no longer creates the 6 default visual presets for CONTRACT-type — contracts inherit the INVOICE default style automatically. New orgs see an empty “Contract form styles” tab; operators who want contract-specific chrome can create one explicitly.
  • Login error capture: bare catch {} replaced with Sentry.captureException so network errors, CORS issues, and Better Auth client throws now report.
  • Geocoding (/lib/geocoding.ts) returns friendly messages on Nominatim 429 / 5xx instead of crashing JSON.parse on the HTML error page.
  • Customer substring search raised cap from 500 → 2000 rows with a truncated: true flag surfaced when older customers may be missing from results.

Security

  • Middleware ordering in backend/src/index.ts fixed so rateLimit("api") runs before autoSanitizeMiddleware.
  • Encryption key validation deferred to first use (no eager startup crash on malformed keys).
  • ESLint rule added: raw fetch is now banned in webapp/src/pages/** and webapp/src/components/**. Only @/lib/api can call the backend, with one legitimate eslint-disable for an in-memory data: URL conversion.

v3.1.0 — 2026-05-09

Twilio compliance, invitation flows, and audit hardening.

New

  • SMS-AUTO invitation delivery with Twilio compliance prefix (From LawnLedger:), STOP/HELP/START keyword handling on inbound webhooks, and SmsOptOut model.
  • Per-org invitation rate limits: 10/hour and 50/day, sliding-window counters.
  • Username plugin (Better Auth v1.5.5) added — User.username and displayUsername fields, login-by-username flow.

Fixed

  • Customer detail page no longer doubles entity names (“Chicagoland Community Management Chicagoland Community Management” → “Chicagoland Community Management”).
  • Sidebar icons no longer clipped on collapsed sidebar — three sidebars (App, Platform, Notion) all patched.
  • Bulk import path hardened: chunked transactions, real error messages surfaced, numeric Excel cells coerced to strings before .trim().
  • Property-import emailHash lookup — customers were no longer “not found” when emails contained encrypted PII.

Changed

  • First name mandatory, last name optional on customer schema — better fit for entity customers (PMs, businesses, associations).
  • Email mandatory, phone optional — matched the brother’s QuickBooks data shape.

v3.0.0 — 2026-03-18

Major release: PDF attachments on emails, portal authentication overhaul, equipment status tracking, crew schedule view, responsive dialogs, circuit-breaker pattern on external API calls, invoice property selector.

Older

See the GitHub Releases page  for the full version history.

Last updated on