Noderax API is the NestJS control plane for the platform. It serves the web dashboard, the first-run installer, workspace-aware control-plane routes, and the remote Linux-based Go agent runtime.
Current stable release: 1.0.0
- NestJS 11
- TypeScript
- PostgreSQL with TypeORM
- Redis for pub/sub and bridge work
- JWT authentication
- Socket.IO gateways for web and agent realtime
src/
modules/
audit-logs/
agent-realtime/
agents/
auth/
diagnostics/
enrollments/
events/
metrics/
nodes/
notifications/
packages/
platform-settings/
realtime/
setup/
terminal-sessions/
tasks/
users/
workspaces/
common/
config/
database/
install/
redis/
- Installer-managed first-run setup with
setup,installed,legacy, andrestart_requiredmodes - Setup-time PostgreSQL, Redis, and optional SMTP validation
- Global user directory with platform-admin-only CRUD
- Invite-only operator onboarding with transactional email delivery
- Forgot/reset password lifecycle and authenticated password change
- TOTP MFA with recovery codes and short-lived MFA challenge tokens
- OIDC provider management with Google, Microsoft, and generic discovery-based SSO
- Workspace-aware control plane with:
- workspace listing and detail
- members and teams
- owner/admin/member/viewer roles
- default-workspace selection
- archive / restore with read-only enforcement
- protected workspace deletion rules
- Append-only platform and workspace audit logs
- Platform-level admin role:
platform_admin - User-centric membership rules:
- users are created globally first
- invited users activate through one-time links before they can sign in
- workspace memberships point to existing accepted active users
- teams are composed from workspace members only
- inactive users cannot log in or receive new assignments
- Workspace-scoped unified search for nodes, tasks, schedules, events, members, and teams
- Linux node inventory with online/offline detection, maintenance mode, team ownership, and version telemetry
- Agent enrollment with approval flow plus legacy registration compatibility
- Metrics ingestion and node telemetry persistence
- Task creation, team-targeted dispatch, batch dispatch, long-poll task claiming, lifecycle updates, and logs
- Workspace-scoped task templates
- Scheduled task creation with workspace timezone support and team targeting
- Package operations through the shared task pipeline
- Platform settings persistence through installer state, including SMTP settings validation
- Realtime updates for node state, metrics, tasks, and events
- Interactive terminal sessions over a dedicated JWT-authenticated Socket.IO namespace
- Terminal transcript persistence with ordered base64 I/O chunks, 7-day retention, and retention cleanup
- Agent realtime terminal bridge for start, input, resize, stop, opened, output, exited, and error events
pnpm installcp .env.example .envImportant values:
JWT_SECRETDB_HOSTDB_PORTDB_USERNAMEDB_PASSWORDDB_NAMEREDIS_ENABLEDREDIS_HOSTREDIS_PORTNODERAX_STATE_DIRSMTP_HOSTSMTP_PORTSMTP_USERNAMESMTP_PASSWORDSMTP_FROM_EMAILSMTP_FROM_NAMEWEB_APP_URLSECRETS_ENCRYPTION_KEY
For installer-managed deployments, NODERAX_STATE_DIR should point to a writable application-data path. For Docker, use a mounted path such as /data/noderax.
If SMTP_HOST is left blank, mail delivery remains disabled. Invite, reset-password, and operational email flows only send when SMTP is configured. In tests, the API uses JSON transport and exposes captured deliveries through the in-memory mailer service.
If you want the API to create the first platform admin automatically, set:
SEED_DEFAULT_ADMIN=trueADMIN_NAMEADMIN_EMAILADMIN_PASSWORD
pnpm start:devDefault URLs:
- API base:
http://localhost:3000/api/v1 - Swagger UI:
http://localhost:3000/api/v1/docs - OpenAPI JSON:
http://localhost:3000/api/v1/docs-json
cp .env.example .envRecommended .env values for the bundled compose stack:
NODE_ENV=production
DB_SYNCHRONIZE=false
NODERAX_STATE_DIR=/data/noderaxThen run:
docker compose up --buildServices:
- API:
http://localhost:3000 - PostgreSQL:
localhost:5432 - Redis:
localhost:6379
The provided docker-compose.yml mounts a named volume for installer state at /data/noderax.
The installer persists runtime setup into install-state.json under NODERAX_STATE_DIR.
Important behavior:
setupmode: Fresh install. The API exposes/setup/*and waits for first-time provisioning.installedmode: The installer has completed and the normal app surface is active.restart_requiredmode: Installer-managed settings were updated and a restart is needed before they fully apply.legacymode: Existing schema and env-driven installs continue to boot without installer ownership.
If the state directory is not writable, setup and platform-settings flows will warn or fail. In containers, use a writable mounted directory instead of writing under a read-only application path.
- Platform role:
platform_adminuser
- Workspace membership roles:
owneradminmemberviewer
Key rules:
platform_admincan create workspaces, manage platform settings, and manage global users.- Workspace
ownerandadmincan update workspace settings, assign existing users as members, manage teams, and delete the workspace. - Archived workspaces remain readable, but mutations, enrollment finalization, and schedule execution are blocked until restore.
- The current default workspace cannot be deleted until another workspace is selected as default.
- The current default workspace cannot be archived until another workspace becomes default.
- Workspace member creation is reference-based:
POST /workspaces/:workspaceId/membersacceptsuserIdplus role. - Team membership creation is constrained to active users who already belong to the same workspace.
- Removing a workspace membership also removes that user from teams inside the same workspace.
- Deleting a user is blocked while that user still owns workspace memberships, team memberships, or scheduled tasks.
Usersis the single source of truth for operator identities.POST /userscreates a pending invited user and dispatches a one-time activation email.POST /users/:userId/resend-inviterotates the prior invite token and sends a fresh activation email.GET /auth/invitations/:tokenandPOST /auth/invitations/:token/acceptpower account activation.POST /auth/password/forgot,GET /auth/password/reset/:token, andPOST /auth/password/reset/:tokenpower the reset flow.POST /users/me/passwordchanges the authenticated password.GET /usersremains platform-admin only.GET /workspaces/:workspaceId/assignable-usersreturns active users not yet attached to the workspace, for workspaceownerandadminplus platform admins.PATCH /users/:userIdsupports profile, role, and active-state updates with last-active-admin protections.DELETE /users/:userIdperforms hard delete only when the user has no blocking assignments.- Session invalidation is version-based. Invite accept, password reset, password change, deactivate, and role-sensitive mutations rotate
sessionVersion. - Bootstrap now repairs orphaned team memberships that no longer have a matching workspace membership.
- Teams are no longer organizational only. Nodes can be assigned to teams, and tasks can be broadcast to every eligible node currently owned by a team.
GET /audit-logsexposes platform-wide append-only audit entries for platform admins.GET /workspaces/:workspaceId/audit-logsexposes workspace-scoped audit entries for workspace owners/admins.- Nodes support maintenance mode with:
POST /nodes/:id/maintenance/enablePOST /nodes/:id/maintenance/disable- workspace-scoped equivalents under
/workspaces/:workspaceId/nodes/:id/*
Interactive terminal access is separate from the HTTP task pipeline.
- Live operator traffic uses the dedicated Socket.IO namespace
/terminal - Browser events:
terminal.attachterminal.inputterminal.resizeterminal.terminate
- Browser receives:
terminal.session.stateterminal.outputterminal.closedterminal.error
- Agent-side realtime events:
- API to agent:
terminal.start,terminal.input,terminal.resize,terminal.stop - agent to API:
terminal.opened,terminal.output,terminal.exited,terminal.error
- API to agent:
REST surface:
POST /workspaces/:workspaceId/nodes/:nodeId/terminal-sessionsGET /workspaces/:workspaceId/nodes/:nodeId/terminal-sessionsGET /workspaces/:workspaceId/terminal-sessions/:sessionIdGET /workspaces/:workspaceId/terminal-sessions/:sessionId/chunksPOST /workspaces/:workspaceId/terminal-sessions/:sessionId/terminate
Current behavior:
- Only
platform_adminusers who are workspaceowneroradmincan start sessions - Archived workspaces cannot start new sessions
- Nodes must be online and reachable through the agent realtime route
- Maintenance mode does not block terminal access
- A live session has a single controller: the creator can interact, others can inspect closed transcripts
- Transcript chunks are stored in order with a unique
(sessionId, seq)constraint - Transcript retention is 7 days
- Controller disconnect has a 5-minute reattach grace window before the session is closed
- Audit events are written for create, open, terminate request, exit, failure, and transcript retention cleanup
POST /auth/loginmay return either a normal session token orrequiresMfa=truewith a short-lived challenge token.- MFA enrollment is QR-compatible through
POST /auth/mfa/setup/initiate, then confirmed withPOST /auth/mfa/setup/confirm. - Recovery code flows are supported through
POST /auth/mfa/recovery/verifyandPOST /auth/mfa/recovery/regenerate. - MFA disable requires authenticated confirmation through
DELETE /auth/mfa. - OIDC providers are managed through:
GET /auth/providersfor public login buttonsGET /auth/providers/adminPOST /auth/providersPATCH /auth/providers/:providerIdDELETE /auth/providers/:providerIdPOST /auth/providers/test
- Public OIDC handoff routes are:
GET /auth/oidc/:provider/startGET /auth/oidc/:provider/callback
The primary task execution path is HTTP polling.
- Agents long-poll
POST /agent/tasks/claim - Agents report lifecycle with:
POST /agent/tasks/:taskId/acceptedPOST /agent/tasks/:taskId/startedPOST /agent/tasks/:taskId/logsPOST /agent/tasks/:taskId/completed
- Cancellation is observed through agent control polling
Interactive terminals are the exception to this rule: they are bridged over the agent realtime socket instead of the HTTP claim loop.
- Realtime agent sockets remain active for telemetry and lifecycle support
- Realtime task push exists only as an explicit compatibility mode and is disabled by default
All routes below are relative to http://localhost:3000/api/v1.
GET /healthPOST /auth/loginGET /auth/providersGET /auth/oidc/:provider/startGET /auth/oidc/:provider/callbackPOST /auth/mfa/challenge/verifyPOST /auth/mfa/recovery/verifyGET /auth/invitations/:tokenPOST /auth/invitations/:token/acceptPOST /auth/password/forgotGET /auth/password/reset/:tokenPOST /auth/password/reset/:tokenGET /setup/statusPOST /setup/validate/postgresPOST /setup/validate/redisPOST /setup/validate/smtpPOST /setup/installPOST /enrollments/initiateGET /enrollments/:token
POST /agent/register(legacy)POST /agent/heartbeatPOST /agent/metricsPOST /agent/tasks/claimPOST /agent/tasks/:taskId/acceptedGET /agent/tasks/:taskId/controlPOST /agent/tasks/:taskId/startedPOST /agent/tasks/:taskId/logsPOST /agent/tasks/:taskId/completed
GET /audit-logsGET /workspaces/:workspaceId/audit-logsGET /platform-settingsPATCH /platform-settingsPOST /platform-settings/validate/smtpPOST /auth/mfa/setup/initiatePOST /auth/mfa/setup/confirmPOST /auth/mfa/recovery/regenerateDELETE /auth/mfaGET /auth/providers/adminPOST /auth/providersPATCH /auth/providers/:providerIdDELETE /auth/providers/:providerIdPOST /auth/providers/testPOST /workspaces/:workspaceId/tasks/teams/:teamIdGET /workspaces/:workspaceId/task-templatesPOST /workspaces/:workspaceId/task-templatesPATCH /workspaces/:workspaceId/task-templates/:idDELETE /workspaces/:workspaceId/task-templates/:idPOST /workspaces/:workspaceId/nodes/:id/teamPOST /workspaces/:workspaceId/nodes/:id/maintenance/enablePOST /workspaces/:workspaceId/nodes/:id/maintenance/disable
GET /usersGET /users/mePOST /usersPOST /users/:userId/resend-invitePATCH /users/:userIdDELETE /users/:userIdPATCH /users/me/preferencesPOST /users/me/passwordGET /workspacesGET /workspaces/:workspaceIdGET /workspaces/:workspaceId/membersGET /workspaces/:workspaceId/assignable-usersGET /workspaces/:workspaceId/searchGET /workspaces/:workspaceId/teamsGET /workspaces/:workspaceId/teams/:teamId/membersGET /workspaces/:workspaceId/nodesGET /workspaces/:workspaceId/tasksGET /workspaces/:workspaceId/scheduled-tasksGET /workspaces/:workspaceId/eventsGET /workspaces/:workspaceId/metricsGET /workspaces/:workspaceId/nodes/:id/packages
POST /workspacesPATCH /workspaces/:workspaceIdDELETE /workspaces/:workspaceIdPOST /workspaces/:workspaceId/membersPATCH /workspaces/:workspaceId/members/:membershipIdDELETE /workspaces/:workspaceId/members/:membershipIdPOST /workspaces/:workspaceId/teamsPATCH /workspaces/:workspaceId/teams/:teamIdDELETE /workspaces/:workspaceId/teams/:teamIdGET /platform-settingsPATCH /platform-settings
GET /diagnostics/task-flow
Returns claim, realtime, and queue-health counters for the web diagnostics panel.
The API publishes web-facing realtime events for:
node.status.updatedmetrics.ingestedtask.createdtask.updatedevent.created
It also hosts the agent realtime namespace at /agent-realtime.
Recommended checks:
pnpm build
pnpm lint
pnpm test
pnpm test:e2e- The bundled installer and platform-settings flows are designed for writable persistent storage.
- Workspace-scoped routes are the primary surface for the current web app.
- Legacy env-driven installs are still supported, but new installs should prefer the setup flow.
