Skip to Content

Release Notes

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

Releases ship to production automatically after PRs merge to main. The version number bumps with each significant batch of changes.

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