Systems

Architecture for a multi-tenant lead-intelligence SaaS

Wrote the requirements, architecture and detailed design for a multi-tenant lead SaaS, and built a demo for client review.

Role
Sole owner
Period
From July 2026
Status
Architecture, specification and a review demo. Not a launched product: no production backend, no users. (as of 6 August 2026)
Outcome
Three specification documents complete and a demo of each plane deployed for client review.

01 / Problem

A client wanted a SaaS that ingests public-records filings, enriches each case with owner contact data from third-party contact-data APIs, validates quality, and pushes sales-ready leads into each customer's CRM. Many customers share one deployment. Enrichment costs money per lookup, so each lookup had to be billable to the tenant that asked. The filings themselves are public and identical for everyone. The client's requirements arrived in rounds, so the design had to stay stable while three decisions stayed open. I owned the specification and the demo, so the two had to agree.

My role: Sole owner: architect, requirements owner, specification author and builder of the frontend demos.

02 / System

Filing ingest 1 Shared store 2 Enrichment 3 Tenant database 4 CRM delivery 5 Control plane 6 Filing ingest 1 Shared store 2 Enrichment 3 Tenant database 4 CRM delivery 5 Control plane 6
The specified path of one lead, in order. This is design: I built only the demo screens, not this pipeline.

Select a component to read what it does and how it fails.

  1. Filing ingest. Polls public-records sources once for everyone, which keeps it cheap. If polling stalls, every tenant's filings go stale together.
  2. Shared store. One database holds property, owner, filing and enrichment results once. A bad write here reaches every tenant.
  3. Enrichment. Contact-data lookups run only when a tenant asks, and are billed to that tenant. A provider outage delays requests, not ingestion.
  4. Tenant database. Everything a tenant owns lives in its own database. Isolation is structural, not a query filter; the price is many migrations.
  5. CRM delivery. Validated, sales-ready leads are pushed into the customer's CRM. As the last hop, its failures are what the customer sees first.
  6. Control plane. A separate repo, backend and privilege boundary for provisioning, tenant resolution and migrations. It reaches every tenant, so guard it.

03 / Decisions

Share the public data, isolate the paid data

Decision
One shared source-of-truth database holds property, owner, filing and enrichment results once. Everything a tenant owns sits in a database per tenant.
Rejected
Copying the public data into every tenant's database.
Why
Filings are identical for everyone, so wide, cheap ingestion should happen once. Enrichment is expensive and demand-scoped, so it stays billed to the tenant that asked.
Cost
Two data planes to keep consistent, and a bad write to the shared store reaches every tenant.

Split the control plane

Decision
A separate repo, backend and privilege boundary for the admin plane, with provisioning, tenant resolution, migration execution and shared-infrastructure placement written down.
Rejected
Building it beside the tenant backend as extra routes.
Why
The code that can create, migrate and inspect every tenant should not share a deploy or a credential set with the code every tenant's users reach.
Cost
Two backends to run, and a written contract between them that has to stay true.

Trace every requirement to a screen

Decision
Requirement IDs run from the requirements document into the demo, and the demo shows only what the document specifies.
Rejected
A richer demo with screens the document did not ask for.
Why
A reviewer can walk from any requirement to the screen that shows it, so disagreement becomes a change to the specification, not an argument about a mock-up.
Cost
The demo could not reveal what the requirements missed. That took the client's written input, which left three decisions open for me to close.

04 / What broke

Nothing broke, because nothing ran in production. The demo is a review artifact: it shows the specified screens, not a working pipeline. When I last checked, the production backend had not been started, so I have no incident to report and will not invent one.

05 / Outcome

  • I finished the requirements (v1.3), architecture (v1.3) and detailed design (v1.1) documents, after a discovery pass on market, competitors, data sources, workflows and personas.
  • I closed the three decisions the client's second-round input left open: a dual-mode data-pool toggle, dismissed-date handling and a filing schema placeholder.
  • This took the architecture and demo from nothing to something a client could review. It did not take a product to launch.

06 / The rule I took from this

Write the specification first, and trace every requirement to a screen.

Rule 7 of 9

Stack

  • Next.js
  • React
  • Tailwind CSS
  • Docker
  • Traefik

Specified, not built by me:

  • NestJS
  • Python
  • FastAPI
  • Celery
  • PostgreSQL
  • OpenSearch
  • Redis
  • Auth0
  • Terraform

Next