3.14

View in English

3.14 Multi-tenancy and SaaS architecture

Overview and motivation

Multitenancy is the practice of running one instance of your software so that it serves many separate customers at once, keeping each customer’s data and configuration logically apart while they share the same code and, often, the same infrastructure. Each customer is a tenant. This one idea is the economic engine of software as a service (SaaS), the model in which you sell access to a running application rather than a copy to install. When a thousand tenants share the same deployment, you patch once, you scale one system, and the marginal cost of the next customer approaches zero. That is why a well-built multi-tenant product can serve a two-person startup and a hundred-thousand-seat enterprise from the same codebase, and why the tenancy model you pick shapes your margins, your security posture, and your operational load for years.

For large teams the stakes run deeper than cost. Multi-tenancy puts a hard requirement at the centre of your architecture: tenant A must never see tenant B’s data, ever, under any bug, race, or misconfiguration. A single cross-tenant leak can end a company. At the same time, the whole point of sharing is efficiency, so every design decision sits on a spectrum between strong isolation (safer, more expensive) and dense sharing (cheaper, riskier). Getting this right is the difference between a product that scales gracefully and one that either bankrupts you on infrastructure or lands you in the headlines. This chapter builds on cloud architecture (chapter 3.11), leans heavily on data architecture (chapter 3.4) and cloud security (chapter 4.3), and connects to scalability and resilience (chapter 3.5) and cost attribution (chapter 9.4).

Enterprises and governments raise the bar further. Enterprise buyers negotiate contractual data guarantees, demand dedicated isolation for their tier, and expect you to migrate them between environments without downtime. Governments add data residency laws, classification-driven separation, and a frequent requirement that each agency be its own tenant with its own audit boundary. The tenancy decisions here are not implementation details; they are commitments you make to every customer who trusts you with their data.

Key principles

  • Isolation is a spectrum, not a switch. Silo, pool, and bridge models trade efficiency against separation; choose per tier and per resource, not once for everything.
  • Tenant context is sacred. Every request, query, log line, and background job must carry a tenant identifier, and every data access must be scoped by it.
  • A cross-tenant leak is the failure that matters most. Design so that a single missing filter cannot expose another tenant’s data; defence in depth, not one WHERE clause.
  • Noisy neighbours are an architecture problem. Without quotas and fairness, one heavy tenant degrades everyone; plan for it before it happens.
  • Per-tenant configuration scales; per-tenant code does not. Bend the product with data and flags, not with forks.
  • The tenant lifecycle is a product feature. Onboarding, provisioning, offboarding, and data export must be first-class, automated, and auditable.
  • You cannot manage what you cannot attribute. Observability and cost must be sliced by tenant, or you fly blind on both reliability and margin.

Recommendations

Choose a tenancy model per tier, along the isolation-versus-efficiency spectrum

Three models anchor the spectrum. In the silo (dedicated) model, each tenant gets its own isolated stack: separate compute, separate database, sometimes a separate account or network. Isolation is strongest and the blast radius of a bug is one tenant, but you pay for idle capacity per customer and operate many copies. In the pool (shared) model, all tenants share the same compute and database, separated only by logic and a tenant identifier. Efficiency is highest and the marginal cost of a tenant is near zero, but isolation now depends entirely on your code being correct. The bridge (hybrid) model mixes the two: shared compute with per-tenant databases, or a shared pool for small tenants and dedicated silos for large or regulated ones.

Do not pick one model for the whole product. The right answer is usually a bridge that maps to your pricing tiers. Put the long tail of small tenants in an efficient shared pool where their economics work. Offer a dedicated or single-tenant deployment as a premium tier for enterprise customers who will pay for the isolation and the contractual guarantees. Write the mapping down as an architecture decision record (chapter 3.11), because “which tenants share what” is a claim your security, sales, and finance teams all depend on.

Partition data deliberately, and make tenant scoping impossible to forget

Data is where multi-tenancy lives or dies, so treat the partitioning choice as a core data-architecture decision (chapter 3.4). Three strategies parallel the tenancy models. Separate database per tenant gives the strongest isolation, easy per-tenant backup and restore, and simple data export, at the cost of many databases to run and schema migrations to fan out. Separate schema per tenant within a shared database is a middle path: one server, logical separation, still a lot of objects to migrate. Shared tables keyed by a tenant column, where every row carries a tenant_id, is the densest and cheapest, and the most dangerous, because now a single query missing its tenant filter leaks data across customers.

