Tenancy & IA · decision brief for ADR 0040

How should orgs, spaces, teams & sharing work?

Grounded in how Notion, Linear, Slack, Confluence, Google Drive & GitHub actually model this (live-verified June 2026). editorzero already commits to per-doc granular ACLs, one-audit-entry-per-mutation, and humans + AI agents as peer principals — so the container can’t be the only source of access. The real fork is how strong the Space ceiling is. This page lays out the vocabulary, three candidate models, and your exact scenarios.

Org (tenant) Space (membership boundary) Personal (private) Agent principal Guest grant (item-scoped)

01Vocabulary — one cohesive set

OrgThe self-hosted deployment. One by default (multi-org stays possible later). Holds the member directory + all agents. ≈ Notion workspace / Linear workspace.
MemberA human in the org directory — a full principal who can be added to Spaces & Teams.
AgentAn AI principal in the org. Receives grants exactly like a member (peer), with its own attribution, rate limits & revocation.
SpaceA membership boundary inside the org — a team’s shared home. Has members (+ Teams) and a default access baseline. Types: Open · Closed · Private.
PersonalEach member’s private Space (owner-only by default). Drafts & scratch live here; promote by moving into a shared Space. (The thing Linear lacks.)
CollectionA folder tree inside a Space. Pure navigation in v1 — it holds no ACL of its own (so a move between Collections in the same Space changes nothing; collection-level grants are reserved). The existing collections table.
DocThe leaf. Carries its own ACL (inherits the Space baseline — Collections add no ACL; can narrow within the Space, or widen past it only via an explicit guest grant).
TeamA named group of members used as a grant target — grant a Team access to a Space / Collection / Doc. ≈ Notion groups / GitHub teams.
Guest grantAn item-scoped ACL entry to a principal outside the Space — the only way to widen past the ceiling. Enumerable, revocable, audited.
PublishAn independent visibility dimension on a Doc (public-read link / published site) — orthogonal to the ACL. A “guest editor” = a guest grant with edit on a published doc.

02The three candidate models

A · Flat org + per-doc ACL

simplest
Org · everyone is a member
Collection (folder — nav only)
Doc · ACL
Doc · ACL
Doc · ACL
Solo & very small teams
Dead simple; matches per-doc ACL literally
“What can Alice see?” = walk every doc
No team homes; big orgs drown in per-doc grants
No membership grouping to onboard/offboard against

B · Org → Spaces + Personal

recommended
Org · member directory + agents
Space “Product” · members = baseline (ceiling)
Collection → Docs
Doc · ACL ≤ ceiling
Personal (Alice) · owner-only
private drafts
Agentgranted like a member
Guest grant1 doc, cross-boundary
Solo → small → big org, one model
“What can X see?” = Space members − narrowing + listed guest grants → bounded & auditable
Clean cross-boundary + guest + publish story
Matches the brand IA (“Spaces”) & today’s schema
More concepts; needs the guest-grant escape hatch so the ceiling isn’t rigid

C · Multi-workspace tenancy

today / heavy
Deployment
Workspace A (tenant)
tree
Workspace B (tenant)
tree
↕ cross-workspace = federation (v2+)
Agencies / true multi-customer isolation
Hard isolation; least change from today
Solo→team & “share one doc out” get awkward
Identity/agents duplicated per tenant
Over-built for one self-hosted org
The one decision that’s yours to make. In Model B, is a Space a hard ceiling (Confluence-style: doc ACLs can only narrow inside a Space; the only way to grant a non-member is an explicit guest grant) — or a soft baseline (Notion-style “broadest-wins”: any grant anywhere can widen)?

My recommendation: hard ceiling + guest-grant escape hatch. With agents mutating ACLs programmatically, “can principal X read doc Y?” must stay a local, provable lookup. A soft baseline makes it a whole-graph walk — un-auditable at machine speed. The hard ceiling keeps it bounded; the explicit guest grant keeps it from feeling rigid (and is itself an audited, revocable, enumerable row).

03Your scenarios — how Model B handles each

