Fjord
Multi-tenant SaaS backend for home-service contractors - lead capture, AI-driven SMS follow-up, and reviews on one stack.

Problem
Home service contractors, including plumbers, HVAC technicians, electricians, roofers, and other local trades, face a problem that goes beyond the work they actually do. Running the business around that work creates a constant amount of overhead that is easy to overlook.
01A phone that can't always be answered
A contractor can be inside a customer's house, driving between jobs, or spending time with their family when a potential customer calls. They cannot realistically have their phone in their hand 24/7.
But the customer usually will not wait. They call the next contractor they find on Google.
02Not every missed call needs a callback
Some are:
- Spam
- Existing customers checking in
- People asking for services the company doesn't offer
Contractors need a way to know which conversations actually matter, without personally answering every call.
03Leads that go cold
The same thing happens after a lead comes in. Contractors send estimates that never get followed up on, forget to respond to inquiries when the day gets busy, and spend time talking to people who never end up booking.
These are not necessarily large failures. They are small things happening every day that quietly turn into lost jobs.
04Tools that don't fit
Many small contractors aren't operating through sophisticated business software. They use Excel, their phones, text messages, email, and memory to keep track of customers - the information is there, it's just scattered. Traditional CRMs can solve some of this, but often introduce another problem: they're complicated enough that the contractor has to spend time managing the software itself.
Their online presence has a similar gap. A website and Google Business Profile are only the beginning - contractors need to understand where leads come from, whether customers are finding them, how their reviews are changing, and what happens to those leads after the first interaction. Most small businesses either don't have the time to track this, or need someone else to do it for them.
Customer communication needs the same care. Contractors want automated follow-ups, but not ones that read as robotic, ignore the service someone actually asked for, or keep arriving after a customer has stopped engaging. Automation needs to understand context, not just trigger another message.
05What was missing
The common thread we found was that contractors were not aware of the options they had to solve these problems - which is itself a problem a lot of people face. And out of the options that did exist, there was a lack of software that fit how small contractors actually work: something easier to navigate, but still customizable.
That tradeoff - simple enough to use, but still customizable - was a balancing act, and highlighted the inherent friction between user-friendly design and functional depth.
The owner of a small contracting company often wears every hat at once:
- Answering the phone
- Estimating jobs
- Managing employees
- Talking to customers
- Handling invoices
- Doing the actual trade work
Every process that still depends on them becomes another bottleneck.
System design & approach
Fjord answers this with one connected surface per contractor, instead of the scattered one described above: a white-label lead-capture website, automated Google review requests after every job, and a dashboard that tracks every lead from first contact to close - so a missed call, an unanswered estimate, or a job nobody asked to review isn't just something the owner has to remember to chase.
Every contractor runs on the same Postgres instance and the same API surface, but their leads, pipeline, and site content can never cross. That's what makes it possible to offer software this opinionated without it being one-size-fits-none: I architected the boundary as a Node/Express backend on Supabase with 59 REST endpoints across 13 database tables, enforcing tenant isolation across three surfaces per business - their dashboard, their sales pipeline, and the white-label site Fjord provisions for them - so each contractor gets something that fits how they work without Fjord having to hand-build it per customer.
On top of that I built the AI layer that closes the missed-call gap: a Gemini-powered workflow system that holds a configurable context per customer - the business's services, tone, and pricing rules - and runs the conversation logic for inbound SMS. It qualifies the lead - separating a real job from spam, an existing customer, or a request for a service the business doesn't offer - then drafts a personalized reply in that business's voice, automatically, 24/7. Fjord's automation also reaches outside its own stack: I integrated it with GoHighLevel's APIs and webhooks, since most contractors already run GoHighLevel for CRM and messaging, rather than asking anyone to switch tools. Every endpoint sits behind JWT-based authentication, hot paths are cached in Redis, and billing runs through Stripe.
Challenges
Two things made this harder than a normal CRUD backend. First, tenant isolation had to hold at the schema and API level with zero exceptions - one contractor's data touching another's isn't a bug you patch later, it's the kind of thing that ends the product. Second, an AI reply that sounds like a generic chatbot is worse than no reply at all for a small business that's built its reputation on personal service, so the SMS layer needed a configurable context per customer, not one shared prompt.
On the reliability side, every tenant depends on the same endpoints, so I couldn't treat performance as something to check after shipping. I load-test changes with k6 against a p95 latency budget under 5 seconds before they go out.


My role
I'm the backend engineer on Fjord - I own the API surface every tenant's dashboard, AI workflows, and third-party integrations run on. The multi-tenant architecture, the Gemini-powered AI layer, the GoHighLevel integration, auth, caching, billing, and load testing above are all mine end to end.
Retrospective
The GoHighLevel integration plus a faster, load-tested provisioning path cut client onboarding time by 88% - contractors go from signing up to live in about a week instead of much longer. The backend now runs 59 REST endpoints across 13 tables, all held to a sub-5-second p95 latency budget under k6 load tests.
Designing tenant isolation at the schema and API level, not just the UI, and treating it as a hard invariant rather than a convention. Building an AI system where the interesting engineering problem is configurable behavior and context per customer, not the model call itself. And treating latency as a testable requirement with a real budget (k6, p95 under 5s) instead of something you only notice once it's already a problem.
- React
- Node
- Express
- Supabase
- Redis
- Stripe
- GoHighLevel
- Gemini
- k6