julian 88cc98f3cc Switch to timescaledb-ha image; enable PostGIS in migration
Migration 0001_positions.sql now runs CREATE EXTENSION IF NOT EXISTS
postgis alongside timescaledb. PostGIS isn't used in Phase 1 but enabling
it now means Phase 2's geofence engine doesn't need a separate migration
step. The deploy stack uses the timescale/timescaledb-ha:*-all image
which ships both extensions.

Integration test (pipeline.integration.test.ts) updated to use the same
timescale/timescaledb-ha:pg16.6-ts2.17.2-all image as the deploy stack.
Stock POSTGRES_USER/PASSWORD/DB env vars retained — if recent ha-image
revisions don't accept them, the test container will fail clearly on
first run with Docker, and we'll switch to the right env-var scheme.
2026-05-01 10:39:27 +02:00

processor

Node.js worker that consumes Position records from a Redis Stream (produced by tcp-ingestion), maintains per-device runtime state, applies racing-domain rules, and writes durable state to Postgres / TimescaleDB.

For the architectural specification see ../docs/wiki/entities/processor.md. For the work plan and task status see .planning/ROADMAP.md.

This service is part of the TRM (Time Racing Management) platform.


Quick start (local)

Prerequisites: Node.js 22+, pnpm, a local Redis instance, and a TimescaleDB instance.

git clone <repo-url>
cd processor
pnpm install
cp .env.example .env
# Edit .env — at minimum set REDIS_URL and POSTGRES_URL
pnpm dev

pnpm dev uses tsx watch for hot-reload during development. The metrics server listens on METRICS_PORT (default 9090). The service connects to Redis and Postgres on startup; both must be reachable before the process starts.


Test the Docker build locally

compose.dev.yaml builds the image from source and runs it next to Redis and TimescaleDB containers. Useful for verifying Dockerfile changes before pushing:

docker compose -f compose.dev.yaml up --build

Once running, the readiness endpoint confirms everything is wired:

curl http://localhost:9090/readyz
# {"status":"ok"}

For day-to-day development, prefer pnpm dev directly — it has hot reload and faster iteration.


Production / stage deployment

This service is not deployed standalone. It runs as part of the platform stack defined in the deploy/ repo, which Portainer pulls and runs on the stage and production hosts.

The image itself is published to git.dev.microservices.al/trm/processor:main on every push to main (see CI behavior below). The deploy/ repo's compose.yaml references that image; updates flow through there, not through this repo.

To pin a specific commit in production, set PROCESSOR_TAG=<sha> in the deploy stack's environment variables.

Note: The deploy/compose.yaml will need a processor service entry and a TimescaleDB service added before this service can run in stage/production. See .planning/phase-1-throughput/11-dockerfile-and-ci.md for the expected service block shape. That is a deploy-side change for the user to make.


Environment variables

See .env.example for all variables with descriptions and defaults. Required variables:

Variable Description
REDIS_URL Redis connection URL, e.g. redis://localhost:6379
POSTGRES_URL TimescaleDB connection URL, e.g. postgres://user:pass@host:5432/trm

All other variables have sensible defaults (see .env.example).


Tests

  • pnpm test — unit tests only. Fast (~12 s), no external dependencies. This is what CI runs.
  • pnpm test:integration — integration tests that need Docker (testcontainers spins up real Redis 7 and TimescaleDB containers). Opt-in. Run locally before changes to the consumer, writer, or migration.

Integration tests live in test/**/*.integration.test.ts and are excluded from the default run by vitest.config.ts.

Without Docker

If Docker is unavailable, pnpm test:integration still exits 0 — the suite logs a skip message per test and does not fail the build. This is the correct behavior for CI runners that lack Docker access.


CI behavior

Gitea Actions workflow is at .gitea/workflows/build.yml.

  • Push to main (only when src/, test/, build config, Dockerfile, or the workflow file itself changes): runs typecheck, lint, test (unit tests only), then builds and pushes the Docker image tagged :main. Auto-deploys to stage if a Portainer webhook is configured via secrets.PORTAINER_WEBHOOK_URL.
  • Manual trigger (workflow_dispatch): same flow, run on demand.

Integration tests are not run in CI — they need Docker access on the runner, which is not currently configured. Run them locally as needed.

The workflow uses secrets.REGISTRY_USERNAME and secrets.REGISTRY_PASSWORD for the Gitea registry login — these must be configured in the repo's (or org's) Actions secrets.

S
Description
No description provided
Readme 302 KiB
Languages
TypeScript 98.7%
JavaScript 1%
Dockerfile 0.3%