Sign inSign up

aixpand/backend

By aixpand

•Updated 1 day ago

A node.js backend for CAVI platform

Image
0

100K+

aixpand/backend repository overview

⁠CAVI2 Backend

Last update: 2026-10-02

⁠Need, Objective, Purpose

This service exists to operate a multi-tenant security/monitoring backend that sits between edge AI execution engines and user-facing applications.

  • Need: unify edge payload ingestion, device control, user/tenant management, and alert/event reporting in one backend.
  • Objective: provide a reliable NestJS API layer that integrates MQTT/Naeural events with persistent storage (Postgres/Oracle), cache, and object storage.
  • Purpose: support Optizone/Preventics-style deployments with configurable app mode (APP_TYPE, where Preventics uses the internal banksight tag) while keeping domain modules isolated (clients, equipment, identity, plugins, system).

⁠Usability & Features

⁠Quickstart

Prerequisites:

  • Node.js 18 (Dockerfile base image is node:18-alpine)
  • npm
  • MQTT broker access
  • Redis
  • PostgreSQL or Oracle
  • MinIO/S3-compatible storage
  1. Create environment file:
cp .env.example .env
  1. Fill mandatory configuration values (src/main.ts enforces these at startup):
  • MQTT: MQTT_PROTOCOL, MQTT_HOST, MQTT_PORT
  • Database: DATABASE_HOST, DATABASE_PORT, DATABASE_USERNAME, DATABASE_PASSWORD, DATABASE_NAME; DATABASE_DRIVER defaults to postgres and only needs to be set for oracle
  • Cache: CACHE_HOST, CACHE_PORT
  • JWT: JWT_SECRET, JWT_EXPIRATION
  • Storage: STORAGE_HOST, STORAGE_PORT, STORAGE_USERNAME, STORAGE_PASSWORD
  • Network/bootstrap: K8S_REDIS_SERVICE, K8S_REDIS_NAMESPACE, AIXPAND_* or ZxAI_* namespace/initiator/key values
  1. Install dependencies:
npm install
  1. Optional: start local dependencies via Makefile:
make check-postgres
make check-redis
make check-minio
  1. Build before migrations/runtime asset-dependent routes:
npm run build
  1. Apply migrations:
npm run typeorm:migration:run
  1. Start backend:
npm run start:dev

Other common run modes:

npm run start:debug
npm run start:prod
make dev
make debug
⁠Examples

Health check:

curl http://localhost:3000/health

Login (local strategy uses username + password):

curl -X POST http://localhost:3000/login \
  -H 'Content-Type: application/x-www-form-urlencoded' \
  --data '[email protected]&password=secret'

Token refresh (JWT-protected):

curl -X POST http://localhost:3000/token/refresh \
  -H 'Authorization: Bearer <jwt>'

Get available timezones:

curl 'http://localhost:3000/system/available-timezones?search=europe'

List report rules:

curl http://localhost:3000/report-rules/

Version metadata (requires built assets in dist):

curl http://localhost:3000/version
⁠Compact Access Tokens

New logins use signed HS256 JWTs containing sub, sid, jti, iat and exp. With the existing 36-character user UUID and ten-digit timestamps, the token is exactly 255 ASCII characters, including its full signature, so the legacy whitelist can persist it in varchar(255). The optional typ header and duplicated email claim are omitted. Read profile information from the authenticated GET /users/profile API, not from JWT claims. Both identifiers use 16 random bytes encoded as 22 base64url characters; clients must treat them as opaque.

Signature, configured expiry, current database identity/permissions and revocation checks are unchanged. Refresh preserves sid, rotates jti and still returns one Redis-elected successor with a fixed 30-second predecessor overlap. Existing signed tokens remain valid until expiry or revocation. Refreshing an existing UUID-based sid deliberately preserves it and produces a 273-character transitional token; a fresh login starts a compact session. Never truncate tokens or shorten an existing session ID to meet a column limit.

The Flutter FE still renews active sessions and ends them after 30 minutes of real inactivity. That is browser session policy, not server-side JWT expiry: background API calls do not count as activity, and JWTs keep JWT_EXPIRATION. The whitelist's missing renewal logic remains unresolved; a fitting token still expires normally. It needs a new login after this change, not reuse of expired stored credentials.

There is no per-account exception or deployment flag. Existing BE versions can verify compact tokens, but an old replica still issues oversized tokens, so whitelist persistence acceptance requires a completed backend rollout. The 255-character contract has no spare capacity for extra claims, different algorithms or longer subjects/timestamps. Tests pin the current format; the durable whitelist fix is wider token storage and proper renewal. Once that upgrade is owned and deployed, storage compatibility no longer constrains the issuer; restoring profile/header fields is a separately reviewed contract change, not a reason to remove session or token-uniqueness protections.

