Skip to content

Backend and API

Purpose

static-web-app/api/ is the main backend surface. It is an Azure Functions v4 application that exposes HTTP routes for auth, administration, telemetry ingestion, emergency workflows, diagnostics, and device management.

Entry point and module model

  • src/functions/index.js registers route modules with safe loading so one broken route file does not stop the entire API from starting.
  • Route files live under src/routes/.
  • Shared business logic lives under src/services/.
  • Shared concerns such as auth, RBAC, rate limiting, response envelopes, and DB access live under src/middleware/ and src/utils/.

Major route domains

DomainFiles
Auth and usersauth.js, users.js
Core locations/devicesbuildings.js, floors.js, zones.js, devices.js, receivers.js
Personnel and assetspersonnel.js, personnel-photo.js, assets.js, departments.js
Telemetry and RTLSiotHub.js, raddecIngest.js, positions.js, context.js, ambient.js, calibration.js
Emergencyemergency.js, communications.js, rules.js, musterPoints.js
Monitoringdashboard.js, battery.js, diagnostics.js, weather.js, health.js, analytics.js, activity.js
Gateway supportdesktopGateway.js, knotIngest.js, arubaIngest.js, phoneBeacon.js
Administrationadmin.js (BLE runtime settings, ambient config), settings.js (BLE tracking settings), audit.js (audit log reads/writes)
Platform supportrealtime.js (Centrifugo negotiate — issues HS256 JWT for the self-hosted relay), upload.js (file/image upload), docs.js (docs asset serving)
Dev/debugdev.js (development-only diagnostic endpoints)

API behavior conventions

  • Route handlers usually return the shared { success, data|error } response envelope.
  • Many endpoints are anonymous at the Functions host level and enforce auth in middleware instead.
  • RBAC uses requirePermission(resource, action).
  • Health and public routes use withPublic; authenticated routes commonly use withAuth.

Auth and RBAC

Current login paths

  • email/password login
  • Okta-backed upstream login when okta flag is provided (active — Auth0 removed)

Important current behavior

  • The backend accepts Okta login payloads ({email, name, okta: true, groups}).
  • Okta SSO is the active frontend provider via nuxt-oidc-auth.
  • JWT issuance, refresh, revocation, and permission loading are handled in backend services.

Backend service domains

Service areaFiles
Emergency orchestrationnotificationOrchestrator.js, employeeEscalationService.js, emergencyService.js, escalationScheduler.js
Real-time messagingwebPubSubService.js
PositioningtrilaterationService.js, positionSmoother.js, kalmanFilter.js
External providerstwilioSmsService.js, twilioVoiceService.js, smsService.js, voiceService.js, emailService.js, weatherService.js
Rules/automationruleEngineService.js, ruleTriggerService.js, scheduledRuleService.js
Voice IVRivrStateMachineService.js — multi-level interactive voice response for emergency calls; manages state transitions (main menu → floor capture → transfer → confirmation)
Outage detectionoutageDetectionService.js — monitors gateway heartbeats and detects power outage patterns (single gateway, building partial/full, campus-level) using configurable thresholds
Provider healthproviderHealthService.js — tracks external service availability (SMS, email, voice) and surfaces status in the emergency UI
Token managementtokenService.js — JWT issuance, refresh, and revocation

Middleware layer

Route handlers pass through middleware in src/middleware/ and auth wrappers in src/utils/withAuth.js:

FilePurpose
middleware/auth.jsJWT decode and user attachment; used by withAuth and route-level auth checks
middleware/rbac.jsrequirePermission(resource, action) — checks loaded role/permission set
middleware/rateLimit.jsConfigurable per-route rate limiting
middleware/performance.jsRequest timing and performance logging
utils/withAuth.jswithAuth wrapper (authenticated routes) and withPublic wrapper (unauthenticated routes)

Utils layer

Shared concerns in src/utils/:

FilePurpose
database.jsgetDb() — returns a pooled PostgreSQL client
response.jsrespond() helper and CORS headers; toCamelCase() and toSnakeCase() key converters
validate.jsZod-based request body and parameter validation helpers
cache.jsIn-memory and optional Redis-backed caching
constants.jsShared application-level constants (RBAC resources, scenario types, etc.)
password.jsbcrypt hashing and comparison
rpaResolver.jsResolves Bluetooth Resolvable Private Addresses (RPAs) against stored IRKs using the BT Core Spec ah() function
sniffypedia.jsSniffypedia integration — maps BLE company IDs and service UUIDs to device metadata
serviceHelpers.jsCommon patterns for service-layer error handling and retries
timestamps.jsparseKnotTimestamp(), parseBattery(), parseTemp() — normalises hardware-format telemetry strings

Storage abstraction layer

src/storage/ provides a backend-agnostic database interface. Most route files use getDb() from utils/database.js directly, but the storage layer is used for heavier query operations and exists to support potential future adapter swaps.

FilePurpose
storage/index.jsgetStorage() singleton factory — reads STORAGE_BACKEND env var (default: postgresql)
storage/adapters/postgresql.jsPostgreSQLAdapter class — wraps a pg.Pool with domain-specific query methods

PostgreSQL adapter pool configuration

The adapter is tuned for Azure B1ms hosting constraints:

SettingValueReason
max pool connections4Azure B1ms: 50 Postgres max, 10 superuser-reserved = 40 for app; 4/instance supports 10 scale-out instances
min pool connections0Pool shrinks to zero when idle to avoid exhausting the 40-slot limit
idleTimeoutMillis10 000 msRelease idle connections quickly
connectionTimeoutMillis10 000 msAzure Burstable cold-start headroom
statement_timeout15 000 msHard query timeout
SSLrejectUnauthorized: falseAzure PostgreSQL Flexible Server with self-signed cert

The adapter includes helper functions gatewayOnlineStatusSql() and gatewayLastSeenSql() to centralize the gateway online/offline determination logic used across multiple queries.

Timer triggers

In addition to HTTP routes, the Functions app registers a timer-triggered function:

FileSchedulePurpose
src/functions/auditCleanup.jsConfigurable via AUDIT_CLEANUP_CRON env varDeletes audit log records older than a configured retention window from the audit_log table

The cleanup job prevents unbounded audit table growth on long-running deployments.

Current backend coding conventions

  • CommonJS modules are the dominant pattern
  • Existing route/service files use semicolons and 4-space indentation; follow local file style instead of forcing frontend formatting rules into backend files
  • Defensive startup and runtime patterns are common: safe requires, lazy-loading, query timeouts, bounded concurrency, input validation helpers

Useful commands

bash
cd static-web-app/api
npm start
npm run lint
npm test

Backend-specific handoff notes

  • iotHub.js is central and high-risk: ingestion, receiver selection, runtime BLE settings, positioning, and realtime broadcast all meet there.
  • desktopGateway.js is the contract boundary for the Windows service.
  • Locked files exist for the IoT/ambient route area; check .claude/LOCKS.md before editing them.
  • The health endpoint reports database, cache, Azure Storage, and basic runtime metrics and is the quickest backend sanity check.

NISC Muster Tracking Documentation