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.
Prerequisites
Section titled “Prerequisites”- Node.js matching the root
package.jsonengine. - pnpm matching the root
packageManagerfield. - Docker with the Docker Compose plugin.
Environment File
Section titled “Environment File”The repository includes .env.example with local placeholders only. Copy it to
.env when ports or local credentials need to be changed:
cp .env.example .envThe default local ports bind to 127.0.0.1:
| Component | Local endpoint | Notes |
|---|---|---|
| PostgreSQL/TimescaleDB | 127.0.0.1:5432 | Database sens_platform. |
| NATS | nats://127.0.0.1:4222 | JetStream enabled. |
| NATS monitoring | http://127.0.0.1:8222 | Local health and monitoring API. |
| Mock MQTT | mqtt://127.0.0.1:1883 | Anonymous local broker. |
| platform-api | http://127.0.0.1:3000 | Service operation endpoints. |
| mqtt-ingestion-worker | http://127.0.0.1:3001 | Service operation endpoints. |
| telemetry-worker | http://127.0.0.1:3002 | Service operation endpoints. |
| Dev cockpit | http://127.0.0.1:3100 | Local 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:
| Variable | Default | Notes |
|---|---|---|
SENS_DEV_COCKPIT_HOST | 127.0.0.1 | Bind host for the local cockpit. |
SENS_DEV_COCKPIT_PORT | 3100 | Local browser port. |
SENS_DEV_COCKPIT_LOG_LINES | 500 | Buffered 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.
Docker Infrastructure
Section titled “Docker Infrastructure”Start TimescaleDB, NATS JetStream, and the mock MQTT broker from the repository root:
pnpm infra:upShow container status:
pnpm infra:psFollow logs:
pnpm infra:logsStop the local infrastructure while keeping volumes:
pnpm infra:downReset the local infrastructure and delete local Docker volumes:
pnpm infra:resetThe 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.
Documentation App
Section titled “Documentation App”The documentation app can be started from the repository root after dependencies are installed:
pnpm docs:devThe 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:
pnpm lintpnpm version:checkpnpm typecheckpnpm testpnpm buildpnpm docs:checkpnpm formatpnpm 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:
pnpm format:writeGenerated 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:
pnpm db:migratepnpm db:test:migrateThe 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:
DOCS_ALLOWED_HOSTS=another-host.example pnpm docs:devDev Cockpit
Section titled “Dev Cockpit”The dev cockpit is a local-only browser surface for checking the current technical baseline before larger platform phases are implemented:
pnpm buildpnpm infra:uppnpm dev:cockpitOpen 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, andGET /metricsfor 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, andpnpm 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.
Service Baseline
Section titled “Service Baseline”Build services and shared packages:
pnpm buildBuild backend service container images locally:
pnpm docker:buildLocal 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:
SENS_IMAGE_TAG=0.5.0-alpha.1 pnpm docker:buildStart a built service from the repository root:
node services/platform-api/dist/index.jsnode services/mqtt-ingestion-worker/dist/index.jsnode services/telemetry-worker/dist/index.jsEach service exposes:
GET /healthzGET /readyzGET /metricsLocal smoke checks for platform-api:
curl -i http://127.0.0.1:3000/healthzcurl -i http://127.0.0.1:3000/readyzcurl -i http://127.0.0.1:3000/metricsRepeat 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.