Every dealership had its own copy of the site. Launching a new one took days.
- Client
- An automotive retail marketing and technology provider
- Scale
- More than 450 dealership sites on one platform
- Engagement
- A replatform onto one multi-tenant codebase
The outcome in five lines
| Measure | Before | After | Evidence |
|---|---|---|---|
| Dealership sites on the platform1 | a separate copy of the code per site | more than 450 on one codebase | Measured |
| Launching a new dealership2 | days, and error-prone | under 30 minutes, done by sales and support staff | Measured |
| Uptime3 | downtime under traffic spikes | 99.9%, held over 12 months | Measured |
| Dealer management and inventory providers4 | a different feed format from each | more than 15 normalised on the way in | Measured |
| Releases5 | features reached sites at different times | every site at once, with no interruption to service | Described |
Four lines are measured figures from the engagement record. One describes a change in how the system works that carries no number, and is marked so. Each links to its source.
The problem, in the client's terms
The previous system had no multi-tenancy. Every dealership site meant another copy of the code, so a feature reached some sites and not others, at different times. Onboarding a new dealership was slow, and somebody usually made a mistake doing it. Updates and content went out unevenly. When traffic spiked, sites went down or slowed, and the client's own customers noticed.
For the people running it, every dealership was a small project. A launch meant a developer setting up a site by hand. A fix meant deciding which copies needed it and applying it to each. A question from a dealer about why a feature was missing had no simple answer, because the answer was different for every site.
Adding dealerships made all of this worse at the same rate. The work grew with the number of sites, not with the number of features, so growth itself was the cost.
- ConstraintEvery dealership keeps its own brand and customisations.
- ConstraintReleases may not interrupt service. The client committed to a high uptime level.
- ConstraintLaunching a dealership has to be work that sales and support staff can do, not a software engineer.
- ConstraintNo dealership may see another's data, stock or customers.
The architecture, before and after
Switch between the two. Separate copies of the code became one codebase with overrides, hand-built launches became a wizard, and every inventory feed now passes through one ingestion path.
- What hurt in this state
- Built in this engagement
Components are from the engagement record. The shape of the old system and the direction of each link are drawn from how the record describes them.
Three decisions, and what we turned down
What was built is in the record. Why it was built that way is the part a technical reader can judge us on, so each decision names what it replaced and what it cost.
One codebase with plugin overrides, not a fork per dealer
Turned down
A fork of the code for each dealership
This was the old system's problem. Every fix is applied once per fork, and forks drift until no two sites behave the same.
Chosen
One codebase, with a plugin-style override for what a dealer needs to differ
A fix or a feature ships once and reaches every dealership. What a dealer changes is kept in one known place, separate from the core.
What it cost: The override points had to be designed up front and kept narrow. A dealer who wants something no override point allows waits for a core change, and every core change has to be tested against the overrides in use.
A database schema per dealership
Turned down
Shared tables with a dealer column
One query that forgets the dealer filter shows one dealership another's data, and one large dealer's load and indexes are everyone's.
Turned down
A separate database per dealership
Every dealer adds a database to provision, connect to, back up and migrate, and connection counts grow with the number of tenants.
Chosen
One PostgreSQL server, one schema per dealership
Each dealer's data sits apart by default, the platform still runs one database, and a dealership can be exported or removed as a unit.
What it cost: Every migration runs once per schema, more than 450 times per release, and has to cope with a run that stops partway. Reporting across dealers means querying across schemas.
Blue and green releases with versioned migrations, not maintenance windows
Turned down
Scheduled maintenance windows
A high uptime commitment leaves little room for planned downtime, and a storefront has visitors at every hour a window could use.
Chosen
Run the new version beside the old, switch traffic once healthy
A release does not take sites offline, and switching back to the old version is quick if the new one misbehaves.
What it cost: Old and new code run against the same database during a switch, so every schema change must work for both. A breaking change takes two releases, and the platform needs room for two versions at once.
How it was delivered
The order of the work follows what depends on what. Tenancy first, then the tools that put dealers on it, then what keeps it running. The record holds no week windows, so none are shown.
Tenancy core
One codebase, the plugin override mechanism, a PostgreSQL schema per dealership and JWT authentication scoped per dealer.
Storefront and search
React with Next.js server-side rendering, Redis caching and Elasticsearch for vehicle search.
Inventory ingestion
Scheduled ingestion over APIs and flat files, with a custom transformer for each provider's format.
Self-service tools
The admin panel with guided wizards for launching a dealer, and the no-code visual builder for promotions.
Platform and releases
Google Kubernetes Engine with autoscaling, GitHub Actions and ArgoCD, blue and green deployments, and Prometheus with Grafana.
Who owns what now
The client's own sales and support teams launch new dealerships through the admin panel, and dealerships run their own promotions and landing pages.
Results
What changed for the client's staff, for the dealerships and for the people shopping on their sites.
- Sales and support staff launch a new dealership through a guided wizard in under 30 minutes, without a software engineer.
- Dealerships run their own promotions, banners and landing pages through a no-code visual builder.
- The client's own team ship a fix or a feature once and see it on every dealership site at the same time.
- People shopping for a vehicle meet a site that stays up when traffic spikes, held at 99.9% uptime over 12 months.
The old system's uptime and launch time were not recorded as figures beyond "days", so no before number is shown for either.
What it would be worth to you
We do not publish what an engagement costs. So this works from your side: what your client launches cost today, what they would cost at under 30 minutes, and, if you enter them, what your downtime costs.
Launch labour saved per year
Enter your launches
- Launch hours per year, today
- Enter your launches
- Launch hours per year, after
- Enter your launches
- Downtime hours avoided per year at 99.9%
- Enter your uptime
- Value of that downtime
- Enter both uptime fields
A launch becomes a task for the sales team rather than a project for a software engineer.
What went wrong, and what we would change
Every inventory provider sent a different shape
The record says standardising vehicle feeds from diverse dealer management systems with inconsistent formats required custom data transformers. More than 15 providers means more than 15 ways for a field to be missing, renamed or formatted differently, and each one surfaced when a dealer on that provider went live. Next time, each provider gets a set of captured sample files and a test the transformer must pass before the first dealer on it launches, and a record that will not map is set aside for review instead of failing the whole feed.
An override can turn into a fork by another name
A plugin override is the right tool for a dealer's real differences. Left unwatched, overrides grow until one dealer's site behaves like a separate product again, which is the problem the platform replaced. What we would change: count overrides per dealer and review any that reach past presentation into business logic.
A migration has to succeed on every schema, not most
With a schema per dealer, one release migrates every schema. A migration that works on a test schema can fail on one dealer whose data is unusual, and the release is then half done. What we would change: rehearse each migration against a copy of every schema before the release, and make every migration safe to run twice.
Will this work for your platform?
It fits when
- You run many sites for many clients, and most of what each client needs is the same.
- You launch new clients often enough that the launch itself is a cost you notice.
- Clients should not see each other's data, and you need to prove it.
Look elsewhere when
- You have a handful of clients who each want something very different. Separate builds may cost less.
- One client needs its own infrastructure by contract. A schema on a shared server will not satisfy that.
- Your sites differ mostly in content, not in behaviour. A content system with themes may be enough.
Check it yourself after your next client launch
If a launch takes days and a fix reaches your sites at different times, this case study is about you. Put your launch count into the calculator above.
- Write down the hours the last launch took, and who had to do it.
- Count the copies of your code running in production.
- Pick your last fix and count how many sites have it today.
The stack, by layer
- StorefrontReact with Next.js server-side rendering, a no-code visual builder for promotions
- AdminA React admin panel with guided wizards for launching a dealership
- PlatformLaravel and Node.js, one codebase with plugin-style overrides, JWT authentication with per-dealer scope
- DataPostgreSQL with a schema per dealership, Redis for in-memory cache, Elasticsearch for vehicle search
- IntegrationScheduled inventory ingestion over APIs and flat files, custom transformers for more than 15 providers
- InfrastructureGoogle Kubernetes Engine with autoscaling, Cloudflare managed certificates, an NGINX reverse proxy cache
- DeliveryGitHub Actions and ArgoCD, blue and green deployments, versioned database migrations, Prometheus and Grafana
Where each figure comes from
- Engagement write-up. "450+ active dealerships supported with customizable retail experiences" and "Multi-Tenant SaaS Engine: Built with Laravel and Node.js, enabling independent dealership sites to share a single codebase while supporting brand-specific customizations." The problem statement records that the previous system had no multi-tenancy, so each site meant duplicated code.
- Same write-up. "30-minute dealer onboarding reduced setup time from days to minutes" and "A React-based admin panel with intelligent wizards allowed sales and support teams to launch new dealers in under 30 minutes." The problem statement records onboarding as slow and error-prone.
- Same write-up. "99.9% SLA met consistently over 12 months". The problem statement records downtime and inconsistent performance under traffic spikes, which the record does not quantify.
- Same write-up. "Scheduled ingestion and syncing of vehicle inventory via APIs and flat file parsers, compatible with over 15 DMS and inventory providers." and "Standardizing vehicle feeds from diverse DMS systems with inconsistent formats required custom data transformers."
- Same write-up, described without figures. "With high SLA requirements, we implemented blue/green deployments and database migration versioning to avoid interruptions." The problem statement records features and updates reaching sites unevenly.
- Same write-up, described without figures. "PostgreSQL with multi-schema support per dealership, Redis for in-memory cache, and Elasticsearch for lightning-fast vehicle search." and "Dealerships could launch promotions, update banners, and manage landing pages through a no-code visual builder."
Figures we hold and do not show yet
- Performance scores improved 60%. The record does not name the instrument or which scores. It publishes once the instrument is known.
Tell us how long your last client launch took, and we will tell you if one codebase pays.
Send the launch hours and the number of client sites you run. A software engineer reads it and replies with an honest answer, including when separate builds are the better choice.