⁠Configuration

Configuration is loaded from .env through src/configuration.ts.

Core groups:

  • MQTT and edge network (MQTT_*, AIXPAND_* / ZxAI_*)
  • DB driver and connection (DATABASE_*, including pool settings)
  • Redis cache (CACHE_*)
  • JWT auth (JWT_*)
  • Storage (STORAGE_*)
  • Runtime behavior (APP_TYPE, DRIVERS_PIPELINE, DELETE_NAMESPACE_PREFIX, cleanup windows, websocket suppression)
  • Communications diagnostics (COMMS_LOG_LEVEL)

Mode behavior:

  • APP_TYPE allowed values: optizone, banksight (banksight is the current internal tag for Preventics).
  • Invalid/missing APP_TYPE falls back to any in local/dev, but fails fast in NODE_ENV=staging|production.
  • Plugin visibility is filtered by schema tags against app.tag and any.
  • DATABASE_DRIVER controls migration set and DB behavior independently of APP_TYPE.
  • DATABASE_DRIVER allowed values are oracle and postgres; when unset it defaults to postgres, and explicit invalid values fail fast in all environments.
  • COMMS_LOG_LEVEL is the primary comms-diagnostics knob:
    • 0: disable backend and jsclient comms diagnostics output
    • 1: periodic comms summaries every 120000ms, no NET_MON flow tracing
    • 2: high-frequency MQTT/jsclient diagnostics every 30000ms plus NET_MON flow tracing
  • COMMS_LOG_LEVEL is the only supported comms diagnostics env var; backend [COMMS:Lx] lines and jsclient [COMMS][JSCLIENT] summary cadence are derived from it.
  • When COMMS_LOG_LEVEL is unset, the backend defaults to 0.
  • Backend comms lines include the effective prefix form [COMMS:L0], [COMMS:L1], or [COMMS:L2].
  • For detailed behavior differences across deployment modes, see OPTIZ_VS_PREVX.md.
⁠Preventics on PostgreSQL

Minimal env switch from a legacy Preventics-on-Oracle deployment to Preventics-on-PostgreSQL:

APP_TYPE=banksight
# Optional: omit DATABASE_DRIVER entirely to use the PostgreSQL default.
# DATABASE_DRIVER=postgres
DATABASE_HOST=<postgres-host>
DATABASE_PORT=5432
DATABASE_USERNAME=<postgres-user>
DATABASE_PASSWORD=<postgres-password>
DATABASE_NAME=<postgres-db>
  • If the current Preventics env still contains DATABASE_DRIVER=oracle, change it to postgres or remove it entirely; PostgreSQL is now the default when the variable is unset.
  • Keep APP_TYPE=banksight; APP_TYPE=preventics is not a supported runtime value.
  • After the env switch, run npm run build and then npm run typeorm:migration:run before starting the app.

This changes runtime wiring and migration selection only. It does not migrate data from Oracle to PostgreSQL by itself.

⁠Outputs

Primary outputs produced by the backend:

  • REST API responses across auth, users/roles/permissions, clients, equipment, AI/plugin status, notifications/alerts, system tools.
  • Health data from DB/Redis/MQTT (/health).
  • Report entries (report_entry table) generated from payload rules (report_rule) in ReportsService.
  • Logs:
    • Console logs always.
    • Rotating file logs under logs/ when LOG_TO_FILE is not false.
  • Build artifacts in dist/, including copied JSON/YAML assets from src/system.

