Skip to content

portal (admin)

apps/portal is the internal admin interface for Innerlight staff. It is a TanStack Start app (server-rendered React with file-based routing) that talks to scheduler-api via the tRPC admin surface.

Attribute Value
Framework TanStack Start (Vite + React)
Port 3030
Auth WorkOS AuthKit via @nexus/auth-client
API client @nexus/scheduler-client (tRPC, admin surface)
UI @nexus/ui (shadcn + Radix + Tailwind)
Target users Innerlight admins
sequenceDiagram
    actor A as Admin
    participant Portal as portal (TanStack Start)
    participant WOS as WorkOS AuthKit
    participant SA as scheduler-api (tRPC)

    A->>Portal: navigate to /
    Portal->>WOS: redirect to AuthKit (if unauthenticated)
    WOS->>Portal: callback with JWT
    Portal->>SA: tRPC call with Authorization: Bearer <jwt>
    SA->>SA: validate JWT (@nexus/workos-auth)
    SA-->>Portal: typed response
    Portal-->>A: render page
Route Description
/ Dashboard — platform summary
/businesses Business list + search
/businesses/:id Business detail — settings, billing, staff
/businesses/:id/provision Provision a new business (Temporal workflow)
/health Health dashboard
/health/queues BullMQ queue depths + failed jobs
/health/ci Latest CI run status per GitHub workflow
/health/railway Railway deploy status per service
/health/temporal Temporal workflow stats
/notifications Notification monitoring
/users Platform-level user management
/config Platform config toggles (money gate, etc.)

Portal imports @nexus/scheduler-client, which wraps the AppRouter type exported from apps/scheduler-api/src/trpc/router.ts. Types are inferred — never hand-written. All procedures live under admin.*:

// Example usage inside a TanStack route loader
const businesses = await trpc.admin.businesses.list.query();

WorkOS requires two separate allowlists (both must include the portal origin):

  1. Redirect URIs — where WorkOS sends the auth callback
  2. Allowed Origins — where AuthKit’s browser SDK can make requests

Missing the second causes silent /callback redirect loops with no error message.