The Month We Shipped the Product
January produced over 300 commits. The matching engine, location-aware search, onboarding flows, notification system, media handling, and API layer all shipped within weeks of each other. By the end of the month, KinTrades had every system a hiring platform actually needs.
That kind of velocity in a single month is what people ask me about most. The honest answer is in a separate post on small-team velocity. The short version: the infrastructure from December made it possible.
Matching Engine
The matching engine is the core of KinTrades. It evaluates multiple factors to score how well a worker fits a job and how well a job fits a worker. The algorithm considers trade-specific, location-based, and availability-related factors to produce a relevance score that powers search results, job recommendations, and employer discovery.
The matching system is tunable by design — factor weights adjust based on what we learn from successful hires without changing the underlying code. The algorithm improves from real-world outcomes over time. That tunability matters because the assumptions you start with are never quite right; usage data tells you which factors actually predict good matches.
Location-Aware Search
Trades work is local. A 90-minute commute that's normal for office work is a dealbreaker for a job site. Search and matching are built around geographic proximity, with radius filtering and distance-sorted results.
A geocoding layer converts user-provided addresses into coordinates for distance calculations, with caching to avoid redundant lookups. Workers are geocoded on registration so they're immediately discoverable by location. The cached coordinates also make filter performance instant — distance calculations happen against pre-computed values, not against an external service on every query.
API Architecture
Mid-January we migrated the API layer. The original approach had performance and developer-experience issues that were going to compound. We moved to a single server process with consistent middleware, route-level authentication, and a local development workflow that didn't require cloud credentials for basic testing.
The migration preserved every existing endpoint and added support for role-based API access — different responses for workers, employers, and platform administrators from the same endpoints. The migration itself was the kind of work that's easy to defer and expensive to skip. We did it while the codebase was small enough that the migration took days, not weeks.
Media Handling
Workers upload photos and videos of their work. The platform handles storage, access control, and client-side optimization. Uploaded media lives in cloud blob storage with access-controlled URLs — media is private by default and accessed through time-limited signed URLs.
Client-side video compression reduces upload sizes before hitting the server, making uploads practical on mobile data connections. For a worker uploading a 30-second video from a job site on cellular, that compression is the difference between a usable feature and a feature nobody can complete.
Notification System
A hiring platform needs to keep both sides informed. We built a notification system covering the full lifecycle: new job matches, application status changes, team management events, hiring confirmations. Each notification type triggers through the appropriate channel — email, SMS, or in-app — based on the user's preference.
Onboarding Flows
Worker and employer onboarding required different approaches. Workers need a streamlined mobile-friendly flow that collects trade information, skills, and availability. Employers need company setup, team management, and job posting capabilities. Both flows include validation, progress saving, and follow-up reminders for incomplete registrations.
Rebuilds Are Not Failures
Not everything we shipped in January survived to April unchanged. The data infrastructure is the clearest example.
We started with a low-code data approach — fast to stand up, easy to demo, and exactly right for getting feedback in front of users quickly. It hit ceilings fast as the platform's needs grew. We rebuilt on SQL, which gave us the control and performance the matching engine and search needed.
Then we ran into a different kind of rebuild. As we got more validation from workers and employers about how trades, skills, and certifications actually relate to each other, the early taxonomy turned out to be wrong in ways we couldn't patch. A complete taxonomy revamp followed — and that revamp meant another round of data work on top of the SQL foundation we'd just stabilized.
Each rebuild was painful in the moment and right in retrospect. The temptation when you're shipping under deadline is to keep extending what already exists. The harder discipline is admitting when an early choice doesn't hold and committing to the redo before the cost compounds.
The 300+ commits in January — and the months that followed — included rebuilds, not just new features. That's normal for a platform finding its shape. The PRD changed for the same reason the data layer did: reality kept telling us our first version of something wasn't quite right.
What I'd Do Differently
Two things. I'd write the matching engine's factor configuration as data, not code, from the first version — we migrated to data-driven later, but every weight change in the early version touched code and discouraged the small tuning experiments that matter most. And I'd go straight to SQL for data storage, skipping the low-code starting point. The low-code phase taught us things, but the rebuild cost was real and the lessons could have come from prototyping inside SQL itself.
The Approach
300+ commits in a month is sustainable only when the foundation supports it. Every system built in January relied on December's infrastructure: the CI/CD pipeline caught regressions, secrets management kept credentials safe, the environment strategy let us test against real data without risk to production. Speed came from confidence, not shortcuts.