Skip to content

ADR-0022 · Organization resource sharing ​

Status: 🟡 Proposed — authored 2026-08-08, awaiting owner approval · Amends: ADR-0020 (tenancy), ADR-0001 · Depends on: ADR-0006 (role scope), ADR-0021 (feature grants) · Related: industry scope, user ecosystem

The one-line thesis

The automotive-dealership case exposes a gap ADR-0020 cannot express: a dealership has ONE stock of cars and twenty agents selling from it. catalog_items.workspace_id forces either twenty divergent copies or zero visibility. The fix is resolution over the organization, not duplication into it — members own their data, an organization may own shared resources that members resolve as a union, and nothing is shared unless a policy flag says so.

Context ​

Car dealerships are the first planned Enterprise customer, and the requirement has two halves that must run on one foundation:

  1. Independent car sales agent — a solo business owner with their own card, own vehicle listings, own leads and customers.
  2. Dealership — a seat-based Enterprise subscription, an org admin managing agents, centralized billing, users, permissions and features, and potentially shared inventory, service, and dealership-level information.

Assessed against ADR-0020 as written, four of the five requirements already hold. One does not, and it is the one that matters commercially.

What already works, verified against the model ​

RequirementMechanismVerdict
Independent agent as a solo businessworkspaces (kind='solo', ownership_model='member_owned'), own cards row, own catalogue and Party rows✅ No change
Dealership as an enterprise tenantorganizations + org workspace + workspace_members✅ No change
Seat-based subscription, centralized billingbilling_accounts(subject_kind='organization') → subscriptions → seats → member workspaces✅ No change
Org admin controls features and permissionsTwo mechanisms, deliberately distinct — see D3✅ No change
Agent leaves the dealershipownership_model='org_owned' ⇒ seat revoked ⇒ workspace suspended, card stops resolving, leads stay with the dealership✅ No change, and correct

Three of those are worth calling out as validation rather than luck, because they follow from decisions already taken for other reasons:

  • An organization has no archetype; its member workspaces do. So a dealership can run sales workspaces (Expertise) and a service department (Time — service-appointment booking) inside one organization, with one subscription. This falls straight out of "workspace is the business tenant" and would have been impossible had archetype sat on the organization.
  • The dealership's own corporate card and each agent's card coexist — separate workspaces, one cards row each, no special case.
  • ownership_model decides who keeps the leads when an agent leaves, and it is the same column that lets an MLM distributor keep their card. A dealership does not want its lead list walking out of the door; a distributor's book is their own. One column, both requirements, no branch.

Archetype and industry are also sufficient here. A car agent is Expertise — a ₹8 lakh car is not bought on a card; the card generates the enquiry (fit test F3). Vehicle listings are ordinary Catalogue rows whose attributes carry {make, model, year, km_driven, fuel, variant, colour, registration_state, owners}. This is structurally identical to a real-estate agent, already mapped the same way — which is the archetype model working, not straining.

The gap: shared inventory is unrepresentable ​

catalog_items.workspace_id means an item belongs to exactly one workspace. For a dealership with 200 cars and 20 agents that leaves two options, both wrong:

OptionWhy it fails
Copy the inventory into each agent's workspace20 divergent copies. Worse, the exclusivity guarantee breaks: agent A sells the red Swift and agents B–T still show it available. This is the "one 3-foot idol cannot be sold five times" problem, multiplied by seats.
Keep inventory on the org's workspace onlyRLS scopes reads by workspace membership, so no agent can see it — and no agent's public card can render it.

This is a foundation-level gap, not a feature gap. It cannot be patched with a feature grant, because feature grants control whether a workflow is available, never whose data a query can reach.

Decision ​

D1 — Resolution over the organization, as a UNION. Never duplication ​

An organizations row may own shared resources. A member workspace resolves:

visible resources = own workspace  ∪  { organizations it belongs to, where sharing is enabled for that type }

One row per car. Twenty agents. Exclusivity holds by construction, because there is only ever one row to mark sold — which is precisely the argument that decides this against duplication.

It is a UNION, not an override, and that distinction is load-bearing: a dealership agent may legitimately have both dealership stock and their own privately-sourced used car on their card. This differs from the appearance resolver (ADR-0019 G4: member → org → archetype → platform, where the nearest wins) — so the two resolvers must not be implemented from a shared "org resolution" helper that assumes override semantics.

D2 — Sharing is per-resource-type, policy-flagged, and DEFAULT OFF ​

A small closed set of shareable types, each with an explicit organization policy flag:

ShareableDefaultNotes
Catalogue (inventory, price list)offThe dealership case. Also brokerage listings, franchise product sets
Location (showrooms, branches)offPairs with QRS-385
Resource (test-drive cars, service bays, staff)offPairs with QRS-386
Branding / templateoffAlready a resolver (ADR-0019); this just gives it its flag
Party (customers, leads)off, and the most sensitiveSee the warning below

