All work

Steer

Principal Engineer · Jul 2026 – Present

Full-time
146 merged PRs in 9 weeks 670-file replatform, sole author
React TypeScript C# .NET RabbitMQ MongoDB SingleStore Kubernetes

Context

Steer builds the front-of-house platform for auto repair shops — booking, two-way messaging, marketing campaigns, reviews, call intelligence and reporting, unifying phones, texts and bookings for operators from single independents to multi-location groups. I joined in July 2026 as Principal Engineer, into event-driven .NET services on Kubernetes, a React frontend, and storage split across a document store, SingleStore and an analytical warehouse.

Two things have had most of my attention: the system that tells a shop which customers to call today, and the pipeline that brings their reviews into the platform.

The Challenge

A repair shop’s most valuable asset is the customer list it already has. Someone declined a brake job four months ago. Someone’s tires are due. Someone opened their digital vehicle report three times last week and never booked. Every one of those is a reason to pick up the phone, and almost no shop has the time to find them by hand.

Turning that into software means scoring a shop’s entire book of business, explaining why each customer surfaced, and handing the front desk something they can act on between walk-ins — software that runs at the counter, live, while a customer is on the phone. A release here doesn’t land in a maintenance window; it lands in the middle of someone’s shift.

The second challenge is structural. Review data is a core surface — shops live and die by their Google and Yelp ratings — and it reached the platform through a third-party intermediary, inheriting that intermediary’s ceiling on freshness, on reconciliation, and on how directly we could answer a customer’s question. Bringing it in-house turns all three from vendor constraints into engineering problems.

Approach & Architecture

The through-line across both efforts is that a change should be safe to land before anyone decides to turn it on.

Score in the warehouse, not the application. Ranking a shop’s whole customer base against weighted signals is an analytical query, not a transactional one. Doing it in the application tier means either paging through the population or approximating it, so scoring, ranking and the top-N cut all live in the warehouse — the API asks for an answer rather than assembling one.

Ship large changes dormant. The alternative to a big-bang cutover isn’t a smaller change; it’s the same change, landed inert. Registration for the new review pipeline is all-or-nothing behind an explicit opt-in production doesn’t set, making the merge and the activation two independent decisions with different evidence.

Prove the new path against the old before cutting over. Correctness on a review pipeline isn’t something you reason your way to — external data has quirks nobody documented. So rather than test in staging and hope, the new pipeline runs as a shadow lane against live work, diffed against the legacy path.

Feature-flag both ends. Backend and frontend ship behind the same flag, so a half-built capability is invisible rather than merely unreachable. On a platform whose users are mid-call, a bad release doesn’t cost a rollback — it costs a shop’s morning.

Enforce consent in the query that builds the list. Do-not-call suppresses a customer at the source of the call list rather than filtering at the edge — a filter is something a new caller can forget to apply, and a suppression isn’t.

Key Contributions

The Opportunity Hub, end to end. Sole owner of the signal-scoring system that ranks a shop’s customer base into a prioritized daily call list — the warehouse scoring, the .NET services, and the React interface the front desk uses. Each signal is a behavior worth acting on (a missed appointment, a maintenance interval coming due, a digital vehicle inspection the customer opened, a web form nobody followed up on) carrying a weight and a decay window tuned to how long it stays relevant. It’s the rare feature where one engineer holds the whole vertical, which is why the scoring model and the UI agree about what a signal means.

Talk tracks and the call guide. A ranked list is half a product; the front desk still has to know what to say. Shops write their own talk tracks with a token picker that interpolates customer and vehicle data, see the next available appointment slots inline so a call can end in a booking rather than a callback, and hide the signals that don’t fit how they operate. Every shop’s Hub differs because the shop configured it, not because anything forked.

Outcome tracking. Every work item resolves to won or lost, lost requires a reason, and the outcome timestamp is immutable once written — reporting is only worth something if the record can’t drift, so the write path enforces it rather than trusting callers. Shops can export their won and lost opportunities for their own analysis.

Review Sync v2. Sole author of the first-party review ingestion pipeline that replaces the third-party path — 670 files and roughly 109,000 lines across a hundred commits, storing into SingleStore, with six scheduled jobs, a shadow lane, and a phased rollout behind six independent flags.

Reputation escalations. I own the escalation path for reputation issues, which means I see the recurring shapes first — where review data originates, how it reconciles against the platform of record, what happens at the seams with an external provider. That vantage point is most of why I could make the architectural case for a first-party pipeline: the design followed the operational evidence rather than preceding it.

Campaign reporting and consent. Worked on the accuracy of email campaign analytics — opens, clicks, and review attribution — so the numbers operators plan against reflect what happened. Separately, consolidated the platform’s opted-out states behind a single check on the send path, so opt-out is enforced in one place with one meaning rather than reconstructed by each caller.

Technical Deep Dives

Ranking a population, not a page. “Show me my top opportunities” is a question about a shop’s entire customer base, and the tempting implementation — take the top N from the page the API already returned — produces an answer that looks right and is quietly wrong. The customer ranked first overall can sit on page four and never surface, with nothing anywhere raising an error. Getting it right meant pushing both the ordering and the limit into the warehouse so the cut comes from the whole filtered population before anything is paged — which in turn meant the filter set had to be expressible there rather than applied in the service layer afterward. Ranking and pagination are not composable in either order: rank over everything, then page, or you have silently changed the question.

Landing a 670-file replacement inert. Merging a change that size into a platform serving live shops is where replatforms go wrong, so the goal was to make the merge a non-event. The new infrastructure registers all-or-nothing behind a single predicate, and the shape of that predicate is the load-bearing detail. A gate built from infrastructure that already exists for other reasons — a connection string, an environment name, the presence of a config section — isn’t a gate at all, because something else in the cluster can satisfy it without knowing the feature exists. Shared configuration is inherited widely, by design. So the opt-in is a dedicated key that means one thing and is set by one decision, and dormancy is asserted by tests exercising the real registration path rather than a mock — a gate you haven’t proven closed is a gate you’re assuming. On a production deploy the feature adds exactly one dependency-injection descriptor and nothing else runs.

Impact

Nine weeks in: 146 merged pull requests across six repositories. The Opportunity Hub has gone from a signal list to a configurable calling workflow — per-shop signal visibility, shop-authored talk tracks, inline appointment availability, saved views, outcome tracking and export — every piece behind its own flag. Review Sync v2 merged at the start of September and is moving through phased rollout, the shadow lane proving it correct against live traffic before any shop is cut over.

Reflections

Reversibility beats correctness-on-the-first-try. A change that is right but irreversible is a bet; a change that is reversible can be wrong cheaply and fixed on a Tuesday. Almost everything I’ve built here — the dormant registration, the shadow lane, the flags on both ends — is an investment in being able to undo things, and it has been worth more than any amount of additional care before the merge.

Polyglot persistence asks for provenance discipline in return. A document store, a fast relational store and a warehouse each earn their place on a platform doing transactional, operational and analytical work at once. What it costs is the ability to answer a question offhand: every claim about production behavior has a correct place to be answered from, and naming that place first is what separates a real answer from a plausible one.

Own the escalations if you want to earn the architecture. The case for replacing the review pipeline wasn’t something I could have made from a design document two months in — it came from being the person the hard tickets route to, long enough to tell incidental failures from structural ones. Support work gets framed as a tax on senior engineers. It’s closer to the cheapest research available.