The account owns everything
One entity, personal or organization, owns every integration, workspace and project; every table carries its id from the first migration. An organization is created instantly and proves itself later, by a DNS record.
What was on the table
The platform is multi-tenant from the start: people with their own authentication; organizations with members, roles and per-resource access; both individuals and organizations owning integrations, workspaces and projects. Two constraints shaped the model: a personal account’s integration must be private while an organization’s is shared under control — with no special case per situation — and creating an organization must not require paperwork, while still letting it prove it is the company it claims to be.
The paths we weighed
A polymorphic owner — owner_type plus owner_id on every resource.
Rejected: two fields and a branch in every query, access rules written
twice, and a transfer that becomes a migration.
Nestable namespaces with inheritance at any depth. Rejected: the hierarchy is fixed and three levels deep.
Single-user first, tenancy later. Rejected: retrofitting isolation is the expensive migration.
Everything built before returning to the product. Rejected: it delays the product that justifies the platform.
Ownership validated by national ID or a power of attorney at creation. Rejected: friction, a registry integration, and no reference product does it — GitHub and Google Cloud verify a domain, later.
No verification at all. Rejected: a shared handle namespace needs a dispute path.
What we chose, and why
An Account, personal or organization, is the single unit of
ownership. Everything owned carries an account_id and no other owner
field; a person is linked to an account by a Membership with a role; a
personal account is created with the user. A personal account’s
integration is private because the account has one member; an
organization’s is shared because it has several — no code needs to know
the difference.
The model is complete from the first migration — every entity carries account, workspace and project; every call resolves an active account — while phase one builds authentication, the personal account and the workspace → project hierarchy. Organizations, members, roles and grants arrive later without a migration.
An organization is created instantly: a name and a company registration number, which autofills the legal name and address. It verifies its domain later, optionally, by publishing a DNS TXT record. Verification unlocks exactly three things: automatic entry for anyone with an e-mail at that domain, the verified badge, and the right to contest a handle someone else holds. Everything else works unverified.
What it cost
An implicit personal account. A shared handle namespace, where verification mitigates contention but does not remove it. A larger scope before any product value — authentication, accounts, roles, grants. Personal and company registration numbers in the system, with the data protection obligations that follow. And a line worth keeping in view: controlling a DNS zone proves control of DNS, not legal representation.
Since then
The model was consolidated into one record on 2026-09-04. The invite and the second factor both rest on the account being the boundary: it is what a membership grants, and what a policy can require a second factor for.