If you share tables, do not rely on developers remembering the filter. Enforce tenant scoping in a layer that cannot be bypassed: database row-level security that attaches a mandatory predicate to every query based on the session’s tenant, an ORM or data-access layer that injects the tenant clause automatically, or both. Belt and suspenders is correct here. As tenants grow, sharding by tenant becomes natural: place groups of tenants on different database shards so no single instance holds everyone, which also caps the blast radius of one shard’s failure and lets you move a large tenant to its own shard without changing the model.

Propagate tenant context everywhere, and defend against cross-tenant leaks in depth

The tenant identifier must ride along with every unit of work. Establish it at the edge, typically from the authenticated session or a subdomain, validate it, and thread it through the request context, every downstream service call, every database session, every queued job, and every log line and metric. The dangerous gaps are the asynchronous ones: a background worker that processes a job without re-establishing tenant context, a cache keyed without the tenant, a webhook handler that trusts a tenant identifier from the caller. Each is a path to serving one tenant’s data to another.

Treat cross-tenant isolation as a security property with defence in depth, and hand the details to chapter 4.3. Apply the principle of least privilege so that even a compromised component can reach only the tenant it is acting for. Never accept a tenant identifier from client-controlled input for authorisation decisions; derive it from the authenticated identity. Namespace caches, object storage prefixes, and search indexes by tenant so a key collision cannot cross the boundary. Then test the boundary on purpose: automated tests that assert tenant A’s credentials cannot read tenant B’s records, and periodic red-team exercises that try to break out of a tenant. A leak found by your test suite is a bug; a leak found by a customer is a crisis.

Contain noisy neighbours with quotas, rate limits, and fairness

When tenants share resources, one tenant’s spike becomes everyone’s outage. This noisy-neighbour problem is not an edge case; it is the default behaviour of a shared pool under load. Design against it from the start. Set per-tenant quotas on the resources that matter (requests per second, concurrent jobs, storage, query cost) and enforce them with rate limiting at the edge and at expensive internal boundaries. Prefer fair scheduling that gives each tenant a share rather than first-come-first-served queues that let one tenant starve the rest.

Match the enforcement to your tenancy model. In a shared pool, quotas and fairness are the primary defence, so invest in them. For a tenant whose load genuinely exceeds what fair sharing can absorb, the answer is often to promote them out of the pool into a bridge or silo deployment, which is a feature you can sell rather than a failure. Tie this to your scalability and resilience work (chapter 3.5): load-shedding, circuit breakers, and backpressure all need to be tenant-aware so that shedding one tenant’s excess load protects the others instead of degrading the whole system.

Configure tenants with data, not forks of your code

Every customer will want something slightly different: their logo, their workflow rules, their integrations, a field you do not have. The scalable way to say yes is per-tenant configuration: feature flags, settings, entitlements, and extensibility points that are data, evaluated at runtime, and shared by one codebase. The path that destroys a SaaS business is per-tenant custom code: a branch or a fork or a special case in the code path for a big customer. Ten of those and you no longer have a product, you have ten products wearing a trench coat, and every change must be tested ten times.

Draw a firm line. Model the axes of variation you are willing to support as first-class configuration, and treat requests outside those axes as either product roadmap or a firm no. When a customer needs true customisation, give them extension points (webhooks, an API, plugins, custom fields) that run their logic without branching yours. Reserve genuinely bespoke deployments for the single-tenant premium tier, where the isolation is the point and the higher price covers the operational cost.

Make the tenant lifecycle automated, observable, and cost-attributed

Onboarding a tenant should be a self-service, automated flow: provision the tenant’s data partition, seed defaults, set entitlements, and be ready in seconds, not a ticket to an operations team. Offboarding matters just as much and is easier to neglect. When a tenant leaves, you must be able to export their data in a usable format, then delete it provably, because contracts and privacy law will require both. Design data export and deletion on day one; retrofitting them into a shared-table schema is painful.

Instrument everything per tenant. Tag logs, traces, and metrics with the tenant identifier so you can answer “is this outage all tenants or one?” and “which tenant is driving this cost?” in seconds. Attribute infrastructure cost to tenants so you know your true margin per customer and can spot the tenant whose usage makes them unprofitable at their current price (chapter 9.4). Tenant-aware observability and cost attribution turn multi-tenancy from a black box into a system you can actually run and price.

