MeridiansMeridians

platform-and-people

From the Meridians Wiki · Public · Maintained · joint


Platform, instances & people (the roadmap vocabulary)

The platform (the shipped Hosted runtime + control-plane / desktop-app epics; see Gateway 🔒) turns on a small set of words that are easy to overload. This is the canonical set — use exactly these; the collisions below are resolved on purpose.

People — four layers, two of them collide by name (resolve by layer + case):

  • user — a person. At the platform layer, one auth.users row (Supabase). The base unit; every other word below is a role a user plays.
  • member — a user's presence inside one instance: an instanceMembers identity record. It carries sign-in details, not an editable access assignment. "A user is a member of an instance."
  • role — the capability ladder (low→high): guest < viewer < contributor < manager < director. Non-Director roles are assigned at constellation or domain scope and enforced by permissions.ts plus the effective-role resolver. These are instance roles, not platform roles. (The manager role was renamed from "admin" so that "admin" is free for the platform layer — see below. There is no in-instance "admin".)
  • Director (capital-D — platform account) vs director (lowercase — in-instance role). The platform Director is a user with a gateway account (directors, Supabase) that owns product subscriptions. The director role is the top rung of the ladder — the sovereign of that instance. They coincide (the account owner is their instance's director) but name different systems (Supabase directors vs the master's instanceMembers). Disambiguate by case + "platform Director" / "director role".
  • manager (in-instance role) vs Admin (platform operator — us). manager = the ladder role just below director inside one instance (the director's deputy: manages people + edits the model, minus hosting/sovereignty). Admin = the platform operator, a platform_admins row — the business admin over all accounts (the gateway /admin). Never conflate — "Admin" is always the platform; "manager" is always an in-instance role. (Under a director you have a Manager, not an "admin".)

Instances — two orthogonal axes (never collapse them):

  • instance — one running Meridians host, sovereign over its own record.
  • Axis 1 · runtime authority (getSyncRole; after E1, the server-of-record):
    • master — the authoritative record-holder. Shipped: the Director's browser on localhost/Electron. After E1: the server daemon (the forked Next server — local or on a VM). One master per instance.
    • client — a renderer that reads from a master over a transport: the local renderer, or a remote browser that joined over the tunnel. Retired synonyms — do not use for the sync role: clone, tributary. ("clone" survives only for duplicating a domain/scene, never the role.)
  • Axis 2 · product / where the master runs:
    • License — the master runs as an Electron app on the user's own machine (local; BYOK keys; the cheap flat plan). The electron/ roadmap.
    • Hosted (VM) — the master runs on a Fly VM we provision (always-on; platform-supplied and metered provider services; pricier). The gateway/ roadmap. Avoid "Managed" as the product name (ambiguous) — say Hosted.
  • Orthogonality (the key unification): master/client is runtime authority; License/Hosted is where the master runs + who pays/keys. A master is the record-holder whether it's a local Electron (License) or our VM (Hosted); collaborators are clients in both. A user can hold License AND/OR Hosted — products are per-subscription (hasLicense / hasHosted), never a field on the account.

Gateway & control plane (the C0–C2 vocabulary):

One codebase, two deployment modes — the mode decides which surfaces exist (src/proxy.ts → the pure routeForDeployment policy is the one enforcement point):

  • gateway — the control-plane deployment (meridians.global, MERIDIANS_GATEWAY=true): central auth (Supabase) + billing (Stripe) + the business consoles (Users / Devices) + Host + Explore. It mounts no store / IndexedDB / instance surface (ThemeProvider only) and runs none of the instance's sync/record machinery. Say gateway, not "the site" / "the portal".
  • instance — a running Meridians app (the workspace): the Director's Electron app, a hosted VM, or a plain web deploy. Canonical word: instance. Retired synonym: tenant — it survives only in legacy filenames (tenant-guard.ts, tenant-auth.ts); never write "tenant" in new copy, docs, or identifiers. Avoid "host instance" as a noun too — host is reserved for the tunnel-hosting role (an instance that runs the broker + ngrok so clients can join); say "instance" and add the role only when the tunnel is the point.
  • instance typeelectron | hosted | web (detectInstanceType). The product that unlocks each: Electron ← License, hosted VM ← Hosted; platform owner/admin run either free. Say "Electron instance (License)" / "hosted instance (Hosted)" — never "license instance".
  • control plane — the gateway's API surface consumed by instances (/api/account|admin|billing| directory|entitlement). Instances call it only when controlPlaneEnabled() (a gateway URL is configured AND the build is production) — never in development, and never during sign-in. Auth is local-first; the control plane is a separate, non-blocking layer (entitlement verdicts + device telemetry) applied after a Director is signed in.
  • central auth — Supabase authentication, Directors only (Google or email + password). Members never touch it: they sign in with a local PIN/password and ride the Director's window. A local Director record linked to its central account is centrally linked (centralLinked). The Director's email/mobile are owned by the gateway — instances mirror them read-only and re-sync on every auth event (centralIdentityPatch); the instance edits display names only.
  • platform rolesowner > admin (the platform operators — free access to every product) · Director (a paying account) · guest (signed up, no plan). Resolved by resolveRole from platform_admins + subscriptions. Distinct from instance roles (the guest→director ladder above) — "Admin" is always the platform, never an in-instance role.
  • entitlement / the window rule — entitled while actively subscribed or still inside the paid-through period (isEntitled); canceling keeps access until the period ends, and every member of the instance rides that same window. Offline, a cached verdict is trusted for the grace ceiling (14 days), then the app must re-check.
  • device / access point — one row in access_devices: a host (an instance that checked in) or a member seat riding it, with server-observed IP + browser/region. Written by the heartbeat, admin-only visibility (the gateway Devices console). Telemetry, never an auth factor.
  • hand-off — the C2 §5 one-time token that lets an instance's "manage account" link land on the gateway already signed in (same Supabase project, different origin). Specced, not yet shipped — today the profile link opens /account and the user signs in there.

Activity classification — category vs area (two axes, never conflate)

Every reducer action is classified on two orthogonal axes in action-policy.ts:

  • action categorywho may do this: the permission lattice (view/sync/game/learn/ contribute/people/membership/extraction/extension/edit/delete/constellation) that canDispatchAction gates on. Authority only — never use it as an analytics lane.
  • activity areawhat the person was doing: the intent lane the activity log records and the Usage page swimlanes on. Eleven areas: world (editing the domain artifact), opinion (streams, priors, merges, projections, readings, notes, perspectives), research (Watch: loops, runs, the source catalog, articles), chat, extraction (new-domain/extension jobs), learning, program (the machine loop + auto mode), game, constellation (feed/newsletter/editorial), governance (members, roles, boundary changes, deletion), access (sign-ins/outs, session resumes, presence). Derived per action as category-default + explicit override (actionArea); pre-area history re-lanes at read time from the entry's stored