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-385

6.10 Organization (root-account) tier + org admin

Done
Description

Introduce the missing TOP tenancy tier above the workspace — the Organization (the root account a customer is, the parent of N workspaces) — and the org administration surfaces (org settings, cross-workspace member management, the org switcher in the shell). The org is the billing entity credits + usage roll up to (Yue, locked); 6.10 establishes that identity + the admin, while the org-scoped credit/usage VIEW is a later story (7.12.5) and the cross-org platform console is Epic 10 — both deliberately out of 6.10.

The model (locked — see the module header for the full rationale + the verified mirror):

  • Organization is the new root tier — NOT Better-Auth Account. The existing model Account is Better-Auth’s OAuth/credential auth-provider-link, NOT a tenancy tier; the name is taken, so the org tier is Organization. OrganizationMembership mirrors the shipped WorkspaceMembership.
  • Organization → N Workspace → Project. Today Workspace is the top tier with no parent; 6.10 adds Workspace.organizationId so every workspace belongs to exactly one org. This two-level nesting mirrors Atlassian (one org → ONE OR MULTIPLE sites; Motir Workspace ≈ Atlassian site) — verified June 2026. Linear does NOT have this nesting (a Linear workspace IS its org-root and maps to a Motir organization, not a workspace; Linear teams live inside one workspace and are not workspaces), so Linear backs only the billing-at-root half. A single account may belong to multiple orgs, so membership is a many-to-many join.
  • Org membership gates workspace access; an org owner/admin role sits ABOVE the 6.4 workspace MemberRole. The 6.4 role stays the workspace-scoped role; a NEW org-scoped owner/admin extends it (mirroring Atlassian’s org-admin-above-site-admin / Linear’s Owner-above-Admin split).
  • The org is the BILLING ENTITY. Credits + usage roll up to the org (the orchestrator re-keys 7.12’s ledger to the org separately — 6.10 records the decision, ships no credit view, and does NOT depend on 7.12).
  • PROGRESSIVE DISCLOSURE (the scale principle, Yue 2026-06-13). ONE model + ONE set of surfaces serves all three scales (individual / small org / enterprise); the UI reveals a tier only when its count ≥ 2, so there is NO detected "individual" mode and NEVER a migration. The Organization is auto-created at signup + renameable and is ALWAYS the header anchor (a one-person company is just an org of one — OPC); the WORKSPACE switcher is HIDDEN until the org has a 2nd workspace; the PROJECT stays in the sidebar. Only two count-driven reveals exist: the workspace switcher at ws #2 and the org menu’s switch-org section at org #2. At one workspace the workspace-settings SURFACE is hidden but the workspace tier still does the work underneath: the single Settings home (entered as the org’s settings) FOLDS IN the workspace-config sections (workflows/fields/labels/components/automation/dashboards — all workspaceId-scoped) and routes each edit to its own tier (org→Organization, config→the single Workspace); at ws #2 those sections split into a per-workspace Settings area, with no data move. Full spec in design/org-admin/design-notes.md (6.10.1).

Scope: the org-admin design (6.10.1); the Organization-model + billing-entity + role decision (6.10.2); the schema + migration + backfill every-workspace→a-default-org (6.10.3); the org-scoped services + access gating (6.10.4); the org admin UI — settings + cross-workspace members + the shell org switcher (6.10.5); the seed loader modelling the moooon org (6.10.6); vitest (6.10.7); e2e (6.10.8); the create-workspace flow design — the dialog + the tier-2 first-reveal (6.10.10).

CANCELLED — copy-on-create config clone (6.10.9), Yue 2026-06-14. The plan assumed org/workspace-level settings that a new workspace would inherit, but the shipped schema keys all of that config — workflow statuses, boards, custom fields, labels, components, automation rules, saved filters — to the project, not the workspace (only dashboards are workspace-scoped), and a fresh workspace has no project. So there is no workspace-level config to clone. Decision (Path B, Yue): a new workspace just starts with its OWN fresh defaults — intentionally different custom fields / components / workflow per workspace — and config is NOT copied automatically. The shipped 6.10.5 create flow is already name-only (no copy), so this needs no code change. Any future "open pre-configured" UX belongs at PROJECT create (copy settings from an existing project, Jira’s shape), not here. 6.10.9 is kept as a cancelled tombstone; the 6.10.10 design’s copy-source-picker panels are superseded (not built).

Out of scope (named so they land in their owning story, not here): the customer org usage/credit DISPLAY (7.12.5 — a forward story; wiring it here would be a forward dep, forbidden); the Motir-internal platform-staff superadmin console that reads ACROSS all orgs (Epic 10 / 10.1 — a SEPARATE platform-staff concept, not this tenant org-admin); org suspend / feature-flags / credit-grant ops (10.3); billing checkout / pricing (Epic 8).

Verification

  • Pull the Story branch; run the migration + pnpm db:seed against the local Postgres (localhost:5433).
  • The model + backfill. Confirm prisma/schema.prisma has Organization, OrganizationMembership, and Workspace.organizationId (an @relation, NOT raw-SQL-only — the CLAUDE.md FK-as-relation rule), and that the backfill migration created exactly ONE default org per pre-existing workspace and pointed each workspace at it (no orphan workspace with a null organizationId). Confirm Organization is a NEW model and Better-Auth’s Account is untouched.
  • The seed. After pnpm db:seed, the moooon org exists and owns its workspace(s); the seeding owner is an OrganizationMembership with the org-owner role.
  • Access gating. A user who is a member of an org’s workspace but NOT of the org cannot reach that workspace (gated at the org tier); an org owner/admin can administer every workspace under the org; a non-member gets 404-not-403 cross-tenant (the standing guard). The 6.4 workspace MemberRole still governs in-workspace actions unchanged.
  • The org admin UI. In the shell, the org switcher lists the orgs the signed-in user belongs to and switches the active org; org settings renders + saves; cross-workspace member management lists every member across the org’s workspaces (paginated — at-scale, NOT load-all) and can add/remove/role-change a member. Confirm there is NO credit/usage view and NO billing surface here (that is 7.12.5 / Epic 8).
  • pnpm test (6.10.7) covers the org model + the membership-gating predicate (member-of-workspace-but-not-org is denied; org-owner spans all workspaces) + the backfill (one default org per workspace, idempotent).
  • The e2e (6.10.8) creates an org, attaches workspaces, and manages a cross-workspace member end to end.
  • Dep audit. Confirm no 6.10 subtask references any id > 6.10 (no forward dep on 7.12/7.x/10.x); the billing-entity fact is prose only.
  • If every step holds, approve and merge the Story PR. If anything fails, comment with what didn’t work and Motir will produce a follow-up Subtask under the same Story.