Trade-offs: pros and cons

Tenancy modelProsCons
Silo (dedicated stack per tenant)Strongest isolation, smallest blast radius, easy per-tenant compliance and export, simple noisy-neighbour storyHighest cost, idle capacity per tenant, many copies to operate and patch
Pool (fully shared)Lowest marginal cost, densest packing, one system to scale and upgradeIsolation depends entirely on code correctness, worst noisy-neighbour risk, hardest per-tenant export and deletion
Bridge (hybrid, tiered)Efficient for small tenants, dedicated isolation for large ones, maps to pricingMore models to build and operate, promotion path between tiers to maintain
Shared DB, shared schema (tenant column)Cheapest storage, one migration, simplest operationsA single missing filter leaks data; needs row-level security as a backstop
Shared DB, schema per tenantLogical isolation, one server, decent exportMany schema objects, migrations fan out, scaling limits per server
Database per tenantStrong data isolation, per-tenant backup and exportMany databases, migration fan-out, higher cost

The central tension is isolation versus efficiency, and it runs through every row. Denser sharing multiplies your margins and multiplies your risk in the same motion; stronger isolation buys safety and simplicity at a real per-tenant cost. The resolution is not to pick one pole but to place each tenant deliberately along the spectrum, usually by tier: pack the small tenants densely where the economics demand it and the risk is bounded, isolate the large and regulated tenants where they will pay for it and the blast radius must be small. Then make the dense end safe with enforced tenant scoping, and make the isolated end cheap with automation, so neither pole hurts as much as the naive version would.

Questions to discuss with your team

  1. If one tenant-scoping filter were missing tomorrow, would a customer see another customer’s data? This is the question that separates a defensible multi-tenant product from an accident waiting to happen. The honest test is to trace a real read path and ask what enforces the tenant boundary: is it one developer-written WHERE clause, or is there a backstop like database row-level security or a data-access layer that injects the scope no matter what? Bring your actual query paths, your background jobs, and your caches, because the leak almost always hides in the asynchronous corner nobody scoped. You should also bring the results of a test that deliberately uses tenant A’s session to request tenant B’s records and asserts a denial. If the boundary rests on human vigilance alone, you have a latent breach, and the fix (defence in depth) should jump to the top of the backlog.

  2. Which tenancy and data-partitioning model does each customer tier actually use, and does it match what we sold them? Many teams drift into a single model by default, then discover their pricing and their architecture disagree: enterprise customers were promised isolation the shared pool does not provide, or small customers sit in expensive dedicated stacks that wreck the margin. Map each tier to its real model (silo, pool, or bridge; database-per-tenant, schema, or shared table) and lay it beside the contractual data guarantees your sales team makes. Where they diverge, you have either a compliance risk or a cost problem, and both are worth surfacing before a customer or an auditor finds them. The evidence to bring is the tier-to-model mapping, the per-tenant cost, and the actual language in your enterprise contracts.

  3. When a large tenant’s load spikes, who else feels it, and what is our plan? In a shared pool the answer is often “everyone,” and teams frequently do not know this until an incident makes it obvious. Walk through what happens when your biggest tenant runs a bulk import or gets a traffic surge: do per-tenant quotas and fair scheduling contain it, does load-shedding protect the neighbours, or does the whole system degrade together? Bring load data and the story of your last noisy-neighbour incident, because the tenant who hurts you is usually one you can name. The answer should shape both your rate-limiting investment and your tiering strategy, since the cleanest fix for a tenant who outgrows fair sharing is to promote them into a bridge or dedicated deployment you can charge for.

  4. When a tenant offboards tomorrow, can we hand them a clean export and prove we deleted every trace, or would we be scrambling? Offboarding is the part of the tenant lifecycle teams neglect until a contract exit clause or a privacy-law request forces the issue, and by then the shared schema makes extraction and deletion painful. For a large team the risk compounds, because a tenant’s data is scattered across the primary database, caches, object storage, search indexes, backups, and analytics pipelines, and each one must be exported in a usable format and then provably purged. The competing considerations are real: dense shared tables that give you cheap storage are exactly the ones that make per-tenant extraction and deletion hardest, so the efficiency you bought at the storage layer you may pay back at the exit. Bring a live walk-through of an offboarding on a real tenant, the list of every store that holds tenant data, and the evidence you would show that deletion actually happened. For enterprise and government tenants, the export must be certified and the deletion provable to satisfy public-records and privacy statutes, so treat a missing deletion path as a compliance defect to close now, not a feature to add when a customer leaves.

  5. How many one-off special cases for individual customers already live in our code path, and where is the line we refuse to cross? Per-tenant code forks are the quiet way a SaaS business stops being one product and becomes many products wearing one name, where every change must be tested against every special case and velocity decays as you add customers. The tension is that a big customer with a real need is hard to refuse, and a branch in the code path feels faster than building a configuration surface, so the special cases accumulate one reasonable exception at a time. Bring an honest inventory: grep the codebase for customer names and tier-specific branches, count them, and estimate the extra test and review cost each one imposes on an unrelated change. The discussion should draw a firm line between variation you model as first-class configuration (flags, entitlements, extension points) and true bespoke work you reserve for a single-tenant premium tier where the higher price covers the operational cost. For enterprise buyers who demand deep customisation, the durable answer is extension points that run their logic without branching yours, so that governance and audit stay tractable across the fleet.

  6. Can we tell, per tenant, both what an incident is costing whom and which customers are unprofitable at their current price? Multi-tenancy turns into a black box the moment your logs, traces, metrics, and infrastructure cost carry no tenant dimension, because then you cannot answer whether an outage is one tenant or the whole fleet, and you cannot name the tenant whose usage makes them a loss at their contract price. For a large team this attribution is what separates running the platform from guessing at it, and it directly shapes both reliability response and pricing. The considerations pull against instrumentation cost and cardinality: tagging everything by tenant is not free, and high-cardinality metrics strain your observability budget, so you choose deliberately what to slice per tenant and what to sample. Bring your current tenant-tagging coverage, a real query that attributes cloud spend to a single tenant, and the margin table that would let you name your least profitable customer. In enterprise and government settings, per-tenant cost and audit-scoped observability also feed chargeback, capacity planning, and the audit boundary each agency or business unit is entitled to, so the tenant dimension is a governance requirement as much as an operational one.

