Skip to content

Instance-administrator recovery

Instance administrators can create organizations. The grant alone gives no access to an organization’s workspaces or data. First-run setup creates the initial grant. Upgrades grant it only to an existing setup actor who remains an owner or administrator of that organization. A removed or deleted setup actor leaves recovery to the installation operator.

Use the protected maintenance command on the deployed release, after migrations have completed. It requires the owner’s direct or session-pooler database URL, the correct instance configuration and the private setup code derived from AUTH_SECRET. Never run it with runtime credentials, expose it as an HTTP route, or put the code in an argument, source file or shell history.

Read the code privately on a trusted Bash terminal, then pipe it on standard input:

Terminal window
read -rs -p 'Private setup code: ' gc_admin_code
printf '\n'
printf '%s\n' "$gc_admin_code" | pnpm --filter @guestcraft/server instance-admin list
unset gc_admin_code

The migration image also ships the command. For Docker Compose, pipe the same private code into docker compose run --rm -T --entrypoint node migrate src/migrate/instance-admin-main.ts list using the installation’s normal protected environment.

Replace list with grant usr_ID or revoke usr_ID. Use an existing canonical user identifier from the team directory or installation records; this command never creates users. It prints only administrator identifiers and a count, never names, email addresses or the code. Grant is idempotent and works when there are zero administrators. Revoke is idempotent for a user without a grant and refuses to remove the last administrator, including concurrent commands. Grant the replacement first, verify the list, then revoke the departed operator.

The setup code remains a private installation-maintenance credential after browser setup has closed. Keep AUTH_SECRET, the code and owner credentials together in the installation’s restricted secret store. An operator who can read AUTH_SECRET can derive the code with setupCode from @guestcraft/server/config; do so only in a trusted administrative session. Commands never print it. Every grant, revoke and safe refusal is retained in the installation-level administrator change history, with the setup-code operator class and target identifier; malformed input, an instance mismatch and failures before the installation can be identified cannot be recorded safely. Organization membership and organization ownership are managed separately.

When a person cannot sign in and no organization administrator can reset them (they belong to several organizations, or they are the only owner), the installation operator issues a one-time reset link (ADR 0053):

Terminal window
read -rs -p 'Private setup code: ' gc_admin_code
printf '\n'
printf '%s\n' "$gc_admin_code" | pnpm --filter @guestcraft/server instance-admin reset-password person@example.com
unset gc_admin_code

The command prints the link’s expiry and the link, once. The link works once, for 60 minutes, and replaces any earlier link of the person. Send it to the person over a channel you trust; it is the only way in until it is used or expires. Redeeming it sets a new password and ends every session of the person, in browsers and on phones. Each organization of the person records the issuance as the system’s, with source: installation_operator, without the link. Two-factor and passkeys stay as they are: a person who lost their authenticator signs in with a recovery code. An unknown address answers instance_admin.user_not_found. A person gets at most 5 links an hour, counting those their organization’s administrators issue, and the command issues at most 30 an hour in all; past either, it answers instance_admin.password_reset.rate_limited: retry after N s and prints no link.