Appearance
Explore your first Domain
In this lesson you will walk the demo tenant that make dev seeded for you. By the end you will have read a Domain, its Projects, its identities, and its audit log from the command line, and built a working mental model of how plexsphere's tenancy fits together.
You will not change anything. This is a guided look around a known-good system — exactly the right thing to do before you start running how-to guides that do change things.
This lesson takes about fifteen minutes.
Before you start
You need the result of the first lesson, Set up your local plexsphere: a running plexsphere kind cluster and a plexctl that is built, on $PATH, and logged in. If make dev is not currently up, complete that lesson first and come back.
Recreate the shell environment from that lesson so the commands below work in a fresh terminal:
bash
export PATH="$PWD/bin:$PATH"
export PLEXSPHERE_URL=http://localhost:8080
DOMAIN_ID=$(kubectl exec statefulset/postgres -- \
env PGPASSWORD=plexsphere psql -U plexsphere -d plexsphere -tAc \
"SELECT id FROM plexsphere.domains WHERE slug='acme-corp'")$DOMAIN_ID now holds the UUID of the Acme Corp demo Domain. We will use Acme Corp throughout — Beta LLC and Gamma Cooperative are identical, so once you have done this for one you have done it for all three.
Step 1 — Confirm who you are
Every plexsphere call is made as someone, in some Domain. Ask the platform who it thinks you are:
bash
plexctl whoamiYou should see exactly one principal — the seeded admin — scoped to the Acme Corp Domain:
text
PRINCIPAL SUBJECT DOMAIN ACR AMR
user <seed-user-uuid> <acme-corp-uuid> - -This is the single most important idea in plexsphere: identity is per-Domain. The same human signing into Beta LLC would be a different principal there. Hold on to that — every step below is a consequence of it.
Step 2 — List the Domains you can see
bash
plexctl domain listThe three seeded Domains come back — Acme Corp, Beta LLC, and Gamma Cooperative — because the bootstrap job granted your seed user the admin relation on each one. A Domain is the top of the tenancy tree: nothing — no Project, no identity, no Node — exists outside a Domain.
You did not get an empty list and you did not get a permission error. That is the seed working as designed. If you did get an error, the stack is not healthy — return to Set up your local plexsphere and run the reset recipe.
Step 3 — Look inside the Domain
A Domain contains Projects. Ask Acme Corp for its Projects, then its identities:
bash
plexctl project list --domain "$DOMAIN_ID"
plexctl identity list --domain "$DOMAIN_ID"identity list shows the seeded admin@example.com user — the same identity plexctl whoami reported in step 1, now seen from the Domain's side rather than the caller's. You are looking at one fact from two directions: who am I and who is in this Domain.
Notice that every command so far has needed --domain "$DOMAIN_ID" once you looked inside a Domain. That is not boilerplate — it is the tenancy boundary asserting itself. There is no "list all Projects everywhere" call, because a Project only has meaning relative to its Domain.
Step 4 — Read the audit log
Every state-changing call in plexsphere is recorded in a per-Domain, hash-chained audit log. Read Acme Corp's:
bash
plexctl audit entries list --domain "$DOMAIN_ID"You are seeing the trail the bootstrap job itself left when it created the Domain and wrote your permissions. The audit log is per-Domain for the same reason identity is: one tenant can never read another tenant's history.
Step 5 — Cross a tenancy boundary
Re-read the same IDs for Beta LLC and re-run a list call against it:
bash
BETA_ID=$(kubectl exec statefulset/postgres -- \
env PGPASSWORD=plexsphere psql -U plexsphere -d plexsphere -tAc \
"SELECT id FROM plexsphere.domains WHERE slug='beta-llc'")
plexctl project list --domain "$BETA_ID"
plexctl identity list --domain "$BETA_ID"The Projects and identities change, because you have crossed a tenancy boundary — exactly what swapping --domain does. Every list call goes through the same /v1 API, gated by the same per-Domain permissions; there is no second source of truth behind it.
Step 6 — Ask for machine-readable output
Everything you have run prints a human table by default. Add --output json (long form only — plexctl does not bind it to -o) to get a structured payload instead:
bash
plexctl project list --domain "$DOMAIN_ID" --output jsonThe shape is always { "items": [ ... ] }. This is the form you would script against — and the bridge from "I am learning plexsphere" to "I am automating plexsphere".
What you learned
You now have a working mental model:
- A Domain is the tenancy boundary. Projects, identities, and audit history all live inside exactly one Domain and never leak across.
- Identity is per-Domain. The same person is a different principal in a different Domain;
plexctl whoamialways answers in the Domain you are scoped to. - The CLI and the
/v1API are one system.plexctlis a window onto the same data and the same permission checks the API enforces, not a separate store. - Everything that changes state is audited, per-Domain and hash-chained.
Where to go next
You have outgrown the tutorials for this topic. Pick the quadrant that matches what you need now:
- You have a job to do — invite an operator, register a node, manage Projects: the how-to guides.
- You need an exact contract — the wire shape of an endpoint, a
plexctlflag, a JSON schema: the reference, starting from the API surface map and theplexctlreference. - You want to understand why tenancy, identity, and audit are shaped this way: the tenancy bounded context and the architecture overview.