julian dda53bec16 Add slim Phase 1 task 1.11 (Dockerfile + Gitea workflow) for pilot deploy
- Multi-stage Dockerfile (Node 22 alpine, BuildKit cache, non-root user).
  HEALTHCHECK and metrics port (9090) deferred until task 1.10 ships;
  comments document the resume.
- .gitea/workflows/build.yml — single build job following the pattern
  of other TRM repos (no services/container, ubuntu-latest direct).
  Tests + typecheck + lint inline; image tagged :main.
- compose.dev.yaml — local-build variant for verifying Dockerfile
  changes pre-push. Production deploy lives in the sibling deploy/ repo.
- .env.example documenting all runtime env vars.
- README updated to point at deploy/ for production and explain CI.
- Task 1.11 marked done (slim variant) in ROADMAP and task file.
2026-04-30 17:31:25 +02:00

tcp-ingestion

Node.js TCP server that accepts persistent connections from Teltonika GPS hardware (FMB/FMC/FMM/FMU series), parses Codec 8, 8E, and 16 AVL frames, and publishes normalized Position records to a Redis Stream for downstream consumers.

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


Quick start (local)

Prerequisites: Node.js 22+, pnpm, a local Redis instance (or use compose below).

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

pnpm dev uses tsx watch for hot-reload during development. The server listens on TELTONIKA_PORT (default 5027).


Test the Docker build locally

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

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

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/tcp-ingestion: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 TCP_INGESTION_TAG=<sha> in the deploy stack's environment variables.


Environment variables

See .env.example for all variables with descriptions and defaults. The only required variable is REDIS_URL — all others have sensible defaults.


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, then builds and pushes the Docker image tagged :main. Auto-deploys to stage if a Portainer webhook is configured.
  • Manual trigger (workflow_dispatch): same flow, run on demand.

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.


Pilot deployment notes

This service is running in pilot form. The following tasks are paused — they are not missing by accident, they are deferred by design to get onto real Teltonika hardware first:

  • Observability (task 1.10): No /metrics, /healthz, or /readyz HTTP endpoints exist yet. METRICS_PORT is in the config schema but nothing listens on it. The Docker HEALTHCHECK is also absent for this reason.
  • Production hardening (task 1.12): Graceful shutdown is a functional stub; uncaught-exception handling is minimal.
  • Device authority (task 1.13): AllowAllAuthority is active — every IMEI is accepted. STRICT_DEVICE_AUTH=true is wired but the Redis allow-list refresher is not yet implemented.

See .planning/ROADMAP.md for the resume triggers for each deferred task.

S
Description
No description provided
Readme 225 KiB
Languages
TypeScript 98%
JavaScript 1.3%
Dockerfile 0.7%