Sector lens

Startup. Ship a single shared pool from day one and put your scarce engineering attention into the one thing that cannot be retrofitted: enforced tenant scoping. A managed Postgres with row-level security, a tenant_id on every table, and tenant context resolved at the edge buys you safe density without an operations team. Do not build silo tiers or per-tenant infrastructure speculatively; add a bridge tier only when a paying enterprise prospect makes the isolation worth its cost.

Small business. With no platform specialist and a tight budget, lean on what your cloud and framework already give you rather than building isolation machinery yourself. Managed databases with row-level security, a platform-as-a-service that scopes tenants for you, and an authentication provider that carries tenant identity are usually cheaper and safer than hand-rolled equivalents. Treat multi-tenancy as a buy-versus-build decision at every layer, and reserve custom work for the tenant boundary tests that only you can write.

Enterprise. The problem is portfolio governance across many teams: a tiered bridge architecture, an architecture decision record mapping each tier to its tenancy and data-partitioning model, and per-tenant cost attribution so finance knows the true margin on every account. Standardise the tenant-context propagation and the scoping backstop so no team reinvents them, budget the isolation and lifecycle automation explicitly, and keep a supported, priced path to migrate a tenant between tiers without downtime as they grow or their compliance needs change.

Government. Procurement, data residency, and public accountability drive the model. Pin each agency’s data to in-country regions with policy-as-code, silo sensitive or high-classification workloads into separate accounts with their own audit boundary, and give each agency its own identity integration, retention rules, and audit trail so one agency’s auditors never see another’s activity. Offboarding must produce a certified export and provable deletion to satisfy public-records and privacy statutes, and the tenancy guarantees you sign must be ones your architecture can actually keep.

Examples

Startup. A fifteen-person startup builds its product as a single shared pool from day one and is right to. All tenants share one managed Postgres database with a tenant_id on every table, row-level security enforces the tenant predicate at the database so a forgotten filter cannot leak, and the application resolves the tenant from a subdomain at the edge and threads it through every request and background job. Onboarding is self-service: a new signup provisions its tenant row, seeds defaults, and is live in seconds. Two engineers run the whole platform because there is one system to operate. When their first real enterprise prospect demands a dedicated database and a contractual isolation guarantee, they add a bridge tier: the same codebase, but this tenant gets its own database on its own shard, sold at a price that covers the cost.

