# Task 1.1 — Project scaffold **Phase:** 1 — Inbound telemetry **Status:** ⬜ Not started **Depends on:** None **Wiki refs:** `docs/wiki/sources/teltonika-ingestion-architecture.md` § Project location and layout ## Goal Initialize the Node.js / TypeScript project with the directory layout from the wiki, install the agreed tooling, and produce a "hello world" `main.ts` that the rest of Phase 1 builds on. ## Deliverables - `package.json` declaring: - Type: `"module"` (ESM only). - Engines: `"node": ">=22"`. - Scripts: `build`, `dev`, `start`, `test`, `test:watch`, `lint`, `format`, `typecheck`. - Dependencies (production): `ioredis`, `pino`, `pino-pretty` (dev-only via NODE_ENV check), `prom-client`, `zod`. - Dev dependencies: `typescript`, `@types/node`, `vitest`, `@vitest/coverage-v8`, `eslint`, `@typescript-eslint/parser`, `@typescript-eslint/eslint-plugin`, `prettier`, `tsx` (for `dev` watch). - `tsconfig.json` with `strict: true`, `target: ES2022`, `module: NodeNext`, `moduleResolution: NodeNext`, `outDir: dist`, `rootDir: src`, `declaration: false`, `noUncheckedIndexedAccess: true`. - `eslint.config.js` (flat config) with `@typescript-eslint/recommended-type-checked` plus a small project-specific allow-list. - `.prettierrc` — 2 spaces, single quotes, no semis at line end OR keep semis (pick one and stay consistent — recommend keep semis to match Node convention). - `.gitignore` — `node_modules/`, `dist/`, `coverage/`, `.env`, `.env.local`, `*.log`. - `.dockerignore` — same as `.gitignore` plus `.git/`, `.planning/`, `test/`, `*.md` except `README.md`. - Empty directories with `.gitkeep` files where Phase 1 will fill them in: - `src/core/`, `src/adapters/teltonika/codec/data/`, `src/adapters/teltonika/codec/command/`, `src/config/`, `src/observability/` - `test/fixtures/teltonika/codec8/`, `test/fixtures/teltonika/codec8e/`, `test/fixtures/teltonika/codec16/` - `src/main.ts` — minimal stub: imports a logger (placeholder until task 1.3), prints "tcp-ingestion starting" and exits with code 0. - `README.md` — short description pointing at `.planning/ROADMAP.md` for the work plan, and at `../docs/wiki/` for the architectural specification. ## Specification - **Package manager:** pnpm. Commit `pnpm-lock.yaml`. The Dockerfile in task 1.11 will use `pnpm fetch` for layer-cache friendliness. - **Module style:** ESM throughout. No CJS interop hacks. All files use `import`/`export` and `.js` suffix on relative imports per Node ESM resolution rules. - **TypeScript path style:** Use relative imports for now. No `paths` aliases — they add a bundler dependency at runtime that we don't want. - **No bundler.** The build is `tsc` only. Runtime is plain Node consuming `dist/`. The Dockerfile will copy `dist/` and `node_modules/`. - **Linting style:** Configure ESLint to enforce `@typescript-eslint/no-floating-promises` and `@typescript-eslint/no-misused-promises` — both are critical in a TCP server where unhandled promise rejections will silently lose work. ## Acceptance criteria - [ ] `pnpm install` succeeds with no warnings other than peer deps. - [ ] `pnpm typecheck` succeeds on the empty project. - [ ] `pnpm lint` succeeds. - [ ] `pnpm build` produces `dist/main.js`. - [ ] `pnpm start` runs the compiled output and prints the startup message. - [ ] `pnpm test` runs (with no tests) and exits successfully. - [ ] `pnpm dev` runs `main.ts` via `tsx` and prints the startup message. - [ ] Repository builds reproducibly: deleting `node_modules` and `dist`, then `pnpm install --frozen-lockfile && pnpm build` produces identical output. ## Risks / open questions - Pinning Node 22 LTS vs 20 LTS: 22 is current LTS in 2026 and has stable native fetch + better worker thread perf. Stay with 22 unless deployment infra forces 20. - ESLint v9 flat config: ensure the version is compatible with `@typescript-eslint/*` v8+. If issues arise, fall back to legacy `.eslintrc.json` until upstream catches up. ## Done (Fill in once complete: commit SHA, brief notes.)