GAP School Module 12 — Adapting Across Verticals Lesson 12.2

The fastest path to a catastrophic client situation is shared infrastructure. One client's data in the same database as another client's data. One client's credentials giving access to another client's system. One compliance failure contaminating multiple clients at once. These aren't hypotheticals — they're the direct result of cutting corners on isolation.

The three-firewall doctrine is the rule that prevents this.


The situation

When you run a platform that serves multiple clients across multiple verticals, the temptation is to share infrastructure where you can. Shared hosting account. Shared database server. Shared email sending domain. Shared API credentials where the clients don't overlap.

The argument for sharing is cost. A single managed server is cheaper than four. A shared SMTP domain is easier to manage than per-client dedicated sending infrastructure.

The argument against sharing is everything else. Data isolation. Regulatory compliance. Debugging clarity. Blast radius control. The ability to terminate one client relationship without touching any other. These are not academic concerns — they're operational realities that surface at the worst possible time when you haven't built for them.

The three-firewall doctrine makes isolation structural, not a matter of discipline.


What I did

The doctrine has three named firewalls, each protecting a different boundary.

Firewall 1 — The platform firewall

Every client is completely isolated from every other client's infrastructure. There is no shared database, no shared hosting account, no shared credentials, no shared anything at the application layer.

In practice:

  • Separate Cloudways application per client (separate PHP-FPM pool, separate database, separate file system)
  • Separate Cloudflare zone per client (separate WAF rules, separate rate limits, separate certificate)
  • Separate SMTP sending domain per client (separate Brevo sub-account or equivalent)
  • Separate Google Apps Script container per client (separate bound script ID, separate service account)
  • Separate Stripe account per client if payment processing is involved

What does "separate application" mean on Cloudways? It means a separate application entry in the panel, connected to a separate MySQL database user, with no cross-database access possible. The hosting server itself may be shared (same physical/virtual machine) — what matters is that the application boundaries are enforced at the database and file-system layer.

Firewall 2 — The master-vs-client firewall

The second firewall separates the GAP Industries master infrastructure from any client-facing deployment. The master infrastructure is where platform development happens: staging environment, development toolchain, test databases. Client infrastructure is production-only; it never gets development code pushed to it without a proper deployment process.

In practice:

  • No direct development on client production servers
  • No developer credentials stored in client production files
  • No platform admin accounts in client admin panels with God-mode access (admin access exists but is auditable and named)
  • Separate SSH keys per environment (development, staging, production)

The reason this firewall exists is liability scope. If the platform's development infrastructure were compromised, no client production system would be reachable through that compromise. The boundaries are physical — different servers, different credentials, different authentication paths.

Firewall 3 — The sub-processor firewall

Every third-party service that touches client data is a sub-processor. Brevo (email), the SMS platform, Cloudflare (CDN/WAF), Cloudways (hosting), Google (Sheets/Apps Script), Anthropic (AI). Each handles or transmits client data in some form.

The firewall here is documentation and data handling agreements. Before any sub-processor gets access to client data:

  • The sub-processor is named explicitly in the client's data processing agreement
  • The purpose and scope of data access is defined
  • The sub-processor's own data handling commitments are on record

This isn't bureaucracy for its own sake — it's the legal architecture that makes the Platform-vs-Agent doctrine work. GAP Industries is a data processor. The client is a data controller. The client bears the vertical regulatory burden. But that only holds if the sub-processor documentation proves data handling is properly scoped.

What the firewall looks like in code

The table prefix discipline is one concrete implementation at the database layer:

wp-config.php — separate database per client
// Client A — its own WP installation, its own database: $table_prefix = '[client_a]_'; // Client B — entirely separate WP installation, separate database: $table_prefix = '[client_b]_';

Different prefixes in different databases on separate database users. Even if someone had MySQL root access to the server, a query against [client_a]_leads returns nothing for Client B's data because Client B's data is in a different database entirely.

The same isolation applies to file storage:

File system isolation
/home/[cloudways_app_a]/htdocs/wp-content/uploads/[client_a]/ /home/[cloudways_app_b]/htdocs/wp-content/uploads/[client_b]/

No symlinks, no shared upload directories, no cross-app file access. Different apps, different paths, different SSH users.


Why it matters

The blast radius argument: if one client's system is compromised (plugin vulnerability, stolen admin credentials, misconfigured file permissions), the compromise is bounded by the firewall. It cannot spread to other clients. The damage is isolated to one installation.

The compliance argument: each client exists in a different regulatory context. An insurance vertical has TCPA obligations. A healthcare-adjacent vertical has PHI considerations. These obligations must be scoped per client. If clients share infrastructure, a compliance decision made for one client contaminates the others. Isolation means each client's compliance posture is independent.

The operational argument: when you need to terminate a client relationship, change a client's infrastructure, or migrate a client to a new platform, the isolation means you can do it without touching anything else. No entanglement. No "if I move this, what breaks over there."


The Anchor build

The first client on the platform is completely isolated from the second. Different Cloudways applications, different databases, different SMTP accounts, different Cloudflare zones, different Google Apps Script containers. They share one thing: the platform code is descended from the same lineage. But no data is shared, no credentials overlap, no infrastructure is shared.

This was not an obvious decision at the outset. The temptation to share a single server for multiple clients is real — it cuts infrastructure cost significantly. I chose against it for exactly the reasons above. The compliance scope question alone made sharing untenable: how do you sign a data processing agreement with Client A if Client A's data is on the same database server as Client B?

The isolation adds roughly $24–48/month per client in hosting cost. Against the liability it prevents and the compliance architecture it enables, that's not a meaningful cost.


Do this, not that

  • Separate database per client. Not separate tables in the same database — separate databases with separate database users. The cost difference is negligible. The isolation difference is not.
  • Separate SMTP sending domain per client. A client's spam complaint rate affects their sending domain reputation only. If clients share a domain, one client's bad list hygiene can destroy everyone's deliverability.
  • Document your sub-processors before you sign a client. Name them in the data processing agreement. Brevo, the SMS platform, Cloudflare, Cloudways, Google — each one is a named sub-processor. The client signs off on the list. This is the legal infrastructure that makes the processor/controller split work.
  • Never let development credentials touch production. Development SSH key is separate from production SSH key. Development database is separate from production database. The firewall between dev and prod protects clients from developer mistakes, not just external attackers.
When you’re ready to build

The lessons are yours. When you want it built, we’re here.

Every lesson stays free — no account, no paywall, no email gate, ever. But if you’d rather have this system standing on your business than wire all 48 lessons yourself, leave your email. We’ll send you a direct line to a build — and you’ll be first to hear when we add new tools to the curriculum.

None of this gates a single lesson. The curriculum was free before you got here and it stays that way.

We’ll use your email to send you a fast-track to a GAP build and occasional notes on how GAP builds digital sales departments. Lessons stay 100% free — no email required to read any of them. We never share or sell your information. Unsubscribe any time. Privacy policy at gapindustriesllc.com/privacy.html.

Done learning how it’s built? We’ll build it.

You came here to understand the system, and now you do. If you’d rather have it standing on your business than spend the next three months wiring it yourself, GAP Concierge is the same architecture from these lessons — a white-label AI agent that knows your catalog and captures your leads — set up for you, from $97/mo.

See GAP Concierge →