ScenarioWhat happensMechanismvs A / C
1 · Solo userSign up → your Personal space. Everything private to you. No Spaces needed yet.Personal spaceA: same (a folder). C: a whole workspace just for you — heavy.
2 · Personal that expandsInvite a collaborator → create a Space, move drafts in. Personal stays private; shared work lives in the Space.move Personal→SpaceC: must spin a new tenant + re-add identity. Linear: no personal stage at all.
3 · Small team: shared + privateTeam works in one Space (all members see all its docs). Each person also keeps a Personal space for private drafts.Space baseline + PersonalLinear can’t do private drafts; Notion can. A: no “all team sees all” default.
4 · Private doc → share with specific peopleDoc in your Personal space → add a grant to specific people (or, when they sit outside the Space, a guest grant). They see just that doc.item grantAll hybrid tools do this; the ceiling keeps it from leaking siblings.
5 · Cross-space sharingDoc lives in Space A; share with someone in Space B (or no space) → guest grant. They don’t join Space A; it appears in their “Shared with me.” This is the one widening past the ceiling.guest grant (item ACL)Confluence forbids this (must grant space access). Notion/GitHub/Google allow it as an item grant — we copy that, audited.
6 · PublishingFlip the Doc’s publish dimension → public read at a slug. Independent of who can edit. Publish/unpublish are audited capabilities (already in your schema).publish dimensionLinear has no native publish; Notion/Coda/Google treat publish + edit as independent — we do too.
7 · Guest editors (on a published doc)Published doc that needs outside editing → guest grant with edit to a specific external principal. Public still reads; the guest edits just that doc.guest grant · edit= Notion guest + publish, composed. Bounded blast radius (Linear: shared item can’t re-share — copy that).
8 · Invite an org guest (future)A Guest principal lives in the org directory but is not a member — sees only what it’s explicitly granted (item/space). Distinct from a full member.guest principalSlack’s clean split: a guest is yours (your audit/revocation), not federation. Agents reuse the same scoping.

04Drag-and-drop reorg — fixing the universal footgun

Every tool we studied silently mishandles moving content across a permission boundary — Google drops inherited shares with no warning; Confluence applies the new parent’s permissions (they patched a CVE for it); Notion re-privatizes the parent but strands subpages. Nobody prompts well.

Because editorzero has per-doc ACLs and audits everything, a move becomes a first-class, reconstructable event — not a silent side effect.

Within a SpaceReorder / move freely — no ACL change. Drag is pure nav. Instant, no prompt.
Across a boundary (Space↔Space, Personal↔Space)An explicit, audited ACL transition. The UI prompts: “adopt the destination Space’s baseline” vs “keep this doc’s own grants.” Never silent.
InvariantA doc inside a private Space stays private until its publish dimension is explicitly flipped — privacy tightens downward, publish is the one deliberate, audited exception (Linear’s rule; property-tested).

05How this maps onto what’s already built

Model B is mostly a repositioning, not a rewrite, of today’s schema (architecture §3):

workspacesBecomes the Space (membership boundary). The single-Org wrapper sits above; multi-org stays the reserved evolution axis (ADR 0024) — not v1.
workspace_membersBecomes Space membership (role per principal). Already the SSOT for roles (ADR 0024). Gains Teams as a grant-target grouping (a reserved axis).
collections / docsUnchanged tree. docs.visibility (workspace|public|private) generalises to the ACL + publish dimension.
Personal spaceThe auto-minted-on-signup workspace (ADR 0024) is the Personal space — keep it, reframed as a private default, not a separate tenant.
agentsAlready first-class principals (ADR 0016) — they become grant/guest-grant targets with no new principal kind.
Guest principalNew: a directory entry that is not a member. The reserved “platform-admin / membership evolution” axis in ADR 0024 already anticipated this shape.

Sources (live-verified June 2026): Notion sharing & permissions, teamspaces, guests · Linear conceptual model, private teams & issue-share, members & roles · Slack guest roles · Confluence permissions · Google shared drives · GitHub outside collaborators. Research runs: 3 Opus agents (Notion / Linear / cross-tool).