Skip to content
SENS Platform Docs

Local Development

Local development must be fast, reproducible, and compatible with the production architecture.

The local infrastructure uses the same core component choices as V1:

  • PostgreSQL/TimescaleDB,
  • NATS JetStream,
  • a mock MQTT broker,
  • local dev servers for API, workers, frontend, and docs.
  • Node.js matching the root package.json engine.
  • pnpm matching the root packageManager field.
  • Docker with the Docker Compose plugin.

The repository includes .env.example with local placeholders only. Copy it to .env when ports or local credentials need to be changed:

Terminal window
cp .env.example .env

The default local ports bind to 127.0.0.1:

ComponentLocal endpointNotes
PostgreSQL/TimescaleDB127.0.0.1:5432Database sens_platform.
NATSnats://127.0.0.1:4222JetStream enabled.
NATS monitoringhttp://127.0.0.1:8222Local health and monitoring API.
Mock MQTTmqtt://127.0.0.1:1883Anonymous local broker.
platform-apihttp://127.0.0.1:3000Service operation endpoints.
mqtt-ingestion-workerhttp://127.0.0.1:3001Service operation endpoints.
telemetry-workerhttp://127.0.0.1:3002Service operation endpoints.
Dev cockpithttp://127.0.0.1:3100Local verification surface.

The default database user is sens_platform and the default local password is sens_platform_local_password. These values are safe placeholders for local development only and must not be reused for shared, staging, or production environments.

The mock MQTT broker intentionally allows anonymous local access. Its port is bound to the loopback address by default so it is not exposed to the local network.

The dev cockpit also binds to 127.0.0.1 by default. Its local configuration keys are:

VariableDefaultNotes
SENS_DEV_COCKPIT_HOST127.0.0.1Bind host for the local cockpit.
SENS_DEV_COCKPIT_PORT3100Local browser port.
SENS_DEV_COCKPIT_LOG_LINES500Buffered log lines per cockpit-run service.

These keys are local development settings only. They do not define production configuration, Helm values, or public platform behavior.

Start TimescaleDB, NATS JetStream, and the mock MQTT broker from the repository root:

Terminal window
pnpm infra:up

Show container status:

Terminal window
pnpm infra:ps

Follow logs:

Terminal window
pnpm infra:logs

Stop the local infrastructure while keeping volumes:

Terminal window
pnpm infra:down

Reset the local infrastructure and delete local Docker volumes:

Terminal window
pnpm infra:reset

The Compose project is defined in infra/docker/compose.yaml. It creates named Docker volumes for TimescaleDB, NATS JetStream storage, and Mosquitto state. pnpm infra:reset removes those volumes and destroys local data.

All three infrastructure containers define local health checks. pnpm infra:ps should show TimescaleDB, NATS, and the mock MQTT broker as healthy after startup.

The local TimescaleDB image intentionally uses the Apache-2.0 -oss edition. During first initialization, TimescaleDB may log that the internal job-history retention policy is not supported under the Apache license. The database still starts and the TimescaleDB extension is available, but automated TimescaleDB policy features such as retention or compression must not be assumed until the database phase closes the edition and licensing decision.

No object storage substitute is configured yet. Export storage is still an open design decision, so adding a local object store before that decision would create an accidental infrastructure contract.

The documentation app can be started from the repository root after dependencies are installed:

Terminal window
pnpm docs:dev

The Phase 1 workspace foundation also provides root-level commands for the current applications, services, packages, and documentation app. Phase 2 makes these commands the local equivalent of the first CI job:

Terminal window
pnpm lint
pnpm version:check
pnpm typecheck
pnpm test
pnpm build
pnpm docs:check
pnpm format

pnpm lint runs ESLint against repository JavaScript and TypeScript files. pnpm version:check validates that the root package version does not downgrade or skip release lines compared with the previous Git version. pnpm test runs Vitest and intentionally succeeds while the skeleton workspace has no tests. pnpm format checks the Prettier baseline.

Use the write command when introducing or fixing formatting:

Terminal window
pnpm format:write

Generated artifacts such as dist, .astro, coverage, and dependency directories are ignored by the formatting baseline.

Database migration commands are wired to the future database package, but Phase 1 does not define a database schema yet:

Terminal window
pnpm db:migrate
pnpm db:test:migrate

The Celestia theme is pulled from the public npm package starlight-theme-celestia.

Celestia is forced to use Tailwind CSS. The Tailwind entrypoint is docs/docs/src/styles/tailwind.css; keep it registered in Starlight customCss, otherwise Celestia utility classes will not be generated.

The docs dev server allows the local Tailscale host mac-mini-von-samuel.baboon-penny.ts.net. Additional development hosts can be passed as a comma-separated list:

Terminal window
DOCS_ALLOWED_HOSTS=another-host.example pnpm docs:dev

The dev cockpit is a local-only browser surface for checking the current technical baseline before larger platform phases are implemented:

Terminal window
pnpm build
pnpm infra:up
pnpm dev:cockpit

Open http://127.0.0.1:3100.

pnpm dev:cockpit runs the cockpit TypeScript project in watch mode and starts the compiled dist/index.js with Node.js watch mode once the first successful compile is available. Changes to cockpit source files are rebuilt without rerunning a one-shot package build manually.

The cockpit can:

  • show Docker Compose status for TimescaleDB, NATS, and the mock MQTT broker,
  • check TCP reachability for local infrastructure ports,
  • start and stop the three backend service skeletons,
  • call GET /healthz, GET /readyz, and GET /metrics for each service,
  • verify baseline Prometheus metrics,
  • verify operation-endpoint correlation ID behavior,
  • inspect structured JSON logs captured from cockpit-managed service processes,
  • run a local logger redaction self-test,
  • run allowlisted workspace checks such as pnpm test, pnpm typecheck, and pnpm lint.

The cockpit protects mutating routes with a random startup token embedded in the local page. It does not accept arbitrary shell commands and keeps only a bounded number of log lines per service.

The cockpit does not test business API behavior, login, database migrations, MQTT payload processing, decoder execution, telemetry storage, exports, Helm, or Kubernetes. Those capabilities are not implemented in the current baseline and must be introduced by later platform phases.

Build services and shared packages:

Terminal window
pnpm build

Build backend service container images locally:

Terminal window
pnpm docker:build

Local image builds use the SemVer-compatible default tag 0.0.0-local.0. Override it with SENS_IMAGE_TAG when a specific SemVer tag is needed:

Terminal window
SENS_IMAGE_TAG=0.5.0-alpha.1 pnpm docker:build

Start a built service from the repository root:

Terminal window
node services/platform-api/dist/index.js
node services/mqtt-ingestion-worker/dist/index.js
node services/telemetry-worker/dist/index.js

Each service exposes:

GET /healthz
GET /readyz
GET /metrics

Local smoke checks for platform-api:

Terminal window
curl -i http://127.0.0.1:3000/healthz
curl -i http://127.0.0.1:3000/readyz
curl -i http://127.0.0.1:3000/metrics

Repeat the same paths on port 3001 for mqtt-ingestion-worker and port 3002 for telemetry-worker.

Local defaults bind to 127.0.0.1. Future Kubernetes Helm values must set service bind hosts to 0.0.0.0 inside containers so probes can reach the operation endpoints.