Core Concepts

Organizations

The top-level tenant in Project88 — what an org owns, how membership works, and how to switch between them.

An organization is the top-level tenant. Every resource in Project88 — agents, conversations, pages, data tables, canvases, provider keys, integrations — is scoped to an org.

What an org owns

  • Members with one of three roles: owner, admin, member.
  • Canvases — every app and every user-created board hangs directly off the org (no intermediate workspace layer). A protected Home canvas is auto-created with the org.
  • Provider API keys for the LLM providers you've connected.
  • Integrations (OAuth connections to Gmail, Calendar, Slack, etc.).
  • Billing planfree, pro, or enterprise. Usage is tracked in usage_logs per-org for token-based billing.
  • Display metadataicon_name (Lucide icon) and color for the picker UI.

How orgs are created

On signup we auto-create:

  1. A profile row linked to your Supabase Auth user.
  2. A personal organization ("Personal Org" by default).
  3. An org_members row making you the owner.
  4. A Home canvas inside the org (via the handle_new_org_home_canvas trigger).

This is wired up with three Postgres triggers (handle_new_user, handle_new_user_org, handle_new_org_home_canvas), so the first time you sign in you already land on a complete environment.

You can create additional orgs from the org switcher in the breadcrumb.

How membership works

Org membership is stored in the org_members table — a join between auth.users and organizations with a role column. Owners and admins can:

  • Invite and remove members
  • Edit org name, slug, icon, color
  • Manage provider keys and integrations
  • Change the billing plan
  • Toggle each canvas between org-wide and private, and manage its member list (see Canvases and widgets)
  • Delete the org

Regular members can read every org-wide canvas and create their own resources (agents, pages, data) but can't change org-level config.

When a non-owner is added to an org, every member receives a real-time notification ("<display name> joined <org>") via the notify_on_org_member_join trigger — the owner's own self-add at org creation is skipped.

Invitations live in their own table; see Members and roles.

Switching orgs

The current org is persisted to localStorage and reflected in the URL:

/:orgSlug                       — lands on Home
/:orgSlug/<appSlug>             — reserved apps (pages, data, calendar, …)
/:orgSlug/canvas-<userSlug>     — user-created canvases

Switch orgs from:

  • The org switcher in the breadcrumb dropdown (top-left).
  • The org settings modal (Settings → General).

Switching navigates to the new org's URL and reloads canvases, agents, pages, data, conversations, and provider keys.

Security & isolation

Every Project88 table has Row Level Security enabled. Policies enforce that you can only read or write rows whose org_id matches an org you're a member of. Writes that modify org-level config (members, billing, provider keys, canvas permissions) additionally check that you're an owner or admin.

For canvases, RLS adds a second gate: org-wide canvases are visible to every member, private canvases require an explicit canvas_members row. The canvas_visible_to and canvas_writable_to security-definer helpers break the cross-table recursion that pure subquery RLS would hit.

The org_members table itself uses a security-definer helper to break a recursive RLS dependency (migration 013), but the user-facing policy is still strict: you only see members of orgs you're in.

On this page