Enterprise. A SaaS vendor serving large financial institutions runs a tiered bridge architecture. Thousands of small and mid-size customers live in regional shared pools, sharded by tenant, with quotas and fair scheduling holding the noisy neighbours in check. Top-tier banking customers get single-tenant deployments in isolated cloud accounts, with dedicated databases, per-tenant encryption keys, and contractual data-residency and isolation guarantees written into the master agreement. A platform capability migrates a tenant between tiers without downtime when they grow or their compliance needs change. Every tenant’s cost is attributed through tagging so finance knows the true margin on each account, and tenant-tagged observability lets the on-call engineer tell in seconds whether an alert is one tenant or the whole fleet.

Government. A national platform provider hosts many government agencies as separate tenants and treats isolation as a legal requirement, not a preference. Data residency law pins each agency’s data to in-country regions, enforced by policy-as-code that blocks any resource in a disallowed region (chapter 3.11). Classification drives the model: agencies handling sensitive material get fully siloed deployments in separate accounts with their own audit boundary, while lower-classification workloads share a governed pool. Each agency is its own tenant with its own identity integration, its own retention and export rules, and an audit trail scoped to its boundary, so one agency’s auditors never see another’s activity. Offboarding produces a certified data export and a provable deletion, because the records are subject to public-records and privacy statutes.

Business case: motivations, ROI, and TCO

The core business case for multi-tenancy is margin. A single-tenant model, where you deploy a fresh copy per customer, means infrastructure and operations cost grows roughly linearly with customer count, and your engineers spend their days patching many copies. A shared multi-tenant model breaks that link: you patch once, scale one system, and pack customers densely enough that the marginal cost of the next tenant approaches zero. That is what lets a SaaS business grow revenue far faster than cost, and it is why investors and boards treat a clean multi-tenant architecture as a proxy for a scalable company.

The return shows up in three places: operational leverage (one team runs the whole fleet), faster delivery (a fix ships to every tenant at once, so velocity does not decay as you add customers), and pricing optionality (a shared plan for the long tail and a premium isolated plan for enterprises, both from one codebase). Set these against the costs you must fund honestly: the engineering to build enforced tenant isolation, quotas, lifecycle automation, and per-tenant observability, plus the discipline to keep the boundary intact. The cost of getting it wrong is asymmetric and severe, because a single cross-tenant data breach can trigger regulatory penalties, mass churn, and reputational damage that dwarfs the infrastructure you saved by sharing. Frame the case to leadership as margin and scalability on the upside and existential risk on the downside. Anchor the service-level agreement and the contractual data guarantees to the tenancy model you can actually deliver, because a promise your architecture cannot keep is a liability, not a sale.

Anti-patterns and pitfalls

  • Tenant scoping by convention. Relying on developers to remember the tenant filter on every query, with no database-level or data-access-layer backstop; one omission is a breach.
  • Trusting a client-supplied tenant identifier. Accepting the tenant from request input for authorisation instead of deriving it from the authenticated identity, which lets a caller ask for someone else’s data.
  • Unscoped background work. Jobs, caches, webhooks, and exports that lose tenant context because someone only scoped the synchronous request path.
  • Per-tenant code forks. Special-casing a big customer in the code path until you are maintaining many divergent products under one name and every change costs ten times as much.
  • No noisy-neighbour defence. Running a shared pool with no per-tenant quotas or fairness, so the first tenant to spike takes everyone down.
  • Offboarding as an afterthought. Building without data export and provable deletion, then failing a customer’s exit clause or a privacy-law request because the shared schema makes extraction painful.
  • Flying blind per tenant. Logs, metrics, and cost with no tenant dimension, so you cannot tell whose incident it is or which tenant is unprofitable.