Top route groups:

  • auth: /login, /password/reset, /password/reset/:token (public), /token/refresh, /password/change (authenticated)
  • identity: /users, /roles, /permissions
  • clients: /clients, /locations, /clients/schedules, /clients/partitions, /clients/license-plate-lists, /car-registry
  • equipment: /equipment, /equipment/actions
  • plugins/alerts: /ai, /livestream, /notifications, /alerts, /notifications/live-notifications
  • system: /system/*, /translations/*, /storage/*, /blockchain/address, /version, /report-rules, /health
⁠Troubleshooting
  • App exits on boot with env errors:
    • Check required keys in .env against src/main.ts mandatory property checks.
  • npm run typeorm:migration:run fails because dist/typeorm.config.js is missing:
    • Run npm run build first.
  • /version fails with missing file:
    • Run npm run build so dist/src/system/assets/store/system/version.json exists.
  • Local Postgres in Makefile starts with unexpected credentials:
    • make postgres currently reads DATABASE_USER while app config reads DATABASE_USERNAME.
  • npm test does not run source-adjacent specs:
    • Current Jest config for this script uses rootDir: test.
  • DB-dependent verification gates are intentionally conditional:
    • Set PREVX_PGSQL_DB_READY=1 and DB env vars before running npm run verify:migrations:postgres.
  • Some controllers are public by design/implementation:
    • Endpoints without @UseGuards(...) (for example health, version, report-rules) should be protected by deployment perimeter controls if needed.

⁠Technical Details

⁠Architecture
  • Framework: NestJS 10 monorepo-style backend.
  • Entry points: src/main.ts bootstraps src/main.module.ts.
  • Global runtime behavior in bootstrap:
    • CORS enabled
    • global validation pipe
    • global logging/timeout/class-serializer interceptors
    • global HTTP exception filter
  • Data layer: TypeORM + entity auto-loading + vendor-specific migrations.
  • Messaging/integration:
    • Naeural module for network payload consumption
    • MQTT microservice client with custom serializer/deserializer
  • Scheduling: Nest Schedule for recurring jobs.
⁠Modules
  • clients: tenants, locations, schedules, partitions, license-plate lists, car registry.
  • equipment: equipment records and action dispatch.
  • identity: users, roles, permissions, password reset.
  • plugins: AI plugin status/control, payload consumers, notifications/alerts/live notifications.
  • system: auth strategies, cache/storage, reports, delete workflows, translations, websocket, version/system utilities.
  • common: guards, decorators, interceptors, pipes, helper utilities, pagination DTOs.
⁠Dependencies

Key dependencies used in runtime:

  • NestJS core modules (@nestjs/*)
  • TypeORM (typeorm, @nestjs/typeorm, pg, oracledb)
  • Redis (ioredis, @songkeys/nestjs-redis)
  • MQTT + Hyfy (mqtt, @hyfy/jsclient, @hyfy/nestjs-module)
  • Auth/security (passport, passport-jwt, passport-local, passport-custom, bcrypt)
  • Object storage (nestjs-minio, minio)
  • Validation/transform (class-validator, class-transformer)
  • Logging (winston, nest-winston, winston-daily-rotate-file)
⁠Testing

Available commands:

  • npm test
  • npm run test:e2e
  • npm run test:cov
  • npm run test:debug
  • npm run verify:runtime-policy
  • npm run verify:schema-parity
  • npm run verify:migrations:postgres
  • npm run verify:prevx:postgres

Notes:

  • npm test is configured with Jest rootDir: test in package.json.
  • E2E config is in test/jest-e2e.json and resolves TS ESM .js imports through moduleNameMapper.
  • Keep integration-sensitive changes covered with tests and validate auth/permission paths.
⁠Security
  • Authentication supports JWT and x-api-token via MultiAuthGuard.
  • Authorization uses CanGuard + permission scopes.
  • Passwords are hashed with bcrypt.
  • Tokens can be invalidated through inactive-token caching.
  • Security-sensitive controllers should explicitly use guards; any controller lacking @UseGuards is publicly callable.
⁠Build, Deploy, and Ops Notes
  • npm run build compiles TS and copies src/system JSON/YAML assets.
  • Docker image includes Oracle Instant Client setup for Oracle driver compatibility.
  • Container command runs TypeORM migrations, then starts backend.
  • GitHub Actions include semantic-version tagging (.github/workflows/semver.yml); the PREVX PostgreSQL verification workflow is currently paused as .github/workflows/verify-prevx-pgsql.yml.paused.
  • Fundamental repository change history is maintained in append-only CHANGELOG.md.

⁠Citations

Internal repo sources used for this README:

  • package.json
  • Makefile
  • .env.example
  • Dockerfile
  • src/main.ts
  • src/main.module.ts
  • src/configuration.ts
  • src/common/helpers/runtime.mode.ts
  • src/common/helpers/comms.log.policy.ts
  • src/system/version/version.service.ts
  • src/system/reports/reports.service.ts
  • src/plugins/schemas/schema.loader.ts
  • test/app.e2e-spec.ts
  • .github/workflows/semver.yml
  • .github/workflows/verify-prevx-pgsql.yml.paused
  • CHANGELOG.md

External references:

⁠License

UNLICENSED (see package.json).

Tag summary

Content type

Image

Digest

sha256:ae845cc9e…

Size

229.9 MB

Last updated

1 day ago

docker pull aixpand/backend:release-3.53.8