Squashing 35+ Bugs in One Epic Audit Session: SnowTrack & LawnTrack Fixes
Just wrapped up one of those marathon debugging sessions that reminds me why I love (and sometimes hate) maintaining two SaaS apps that share a backend. Today was all about SnowTrack and LawnTrack - my snow removal and lawn care management platforms.
The Hamburger Menu That Wouldn't Behave
Started with what seemed like simple CSS issues but turned into a classic case of conflicting styles. The hamburger menu was showing up on desktop (whoops) and rendering as a single thick line instead of three neat bars. Turns out global CSS with !important declarations were wreaking havoc - the display: flex !important was overriding my page-specific display: none, and a global min-height: 44px !important was stretching the flex container and spreading those three lines apart like they were social distancing.
Fixed it by ditching the conflicting !important properties and switching to padding-based touch targets. Sometimes the solution is just removing code, not adding more.
The Expenses Page That Showed Everything
The expenses page was overwhelming users by defaulting to "all time" view. Nobody wants to see every expense from the beginning of time when they just want to check this month's numbers. Made it default to "This Month" and added an "Show Archived" toggle for expenses from routes completed over 30 days ago.
Here's where it gets interesting - instead of adding a new database column for archived status, I'm calculating it at query time with a JOIN. No schema migration needed, and if a route's status changes later, the archived status updates automatically.
The Critical Date Bug That Made Me Question Everything
This one was a doozy. The expense summary was mysteriously excluding March expenses, and I spent way too long staring at the code before realizing the issue: my getCentralDateRange function was returning UTC Date objects with hour offsets (like 2026-03-01T06:00:00Z). PostgreSQL's DATE column comparison was excluding March expenses because midnight UTC was less than 6 AM UTC.
The fix? Stop being fancy with Date objects and just use YYYY-MM-DD strings with ::date casts. Sometimes simple is better.
Security Audit: The Scary Stuff
Found three critical tenant isolation issues that could have let users see other companies' data. Not great! Fixed missing company_id filters on photo counts, route addons, and service addons queries. Also patched some time-of-check-time-of-use race conditions on DELETE operations.
This is the kind of stuff that keeps me up at night, so I'm glad I caught it during a routine audit rather than in production.
The Great Code Quality Cleanup
Decided to go full Marie Kondo on the codebase and tackled 30 different code quality issues:
High Priority Wins:
- Replaced all those janky
alert()calls with proper state-based error messages - Fixed N+1 queries with batch operations and transactions
- Made the admin panel actually usable on mobile with responsive card layouts
- Added proper error states throughout the UI
The Little Things That Matter:
- Swapped hardcoded colors for CSS variables (future me will thank present me)
- Wrapped localStorage calls in try/catch blocks
- Added form labels for better accessibility
- Parallelized Dashboard API calls with Promise.all
- Added a 375px breakpoint for those tiny phones
What I Skipped (And Why)
Some things just weren't worth the risk today:
- useReducer refactor for Settings.js (40+ useState calls) and StormMode.js (60+ useState calls) - too invasive
- DST timezone fixes for financial summaries - too risky to touch right now
- AbortController cleanup - working fine as-is
Mobile-First Admin Panel
The admin panel was basically unusable on mobile, so I implemented a dual-layout system: tables for desktop (768px+) and stacked cards for mobile. Now I can actually manage companies from my phone without squinting at microscopic text.
The Aftermath
Five commits later, both SnowTrack and LawnTrack are significantly more stable and user-friendly. The shared backend architecture continues to pay dividends - fix something once, and both apps benefit.
Next up: considering a consolidated /api/dashboard endpoint to reduce API calls, and maybe finally tackling those useState-heavy components with useReducer. But for now, I'm calling this a win.
Sometimes the best coding sessions are the ones where you delete more code than you add. Today was one of those days.