Maturity model

  • Level 1, Initiate: Multi-tenancy is improvised and reactive. Tenant separation rests on hand-written filters with no backstop, the model is one-size-fits-all, there are no quotas, onboarding is manual, and logs and cost carry no tenant dimension. The team learns about the noisy neighbour and the near-miss leak from incidents.
  • Level 2, Develop: Basic practices appear but are inconsistent across teams. A tenancy model is chosen and tenant context is propagated through the main request path, a database-level or data-access backstop enforces scoping on core tables, and basic per-tenant quotas exist. Onboarding is partly automated and logs carry a tenant identifier, but background paths, export, and cost attribution vary from service to service and are written down nowhere.
  • Level 3, Standardise: The tenancy approach is documented and enforced across the organisation. Tiered tenancy maps to pricing, with a shared pool for small tenants and isolated deployments for enterprise and regulated ones, tenant scoping is enforced in depth and tested on purpose, quotas and fair scheduling contain noisy neighbours, the tenant lifecycle including export and provable deletion is automated, and observability and cost are sliced per tenant. Every team follows the same tenancy standard rather than its own.
  • Level 4, Manage: The tenancy estate is measured and controlled against baselines. Per-tenant isolation, fairness, latency, and cost are tracked as metrics with agreed targets: cross-tenant test coverage, quota-breach and noisy-neighbour incident rates, onboarding and offboarding time, and per-tenant margin are reported against baselines, and decisions to promote a tenant between tiers or reprice an unprofitable one are made on that evidence rather than by anecdote. Residency and classification conformance is monitored continuously, and drift from the standard triggers a documented response.
  • Level 5, Orchestrate: Tenancy is continuously improved and integrated across the organisation. Cross-tenant boundaries are exercised by routine red-team exercises, tenants move between tiers without downtime as they grow or their compliance needs change, per-tenant margin feeds pricing and capacity planning, and residency and classification rules are enforced by policy rather than by review. The model adapts as the customer mix and the regulatory picture shift, and the lessons feed product, security, and finance as one loop.

Ideas for discussion

  1. Where does each of your customer tiers sit on the isolation-versus-efficiency spectrum today, and is any tier in the wrong model for the guarantees you sold or the margin you need?
  2. If you had to prove to an auditor that tenant A cannot access tenant B’s data, what evidence could you produce right now, and how much of it is automated versus asserted?
  3. Which of your asynchronous paths (jobs, caches, webhooks, exports, search indexes) re-establish tenant context, and which merely inherit it or trust the caller?
  4. When a tenant outgrows fair sharing, do you have a supported, priced promotion path into a bridge or dedicated deployment, or does the answer default to an incident?
  5. Can you attribute infrastructure cost to individual tenants well enough to name your least profitable customer, and would that change how you price?
  6. For a government or regulated tenant, can you enforce data residency and classification-driven isolation by policy, and offboard with a certified export and provable deletion?

Key takeaways

  • Multi-tenancy, one instance serving many tenants, is the economic engine of SaaS: it drives your margins, and it puts cross-tenant isolation at the centre of your architecture.
  • Treat isolation versus efficiency as a spectrum and tier it: pack small tenants in an efficient shared pool, isolate large and regulated tenants in bridge or silo deployments they will pay for.
  • Never rest tenant scoping on a hand-written filter; enforce it in depth with row-level security or a data-access layer, and test the boundary on purpose.
  • Propagate tenant context through every request, job, cache, and log, and defend the asynchronous paths where leaks hide.
  • Contain noisy neighbours with per-tenant quotas, rate limits, and fair scheduling, and promote tenants who outgrow the pool rather than letting them degrade it.
  • Bend the product with per-tenant configuration, not per-tenant code, and make the tenant lifecycle and per-tenant observability and cost attribution first-class.

References and further reading

  • Tom Kwok, Thao Nguyen, and Linh Lam, A Software as a Service with Multi-tenancy Support for an Electronic Contract Management Application (IEEE International Conference on Services Computing)
  • Frederick Chong and Gianpaolo Carraro, Architecture Strategies for Catching the Long Tail (Microsoft)
  • Amazon Web Services, SaaS Lens, AWS Well-Architected Framework and SaaS Tenant Isolation Strategies
  • Microsoft, Multitenant SaaS architecture and patterns (Azure Architecture Centre)
  • Google Cloud, Architecture for Multi-tenant SaaS Applications
  • Cor-Paul Bezemer and Andy Zaidman, Multi-Tenant SaaS Applications: Maintenance Dream or Nightmare? (Proceedings of the Joint ERCIM Workshop on Software Evolution)
  • The Open Web Application Security Project, OWASP Application Security Verification Standard (access-control and multi-tenancy requirements)
  • Martin Kleppmann, Designing Data-Intensive Applications (partitioning, sharding, and data isolation)