Admin panel
The admin panel is for you, the operator. It lists everyone who signed up and what they pay, and has two support tools.
Get in
Section titled “Get in”-
Put your address in
.env, several separated by commas:Terminal window ADMIN_EMAILS=you@example.com -
Restart the API, and sign up or sign in with that address. It must be verified, which is what stops a stranger from signing up with it.
-
Open the menu at the foot of the sidebar and choose Admin.
ADMIN_EMAILS is the only way in, and it is checked on every request: take an address off
and that person loses access on their next one. In production, treat those inboxes as keys to
the product.
What you see
Section titled “What you see”An overview (sign-ups in the last 7 days, subscriptions per plan, failed payments), everyone who signed up with search, and, with teams on, every workspace with its plan and subscription.
Sign in as someone
Section titled “Sign in as someone”Sign in as next to a person gives you their session, to see what they see. A banner stays up with a Stop button. It lasts an hour at most, and they notice nothing.
While you are them, you are not an admin: the panel is gone and @AdminOnly() routes answer
403. What you do is recorded in their activity log, marked
“by support”.
Suspend someone
Section titled “Suspend someone”Suspending signs them out everywhere and refuses every sign-in after. Their data stays. It does not cancel their subscription: if they pay, end it in Stripe or Polar yourself. Lift suspension lets them back in.
Routes of your own
Section titled “Routes of your own”Mark a controller or route with @AdminOnly(); everyone else gets 403. Put code that reads
across every workspace in AdminService, and admin screens in
apps/web/src/routes/_authenticated/admin.
Admin is not a workspace role. @RequireRole('owner') is about one workspace;
@AdminOnly() is about the whole product. Being an admin gives no access to anyone’s
workspace.