Appearance
Data isolation and deployment models: what we can honestly offer
⚠ The headline finding, before the options
📘 Owner direction 2026-08-23: document every viable deployment model so an enterprise dealer conversation is "here are the models" rather than "take it or leave it." Right, and one of the four is not ours to offer yet.
🧮 We cannot reliably keep TWO environments in sync today. Measured on 2026-08-15: a migration authored on the 14th had never been applied to Dev (QRS-693), and four archived Edge Functions were still ACTIVE on Dev six days after being archived for writing dropped tables — two of them on the money path (QRS-694). Both found by reading the live database, because nothing compares a project against the repo.
Selling a dedicated environment is selling N environments kept in sync. At N=2 we have measured drift twice in one afternoon. QRS-856.
1 · The four models, and what each one actually means on this stack
⚠ 📘 The unit of isolation on Supabase is a project — Postgres plus Auth, Storage, Edge Functions and secrets — not a database. That single fact collapses the usual middle option.
| A · Shared multi-tenant | B · Dedicated database | C · Dedicated instance | D · Fully dedicated | |
|---|---|---|---|---|
| What it is | One project, RLS-isolated tenants | A separate database, shared app | Own project + own Worker deployment | Own cloud, possibly the customer's |
| Status | 🟢 This is what exists | 🟠 Collapses into C — see below | 🟡 Buildable, gated | 🔴 Refused for now |
| Database | Shared Postgres, RLS | Separate | Separate | Separate |
| Auth | Shared | ⚠ Separate too — it lives in the project | Separate | Separate |
| Storage | Shared bucket, path-scoped | ⚠ Separate | Separate | Separate |
| Edge Functions | Shared | ⚠ Deployed per project | Separate | Separate |
| Migrations run against | 1 project | N projects | N projects | N projects |
| Secrets managed in | 1 place | N places | N places | Customer's |
| Frontend | One deployment | One deployment | Own deployment | Own |
| Marginal ops cost | ~0 | ≈ C | High | Very high |
| Suitable for | Every dealer today | — | A group with a procurement mandate | ❓ nobody we can serve |
⚠ Why B collapses into C, stated plainly because it is counter-intuitive and it kills a tier people expect
"Shared application, separate database" is the standard middle option in most stacks. On Supabase it barely exists, because a project is not a database:
- Auth lives in the project. A separate database means a separate user pool, so the same login cannot span both. 📘 That breaks the single-identity model the whole platform rests on.
- Edge Functions deploy per project. 📘 The EF is our primary write-enforcement layer, so a second database means a second copy of every function and every secret.
- Storage is per project. A second bucket, a second media base URL.
- Only the frontend bundle is genuinely shareable — and it is the cheapest part.
🔎 So B delivers ~90% of C's operational cost for ~40% of its isolation story. It is the worst value-per-rupee of the four and should not be offered as a tier. If a dealer needs a separate database, they need C.
2 · Option A: what we can actually prove about isolation
🔎 This is the most commercially valuable section on the page, and it is not the dedicated options — it is the evidence that makes them unnecessary for most dealers.
| Control | State | Evidence available in a sales conversation |
|---|---|---|
| Row-level isolation | 🟢 RLS on every user-facing table | 📘 Policies scope by relationship (workspace_id in (my_workspace_ids())), never by role alone |
| Proven negatives | 🟢 pgTAP suites | 🧮 "A logged-in user with no workspace membership can read nothing merchant-owned" is a test, not a claim |
| Least-privilege RPC grants | 🟢 gated | REVOKE ALL FROM PUBLIC + explicit GRANT EXECUTE, checked by npm run check:sql on every push |
| Table names off the wire | 🟢 convention | No supabase.from() in app code; RPC and Edge Function only |
| Write enforcement | 🟢 two layers | Edge Function primary, RLS defence in depth. Both always |
| Encryption | 🟢 platform | At rest and in transit, managed |
| Oversight privacy | 🟢 designed + proven | ⚠ An employer cannot see an employee's member_owned business, at any subtree depth |
| Backups | 🔵 managed daily | ⚠ PITR is a deferred decision, and an enterprise review will ask. Say so |
| Tenant audit trail | 🔴 does not exist | ⚠ The honest gap. See architecture validation §3.5 |
| Data deletion / DPDP | 🔵 partial | Account and data deletion is a standard; per-tenant export is a contract commitment we should make |
Sell the proof, not the iron
🔎 Most "we are not comfortable sharing infrastructure" objections are a request for evidence, not for hardware. A dealer who is shown a passing pgTAP suite that proves a stranger can read nothing, plus a written export commitment, is usually satisfied — and it costs us nothing.
⚠ Escalate to a dedicated model only when a procurement checkbox genuinely requires it, not when a technical objection can be answered. Every dedicated environment we sell is a permanent tax on a two-person team.
⚠ Two gaps to name before the dealer finds them
PITR and the tenant audit trail. 🔎 Naming a gap yourself converts it from a discovered weakness into a roadmap item, and both are cheap to close relative to a dedicated deployment. Bringing them up first is also the stronger negotiating position: it makes the isolation story credible rather than promotional.
3 · Option C: the shape, if a dealer genuinely requires it
| Element | Requirement |
|---|---|
| Database | Own Supabase project. Region chosen with the customer |
| Auth | Own user pool. ⚠ Their staff cannot also be users of the shared platform with the same login |
| Edge Functions | Deployed per project. Same code, no forks |
| Storage | Own bucket, own media base URL |
| Frontend | Same Worker build, own hostname, own environment vars |
| Migrations | The same ordered set, applied to N projects, verified by read-back |
| Monitoring | Own Sentry project or own tag. Own uptime target |
| Backups / DR | Managed daily minimum; PITR is a paid line here, not an assumption |
| Support | Named contact, stated response time, enterprise SLA |
⚠ The hard prerequisite: this cannot be sold before promotion is automated
📘 The pre-promotion checklist has seven lines, and today every one is answered by a human reading: migrations applied in both directions, the EF set equal to the repo's with no extras, secrets present, the client pointed at the right project, critical workflows passing against the target.
🧮 At N=2 that manual process has already produced two measured drifts. At N=5 it produces a customer incident. The automation is designed as QRS-696.
Prerequisite, stated as a gate: no dedicated deployment is sold until a single command can verify a target environment against the repo, in both directions, and print its output.
4 · Option D: refused, with the condition for revisiting
| What was asked | An almost entirely dedicated environment for a highly sensitive group |
| Verdict | 🔴 Refused for now |
| Why | 🔎 Self-hosting Supabase or deploying into a customer's VPC means owning Postgres, Auth, Storage, a function runtime, upgrades and CVE response for someone else's infrastructure. That is a managed-services business, not a product line, and 📘 this repo already refuses the labour businesses that do not scale past two people |
| What we say instead | "Option C gives you a dedicated database, auth pool, storage and functions in your chosen region, under a contract that names your data-export and deletion rights. Full self-hosting is not something we operate today." |
| Revisit when | Three signed Option C customers, an automated promotion pipeline, and a dedicated infrastructure engineer. All three, not any one |
5 · The version-parity strategy
📘 The owner's concern is the correct one: "avoid creating a situation where every dedicated dealership becomes a completely different codebase."
The rule, and it is a generalisation of a decision this platform already made
📘 "A new vertical is configuration, not code." Extended:
A new TENANT is configuration, not code. One codebase, one migration set, many deployment targets.
⚠ A customer-specific code fork is refused, permanently. Customer-specific configuration — feature_grants, industry composition, palette, templates, plan limits — is unlimited and free.
| Concern | Position |
|---|---|
| Version management | 📘 One release.json per release, all targets. A dedicated project is another target row, not another release |
| Releases | Shared first, then dedicated targets on a controlled window the enterprise SLA names |
| Migrations | The same ordered set everywhere. 📘 Expand-contract always — with multiple targets, a breaking change in one step is unrecoverable |
| Backward compatibility | 📘 Contraction is bounded by the oldest live app build across all targets. A dedicated tenant on a slow upgrade cycle raises that floor for everyone — ⚠ the real hidden cost of dedicated deployments |
| Feature rollout | ⚠ Needs feature flags, which do not exist (QRS-296). Without them a per-target rollout means branching code, which is the thing we refuse |
| Security patches | Applied to every target inside a stated window, ahead of the upgrade cycle. Non-negotiable in the contract |
| Bug fixes | Same code, same pipeline. No hotfix that exists only on one target |
| Customisation | Configuration only. If a request cannot be expressed as configuration, it becomes a product feature for everyone or it is declined |
| Monitoring | Per-target dashboards; one alerting path |
| DR | Per-target runbook; the same rollback mechanisms |
⚠ The cost nobody puts in the proposal
🔎 A dedicated tenant on a controlled upgrade cycle becomes the slowest clock in the platform. Every contraction — a dropped column, a narrowed type, an EF signature change — waits for them. The price of a dedicated deployment therefore has to include the option value of the schema changes it delays, which is invisible at signing and painful at the second one. This is the strongest argument for keeping the count very small.
6 · Commercial shape
📘 The owner is right that this cannot use the shared-SaaS model. 🔎 Directional only — no dedicated customer exists and no infrastructure has been quoted.
| Line | Shared SaaS | Dedicated (Option C) |
|---|---|---|
| Infrastructure | Included | ⚠ Pass-through + margin. A dedicated project with real compute is 🔎 ₹1-3 lakh/yr before support |
| Implementation | ₹59,999-2,49,999 | Materially higher — provisioning, migration, verification, cutover |
| Annual platform fee | ₹79,999-2,99,999 per outlet | Enterprise-quoted |
| Support | Standard | Named contact, response-time SLA |
| Upgrades | Continuous | Controlled window |
| Customisation | Configuration | Configuration, contracted |
| DR / PITR | Managed daily | A priced line |
⚠ The floor, so nobody quotes a number that loses money
🔎 Infrastructure alone is ₹1-3 lakh/yr, and the operational overhead — N-target migrations, N secret sets, N monitoring surfaces, a controlled upgrade window and a named support contact — is 🔎 realistically 0.2-0.3 of a person. Against ~₹1,500/h loaded that is ₹5-9 lakh/yr of labour.
A dedicated deployment below roughly ₹8-12 lakh/yr is not a premium product; it is a subsidy.
❓ Every input here is unverified. The point is not the number — it is that the number is an order of magnitude above the shared SaaS book, so a dedicated deal must never be positioned as "Complete, but isolated."
7 · The decision tree for a dealer conversation
| Signal from the dealer | Model | What to say |
|---|---|---|
| "Where is my data?" | A | Region named, encryption, proven isolation |
| "Can another dealer see my customers?" | A | 🧮 A passing test proves not. This is the strongest answer we have |
| "Our IT policy requires a separate database" | C, if the gate is met | Enterprise quote, own project, controlled upgrades |
| "We want it in our own cloud" | D → decline | Offer C with contractual data rights |
| "What if you go out of business?" | any | Export commitment, and 📘 an escrow clause if they ask (O4) |
| "Give us the isolated version at the Complete price" | ⚠ refuse | It is an order of magnitude apart. Conceding here sets the market price for every future enterprise deal |
💡 The capability this gives the sales conversation, which is the owner's actual objective
🔎 Being able to say "QR Setu supports multiple deployment models; based on your requirements we recommend this one" is worth more than any single model — it converts an objection into a qualification question.
⚠ And note the direction it usually resolves: most dealers who ask for isolation should end on Option A, because what they wanted was proof. The dedicated options exist so that the answer to "do you support it" is yes, not so that we sell many of them.
Related
- Architecture validation — every capability against the real schema
- Commercial model — the shared-SaaS book this sits above
- Persona feature map — what each login sees, whichever model is deployed