⚠ Party sharing is the one that can cause real harm, so it is called out rather than listed. A dealership plausibly wants shared customer records; an MLM upline must never see a downline distributor's customers, and an employee's personal side business and consumer history must never be visible to their employer (the QRS-386 finding). Default off, explicitly enabled, and scoped per organization — never per user.

Default-off is the whole safety property. Sharing that must be switched on cannot leak by omission; the reverse can, and would do so silently, in the direction of a privacy breach.

D3 — Feature grants and RBAC permissions are different mechanisms, and the org controls both ​

The requirement "the dealership decides agents may view stock but not edit prices" is not a feature grant. Stating this explicitly because conflating the two produces exactly the tangled conditional logic ADR-0021 exists to prevent:

QuestionMechanismExample
Is this workflow available to this business?feature_grants (ADR-0021)The org's Enterprise plan includes Catalogue
Can this role perform this action on it?roles/permissions (ADR-0006)Agent has catalog:view, not catalog:edit

Both are org-controllable — feature_grants at workspace_group/workspace/workspace_member scope, permissions via roles.scope='organization'. Neither substitutes for the other, and a shared resource needs both: visible via D1, editable only per D3.

D4 — Sharing is an organization property, so it needs no new tenancy concept ​

No new table for "dealership". No dealership_inventory. The mechanism is: organizations gains sharing policy flags, shareable tables gain an owning-organization reference, and RLS gains one union clause. A dealership, a real-estate brokerage, a franchise network and an insurance agency are then the same configuration — which is the ≥3-industry test ADR-0021 requires of any structural addition, and it passes:

  • Car dealership — shared vehicle inventory across agents ✅
  • Real-estate brokerage — shared property listings across agents ✅ (very common at 5–20 agents)
  • Franchise network — shared product catalogue and pricing across franchisees ✅
  • Insurance / travel agency — shared product set across sub-agents ✅
  • MLM / direct selling — ❌ shares nothing; distributors buy their own stock. The useful negative that proves the flag is necessary rather than a default.

Options considered and rejected ​

OptionWhy rejected
Duplicate inventory per agentBreaks exclusivity — the decisive failure. Twenty copies diverge within a day.
Polymorphic owner_kind (workspace|organization) on every shareable tableComplicates every query and every policy, and the second ownership axis spreads (does media get it? analytics_events?). D1 achieves the same visibility with a resolution rule and one owner column.
catalog_shares(item_id, workspace_id) link table200 cars × 20 agents = 4,000 trigger-maintained rows that must be reconciled on every seat change. A resolution rule has no rows to drift.
Containment — member data belongs to the organizationPowerful for dealerships and fatal everywhere else: it destroys the MLM case, and it makes an employee's personal business and consumer history visible to their employer. Rejected on privacy, not on modelling.
A separate "dealership" moduleThe isolated-implementation outcome this whole architecture exists to avoid.

Long-term scalability assessment ​

The question underneath the dealership case is what relationship an organization has to its members' data, and the answer determines how far the platform scales up the customer-size curve:

ModelIndependent vendorGroup / dealershipFranchiseLarge enterpriseMLM
Isolation (ADR-0020 as written)✅❌ no shared stock❌❌✅
Containment❌✅✅✅❌ privacy breach
Resolution + explicit sharing (D1/D2)✅✅✅✅✅

One mechanism covers the whole curve, from a solo Ganapati stall vendor to a multi-showroom dealership group, because sharing is a policy rather than a shape. Extensibility is additive by construction: a new shareable type is one flag plus one union clause, and a new org tier is workspace_group rows.

It is also the fourth resolver of the same family already in the design — feature grants, appearance, capabilities, and now shared resources. Consistency here is worth more than local optimality: one mental model, one place to look for precedence bugs.

Consequences ​

Schema (additive, must be in the baseline): organizations gains sharing policy flags · catalog_items, locations, resources, parties gain a nullable owning-organization reference · every affected RLS policy gains one union clause · pgTAP proving the negative (an agent of org A can never read org B's inventory, and a member of an org with sharing off reads nothing shared).

Cost: ~+0.75d in the baseline. If deferred: changing catalog_items ownership after real inventory exists is a data migration across the table the entire public card renders from, plus a rewrite of every catalogue policy — the same class as QRS-385/QRS-387.

Accepted cost, stated plainly. Every shareable table's RLS gains a second clause, so tenant reads get marginally more expensive and the QRS-382 RLS performance discipline becomes mandatory rather than advisable — the union must be index-backed (workspace_members(user_id, workspace_id) plus an org-membership index), or shared-catalogue reads degrade exactly where the customer is largest. That is the trade: one mechanism for the whole customer-size curve, paid for with one extra indexed clause on tenant reads.

Recommendation ​

Adopt D1–D4 now, in the baseline. The dealership requirement is not a future maybe — it is the first Enterprise customer, and it is the only one of the five requirements that ADR-0020 cannot currently express. Everything else in the automotive case already works, which is the strongest available evidence that the tenancy model is right and needs one addition rather than a rethink.