VIEWPORT
Concepts

Organizations and teams

The tenant model. Workspaces are the wall. Teams are org-local groups. Users are global with multi-org membership.

The Viewport tenant model is single-database, row-level, with workspace as the tenant. Users are global. Memberships are explicit. Teams are org-local groups. Every customer-data row carries a workspace_id and is filtered through a global tenant scope at the database layer.

If you've used Slack: same shape. One person, many workspaces, each workspace is a hard wall.

The shape

User (global)
  ├── membership → Workspace A (role: owner)
  │                  ├── Team: Platform
  │                  ├── Team: Reviewers
  │                  ├── Workflows, plans, vaults, inbox …
  │                  └── Audit log (org-scoped)
  ├── membership → Workspace B (role: admin)
  │                  ├── Team: Engineering
  │                  └── Workflows, plans, vaults, inbox …
  └── membership → Workspace C (role: viewer)
                     └── …

Workspace = the tenant

A workspace is the hard wall. It owns:

  • Members (workspace_memberships).
  • Teams (org-local groups).
  • Machines (paired daemons).
  • Workflows, plans, vaults, inbox items, runs, audit events.
  • Integrations, webhooks, settings.

Workspaces cannot see each other. Resources cannot be shared across workspaces. A team in workspace A cannot receive an ACL entry for a workspace B resource.

Internally referenced by ULID. The slug is display-only.

User = global identity

One user account per email. The same user can belong to many workspaces with different roles in each. There's no users.tenant_id. Sessions cookies are tenant-agnostic; the current org is a per-request context.

Active organization context

For every API request that touches tenant data, the platform resolves the active organization:

  1. Route binding: if the route has {workspace}, that wins.
  2. Request header: X-Viewport-Organization: <ULID>.
  3. Token claim: if the auth token is org-bound, that's used.
  4. Else: fail closed. The request is denied or the page asks the user to pick an org.

The platform verifies the actor has a membership row in the chosen org. No membership = 403 tenant_forbidden.

This means:

  • Web, mobile, CLI, daemon, integrations. They all pass org context in the same way.
  • One user can have web on org A and mobile on org B simultaneously without confusing the server.
  • API tokens can be org-bound (recommended for CI) or user-bound (require explicit header per request).

Team = org-local group

Teams are workspace-scoped collaboration groups. They're not tenants. They're ACL principals.

Rules:

  • A team has exactly one workspace_id. Cannot move.
  • Same slug can repeat across orgs (each "Platform" team is its own thing).
  • A team member must already be an org member. The platform enforces this at write time.
  • Team grants on resources are workspace-scoped: an ACL entry where team.workspace_id != resource.workspace_id is rejected.
  • Teams are never auto-created. An org starts at zero teams.

Roles

LayerRoles
Orgowner, admin, member, viewer
Teamlead, member
Resourceowner, admin, editor, reviewer, viewer

Roles compose: a workspace admin who's also a team member can do everything an admin can plus whatever team membership grants. Multiple grant paths give a user the most permissive resulting role.

The daemon's org binding

A daemon can be paired to one or more orgs. Each org binding has its own:

  • Crypto identity (separate keypair file).
  • Machine ID (different ULIDs in different orgs).
  • Install ID, runtime target ID, relay endpoint.
  • Bound directories.

So the same physical laptop can stream from ~/work to Acme and from ~/personal to Personal without either org ever seeing the other org's metadata or machine identity. See Concepts: Machines and pairing and Concepts: Trust and privacy.

What multitenancy gets you

  • Personal data stays personal. A consultant working on three clients keeps three clean inboxes, three audit logs, three sets of policies.
  • A compromise of one org doesn't cascade. Audit log compromise in Acme reveals nothing about Personal.
  • Different teams, different rules. Aggressive auto-approval for OSS, strict gates for the production org.
  • Clean offboarding. Removing a user from one org leaves their other memberships untouched.

What multitenancy does not do (today)

  • Schema-per-tenant or DB-per-tenant isolation. Single shared DB with row-level scope. If that's a non-starter for your security posture, talk to us about on-prem.
  • Org-to-org sharing. You can't share a workflow from org A into org B. Export/import is on the roadmap.
  • Cross-org search. Each org search is its own. We don't have a global "search across all my orgs."

Where to go next

On this page