Files
tcp-ingestion/.planning/phase-1-telemetry
..

Phase 1 — Inbound telemetry

Implement a Node.js TCP server that ingests Teltonika telemetry over codecs 8, 8E, and 16; publishes normalized Position records to a Redis Stream; and ships with the operational baseline (Prometheus metrics, fixture-based tests, Dockerfile, Gitea CI/CD pipeline).

Outcome statement

When Phase 1 is done:

  • Devices in the deployed FMB/FMC/FMM/FMU fleet connect to a known TCP port, complete the IMEI handshake, and stream AVL frames.
  • Every well-formed AVL record produces exactly one Position JSON entry on the telemetry:teltonika Redis Stream, with all GPS fields and IO element bag intact.
  • CRC-mismatched frames are dropped (no ACK) so devices retransmit.
  • Unknown-codec frames cause the connection to close with a structured WARN log entry; a Prometheus counter increments.
  • Device authority is observable but permissive by default — every handshake is labeled known or unknown based on a configurable DeviceAuthority; the Phase 1 default AllowAllAuthority accepts everything, and an opt-in RedisAllowListAuthority (task 1.13) reads a Directus-published allow-list from Redis. Strict reject-on-unknown is gated behind a STRICT_DEVICE_AUTH flag.
  • The service builds reproducibly via a Gitea Actions workflow, publishing a Docker image to the project's Gitea Container Registry, tagged by branch + git SHA.
  • Tests cover every codec parser using hex captures sourced from the canonical Teltonika doc, with at least one synthetic edge-case fixture per codec.

Sequencing

1.1 Project scaffold
   ├─→ 1.2 Core shell & framing types
   │      ├─→ 1.3 Configuration & logging
   │      ├─→ 1.4 Teltonika framing layer (incl. DeviceAuthority seam)
   │      │      ├─→ 1.5 Codec 8 parser
   │      │      ├─→ 1.6 Codec 8 Extended parser
   │      │      └─→ 1.7 Codec 16 parser
   │      └─→ 1.8 Redis publisher & main wiring
   │             └─→ 1.10 Observability
   │                    ├─→ 1.11 Dockerfile & CI
   │                    │      └─→ 1.12 Production hardening
   │                    └─→ 1.13 Device authority (opt-in, deferrable)
   └─→ 1.9 Fixture suite (cross-cutting; established alongside 1.5)

Tasks 1.5, 1.6, 1.7 can be done in parallel after 1.4 lands. Task 1.9 (fixture infrastructure) should land with or before 1.5 — it's the framework the codec tasks add to. Task 1.13 is the only Phase 1 task that can ship after the rest of Phase 1 is in production — AllowAllAuthority is functional from day one; the Redis allow-list lights up once the Directus-side publisher exists.

Files modified

Phase 1 produces this layout in tcp-ingestion/:

tcp-ingestion/
├── .gitea/workflows/build.yml
├── src/
│   ├── core/
│   │   ├── types.ts
│   │   ├── publish.ts
│   │   ├── registry.ts
│   │   ├── session.ts
│   │   └── server.ts
│   ├── adapters/
│   │   └── teltonika/
│   │       ├── index.ts
│   │       ├── handshake.ts
│   │       ├── frame.ts
│   │       ├── crc.ts
│   │       ├── device-authority.ts          (interface + AllowAllAuthority)
│   │       ├── redis-allow-list-authority.ts (task 1.13, opt-in)
│   │       └── codec/
│   │           ├── data/
│   │           │   ├── codec8.ts
│   │           │   ├── codec8e.ts
│   │           │   └── codec16.ts
│   │           └── command/    (empty in Phase 1)
│   ├── config/load.ts
│   ├── observability/
│   │   ├── logger.ts
│   │   └── metrics.ts
│   └── main.ts
├── test/
│   ├── fixtures/teltonika/
│   │   ├── codec8/
│   │   ├── codec8e/
│   │   └── codec16/
│   ├── codec8.test.ts
│   ├── codec8e.test.ts
│   ├── codec16.test.ts
│   ├── crc.test.ts
│   └── frame.test.ts
├── Dockerfile
├── package.json
├── pnpm-lock.yaml
├── tsconfig.json
├── .dockerignore
├── .gitignore
├── .prettierrc
├── eslint.config.js
└── README.md

Tech stack (decided)

  • Node.js 22 LTS, ESM-only.
  • TypeScript 5.x with strict: true.
  • pnpm for dependency management (deterministic, fast, easy to add workspaces later if needed).
  • vitest for tests.
  • pino for structured logging.
  • prom-client for Prometheus metrics.
  • ioredis for Redis Streams.
  • zod for environment-variable validation.

If an implementer wants to deviate, they must update the relevant task file first.