MotirBuilding in public
MOTIR · moooon
onMotir
You’re viewing a public project. Anyone can view it — no account needed. Sign in to submit, upvote, or comment on requests.View-only — you can’t edit work items
MOTIR-387

6.10.2 Decision — the `Organization` model as top tier + the billing-entity decision + org roles vs 6.4 workspace roles

Done
Description

Estimate: 45m

Type: decision (the keystone ADR the schema [6.10.3], the gating [6.10.4], and every later org-aware story build against). Produce a living decision document; no app behavior ships here, but the shapes it fixes are load-bearing.

Write motir-core/docs/decisions/organization-tier.md (an ADR). It MUST fix:

  1. The new tier is Organization, NOT Better-Auth Account. State explicitly that model Account in prisma/schema.prisma is Better-Auth’s OAuth/credential auth-provider-link and is NOT a tenancy tier — the name is taken — so the root tenant tier is named Organization and its membership join OrganizationMembership (mirroring the shipped WorkspaceMembership). Record this so no one later "reuses" Account and entangles billing tenancy with auth links.
  2. The hierarchy. Organization → N Workspace → Project. Workspace today has no parent; the decision adds Workspace.organizationId (every workspace belongs to exactly one org). Cite the NESTING mirror precisely — it is Atlassian, NOT Linear: an Atlassian org has ONE OR MULTIPLE sites under it and a single account can hold access to many sites within the org, so Motir’s Organization = the Atlassian org and Motir’s Workspace ≈ an Atlassian site (verified June 2026). Linear does NOT have this nesting: a Linear workspace IS its org-root (it maps to a Motir organization, not a workspace) and Linear teams are intra-workspace groups, not workspaces — so cite Linear ONLY for billing-at-the-root (the workspace Owner holds billing; separate workspaces bill separately), never for the org→workspace nesting. Record that a single account may belong to multiple orgs (Atlassian org switcher; Linear multi-workspace), so OrganizationMembership is a many-to-many User↔Organization join, not 1:1.
  3. The org is THE BILLING ENTITY (Yue, locked). Credits + usage roll up to the Organization. Record that the ORCHESTRATOR re-keys 7.12’s CreditLedger to the org and that metering rows (PlanningRun/AgentRun) carry project+workspace+org for rollups — but that 6.10 ships no credit view and takes no dep on 7.12 (the org-scoped usage view is 7.12.5; the platform rollup is 10.1.5). This decision merely DECLARES the billing entity so the later re-keying has a home.
  4. Org roles vs the 6.4 workspace MemberRole. The 6.4 MemberRole STAYS the workspace-scoped role (unchanged in-workspace semantics). A NEW org-scoped role (OrganizationRole — owner / admin / member) sits ABOVE it: an org OWNER/ADMIN can administer every workspace under the org and the org settings/membership; an org MEMBER has org-tier presence but no cross-workspace admin. Fix the precedence rule (how an org role composes with a workspace role at an access check) — mirror Atlassian org-admin-above-site-admin / Linear Owner-above-Admin.
  5. Access gating + membership DIRECTION + the backfill semantics. Fix that org membership GATES workspace access (a workspace is reachable only by a member of its org) and the 404-not-403 cross-tenant posture is preserved. Membership direction is ASYMMETRIC (Yue): (i) adding a user to a WORKSPACE auto-creates their OrganizationMembership (role member) if absent — you cannot be in a workspace without being in its org (UPWARD auto-join, an enforced invariant); (ii) adding a user to the ORG creates NO workspace membership — a plain org member reaches only the workspaces they are EXPLICITLY added to (an org owner/admin still spans all workspaces by role, per §4), so "org-only" members in ZERO workspaces are a valid state (e.g. a billing admin). (iii) Removing from the org cascades loss of all its workspace access (the gate); removing from a workspace does NOT remove the org membership. The migration BACKFILL rule: each existing workspace gets its OWN default org (1:1, named from the workspace), every existing workspace member also becomes an org member (the upward invariant applied to legacy rows), and the seeding/owning user becomes that org’s owner — so no existing data is orphaned and the gate holds for legacy rows.
  6. Progressive disclosure + auto-provisioning (the scale principle, Yue 2026-06-13). Fix that ONE model + ONE set of surfaces serves all three scales (individual / small org / enterprise) and the UI reveals a tier only when its count ≥ 2 — so there is NO detected "individual" mode and NEVER a migration. Record: (a) signup AUTO-CREATES an org + a default workspace for every new account (a one-person company is an org of one — OPC), and the org is RENAMEABLE; (b) the ORG is always the header anchor, the WORKSPACE switcher is hidden until ws #2, the PROJECT stays in the sidebar; (c) the only two count-driven reveals are the workspace switcher at ws #2 and the org menu’s switch-org section at org #2; (d) at one workspace the workspace-settings SURFACE is hidden but the workspace tier still operates underneath — the single Settings home FOLDS IN the workspace-config sections (all workspaceId-scoped) and routes each edit to its own tier (org→Organization, config→the single Workspace); at ws #2 they split into a per-workspace Settings area with no data move. (e) There is NO org→workspace config INHERITANCE in the data model — no org-level config defaults, no override rows, no runtime resolution; config is purely Workspace-scoped. The "inherit" UX is a COPY-ON-CREATE: a new workspace is seeded by copying the source workspace’s config at creation so it opens already configured (looks inherited), after which the workspaces are independent and either can overwrite. (Real live inheritance, if ever needed for enterprise, is an additive future change, not a migration.) The visual spec is design/org-admin/design-notes.md (6.10.1); this ADR fixes the model/auto-provisioning side that the schema (6.10.3), seed (6.10.6) and UI (6.10.5) build to.

Acceptance criteria

  • motir-core/docs/decisions/organization-tier.md exists and fixes all SIX sections, naming Organization (NOT Account) and citing the mirror PRECISELY: Atlassian (org → one-or-multiple sites) for the org→workspace NESTING; Linear (workspace-root billing) for the billing-at-root half only — a Linear workspace maps to a Motir org, NOT a Motir workspace (cited, not asserted).
  • It states plainly that the org is the billing entity AND that 6.10 ships no credit/usage view + takes no dep on 7.12 (the re-keying is the orchestrator’s; the view is 7.12.5).
  • It fixes the org-role-vs-workspace-role precedence and the access-gating rule (org membership gates workspace access; 404-not-403 preserved).
  • It fixes the backfill rule (one default org per existing workspace; the owner becomes org owner; no orphan workspace).
  • It fixes the progressive-disclosure + auto-provisioning principle: signup auto-creates an org + default workspace (OPC = org of one; org renameable), the UI reveals a tier only at count ≥ 2 (no "individual" mode; org always shown, workspace hidden until ws #2), and at one workspace the Settings home folds in the workspace-config sections and routes each edit to its tier (the workspace settings still operate underneath; they split into a per-workspace area at ws #2).

Context refs

  • motir-core/prisma/schema.prisma — the existing Account (Better-Auth, do NOT reuse), Workspace, WorkspaceMembership, and MemberRole (the 6.4 role) this builds above.
  • motir-core/lib/services/ workspace + membership services + the 6.4 role/permission checks — what org gating extends.
  • 6.10.1 — the design surfaces this decision’s roles/gating drive.
  • Story 7.12 (stub) — the credit ledger the orchestrator re-keys to the org (NOT a dep of 6.10); Epic 10 (stub) — the cross-org platform console (a SEPARATE platform-staff concept).
  • Atlassian Community "Jira’s Structure — Orgs, Sites, Spaces" + Atlassian Support "types of admin roles"; Linear Docs — Workspaces, Members and roles (the cited mirror).