Chelabase

Studio tour

What each Studio screen does, from signing in to the Table editor and the SQL editor.

Studio is Chelabase's web app. In a local stack it runs at http://studio.chelabase.localhost:8000 (just workbench up starts it). Everything it does goes through the gateway on :8000 with your member access token, so anything you can click you can also do through the Management API (the reference is in Studio's API page and under Reference in these docs).

Open Studio at studio.chelabase.localhost:8000, not an IP address: the gateway routes by host name, and the sign-in redirect and the gateway's CORS origin are registered for that host.

Signing in

Studio has its own sign-in pages: /login, /register, /accept-invite, /verify, /password-reset, /pending and /logout. They call the auth service through the gateway (/auth/v1/*); the session and the step state live in encrypted HttpOnly cookies, and Studio holds only a short-lived token in memory (Identity service). The Quickstart walks through signing in as the bootstrap admin.

  • Self-hosted mode (the default, CHELABASE_MODE=self-hosted) takes no self-sign-up unless a tenant admin switches it on (PATCH /v1/instance/settings with open_signup). The first admin is whoever claims the instance with the setup code (Install); an admin invites everyone else, by an email, or by a link to hand over when no SMTP server is configured (GET /v1/invites/delivery says). The sign-in page offers Create account only while sign-up is open, and always says "No account? Ask your admin for an invite" otherwise. Platform mode takes no self-sign-up yet.
  • With sign-up open, a new person is a pending member who can do nothing until an admin approves them (approveMember, with their first grants) or declines them. Sign-ups are created with the email already verified in self-hosted mode; set CHELABASE_REQUIRE_EMAIL_VERIFICATION=true to require a code (codes and password-reset emails land in Mailpit at http://mail.chelabase.localhost:8000); =false turns it off in any mode.
  • A sign-up for an email that is taken says so and sends you to sign in.
  • Everyone who joins is in the same tenant: a shared team workspace, by design for self-hosting. An admin can give the tenant a display name (PATCH /v1/tenant); the invite page and GET /v1/me use it, falling back to the slug.

Projects

The dashboard lists your tenant's projects, with New project. Opening a project shows three tabs:

  • Databases: the project's databases and a form to create one.
  • Users: the project's app users. It appears once app users are enabled.
  • Settings: the project name, App users (enable, change or disable) and a danger zone that deletes the project and every database in it.

Databases

The Databases tab lists each database with its status and endpoint. Connection details shows the owner's host, port, user, password and URI; Reset password sets a new owner password; Delete destroys the database with all its branches and data (you type its name to confirm). The five buttons on a row open a panel under it, once the database is ready:

  • Branches: the branch tree with each branch's status and endpoint, a form for a new branch, and the database's settings (history window, branch limit, max rows, statement timeout, max connections). Each branch has Connection details, Reset password, Protect or Unprotect, Reset to parent, Restore, Delete branch, Roles and, with a parent, Merge into and Update from it (see Merging schema). A disabled action says why next to the buttons; while a schema merge holds the branch, a link opens the merge. See Branches and Login roles.
  • Merges: the database's schema merges, newest first, each opening its merge page.
  • Data API: the endpoint, the public key (with Rotate public key), secret keys, and per-database access. See Data API.
  • Tables: opens the Table editor.
  • SQL: the SQL editor.

RLS warning

The Data API panel lists every table, view or foreign table that anon or authenticated can reach without row-level security protecting it, with a button to copy the SQL that fixes it:

  • a table with RLS off: ALTER TABLE … ENABLE ROW LEVEL SECURITY;
  • a view that runs with its owner's rights: ALTER VIEW … SET (security_invoker = true);
  • a materialized view or foreign table, which can't have RLS: REVOKE ALL … FROM anon, authenticated.

It also names the app users table while its RLS is off, even before any role can reach it, because the table holds your users' emails.

Table editor

The Table editor in the left rail browses and edits rows and changes table structure. See Table editor. Rows are read and written through the console endpoint below.

Over the API, the console is POST /v1/databases/{id}/branches/{branch_id}/console/query with:

{ "role": null | "<role>", "database": null | "<name>", "tree": <a data API request> }

role is null (the owner) or a role name, database is null (the branch's main database) or a Postgres database name, and tree is a data API request, the JSON that POST /data/v1/query takes (see Data API). Every operation is allowed, batches included, in one transaction with the data API's max_rows and statement timeout. The answer is the data API's.

  • As the owner (role: null, Studio's default): the orchestrator runs the request itself, on a small pool per branch and database (at most 2 connections, closed after 60 seconds idle), with the owner password it holds. Row-level security doesn't apply to the owner. rest never sees the owner's password. When the owner's password was set in SQL, Chelabase doesn't know it: the answer is 409 owner_password_unknown until you reset it (Reset password, or POST …/branches/{branch_id}/reset-password), which works at once.
  • As another role (anon, authenticated, a plain role you made): the worker checks the role the first time (the result is remembered for five minutes) and grants it to authenticator; rest then runs the request as that role. An owner-level role (a superuser, or one with CREATEROLE, CREATEDB or REPLICATION, or a neon_superuser member), or one that doesn't exist, is refused: 403 role_refused, saying why. A role with BYPASSRLS alone is allowed and reads past row-level security. A role dropped after its check answers 503 unavailable for up to 30 seconds, then 404 unknown_role.
  • Errors: a Postgres database that isn't served is 409 data_api_disabled (Studio offers Enable data API); one that doesn't exist is 404 not_found; everything else is the data API's code. See Error codes.
  • Audit: every write is logged at info (platform user, branch, database, role, operation kind), never the values.

API reference

The API link in the header opens the Management API reference, with a Try it out that uses your signed-in token. Nothing on that page calls an outside service.

How Studio behaves

  • Lists refresh every 2 seconds while a database or branch is pending, provisioning, resetting or deleting, and stop when the status settles.
  • A write refreshes exactly the data it changes.
  • Secrets (connection details, passwords, created or rotated API keys) never enter Studio's query or mutation cache or any stored state. They live in the open panel and disappear when it closes. Keys are shown once, at creation or rotation.
  • The SQL editor keeps its run history, open buffer and timeout in your browser's localStorage.
  • Studio is English-only and light-only today.

On this page