# israfil-miya/adms-tcp-listener architecture

> Architecture diagram of the GitHub repository israfil-miya/adms-tcp-listener, generated by GitDiagram from its file tree, README and a sample of source files (last updated 2026-06-27). It is an AI-made overview: check details against the source.

- Interactive diagram: https://gitdiagram.com/israfil-miya/adms-tcp-listener
- Repository: https://github.com/israfil-miya/adms-tcp-listener

## Overview

1. **Overall shape**
   - This repo is a small, event-ingestion service with two binaries: `adms_server` and `adms_test_client`.
   - The server listens on TCP port 4370 for ZKTeco devices speaking the ADMS push protocol, parses attendance events, logs them locally, and optionally forwards them to a cloud HTTP API.

2. **Configuration boundary**
   - `src/config.*` is the central configuration layer.
   - It reads environment variables and a local `.env` file, with OS env taking precedence.
   - This boundary controls the listen port, cloud API URL/auth, timeouts, log paths, and log level; the rest of the system depends on it rather than hardcoding runtime values.

3. **Ingress / device session layer**
   - `src/main.cpp` is the application entry point and likely owns server startup, accept loop, and health endpoint wiring.
   - The ingress side is connection-oriented: each device connects over TCP, sends ADMS payloads, and receives immediate acknowledgements.
   - The readme indicates a built-in `GET /health` path for monitoring, so the server exposes a small HTTP-like health check alongside the TCP listener.

4. **Protocol parsing**
   - `src/proto/parser.*` is the ADMS protocol normalization layer.
   - It accepts multiple payload shapes from different firmware variants: HTTP POST-style bodies, key-value pairs, comma-separated, and space-separated records.
   - The parser is designed to be defensive and low-overhead: it uses `string_view`-style zero-copy parsing and can handle malformed input and multi-record batches.

5. **Core handoff: lock-free queue**
   - `src/queue/spsc.h` is the concurrency boundary between network ingestion and outbound forwarding.
   - The producer side is the network/session thread; the consumer side is a dedicated worker.
   - This single-producer/single-consumer queue keeps the fast path non-blocking so device acknowledgements are not delayed by cloud API latency.

6. **Forwarding worker**
   - `src/http/worker.h` and `src/http/poster.*` form the outbound delivery subsystem.
   - A worker thread drains parsed events from the queue and posts them to the configured cloud endpoint.
   - The design emphasizes reliability and latency isolation: API failures do not block device intake, and HTTP work is separated from the TCP listener.

7. **HTTP client behavior**
   - `src/http/poster.*` is the cloud API client, implemented around libcurl per the readme.
   - The connection is persistent and reused, with TCP keepalive enabled for efficiency.
   - Failed posts are not silently dropped; they are logged into a dead-letter/failed-events stream for later replay or inspection.

8. **Logging and audit trail**
   - `src/log/logger.*` is a shared, thread-safe logging subsystem.
   - It emits console plus file logs and supports daily rotation.
   - The repo keeps three distinct log streams: application logs, all attendance events, and failed outbound events.
   - Sensitive data redaction is part of the logging policy, which is important because devices may send personal attendance data.

9. **Event data flow**
   - The runtime path is: device TCP payload → parser → SPSC queue → worker → cloud API POST.
   - In parallel, the server writes attendance events and operational logs to local files.
   - Event timestamps are preserved as device-local values; the server adds its own `receivedAt` timestamp in UTC, leaving timezone interpretation to the downstream API.

10. **Testing and local validation**
   - `src/test_client.cpp` is a companion tool for sending sample ADMS payloads to the server.
   - It is used to validate parsing across the main protocol formats without needing a physical device.
   - This keeps protocol coverage and server behavior testable in isolation from the hardware.

11. **Build and dependency model**
   - The project is CMake-based and targets C++20.
   - Runtime dependencies that materially affect architecture are Asio for async TCP I/O and libcurl for outbound HTTP.
   - Build scripts are provided for Linux/macOS and Windows, and the repository is set up to fetch or build needed third-party pieces as part of the CMake flow.

12. **Architectural intent**
   - The repo is organized around one key principle: never let cloud forwarding slow down device ingestion.
   - The main architectural seams are configuration, protocol parsing, queueing, and outbound delivery.
   - Those boundaries are what you would want to show in an architecture diagram: device/network ingress on one side, local normalization and buffering in the middle, and asynchronous cloud posting plus logging on the other.

Main entry points: [`src/main.cpp`](https://github.com/israfil-miya/adms-tcp-listener/blob/main/src/main.cpp) (Server), [`src/log/logger.h`](https://github.com/israfil-miya/adms-tcp-listener/blob/main/src/log/logger.h) (Logger), [`src/http/worker.h`](https://github.com/israfil-miya/adms-tcp-listener/blob/main/src/http/worker.h) (Worker), [`src/config.h`](https://github.com/israfil-miya/adms-tcp-listener/blob/main/src/config.h) (Config)

## Diagram (Mermaid)

```mermaid
flowchart TD

subgraph group_group_runtime["Runtime flow"]
  node_node_main(("Server<br/>binary entrypoint<br/>[main.cpp]"))
  node_node_parser["Parser<br/>protocol normalizer<br/>[parser.h]"]
  node_node_queue["SPSC queue<br/>handoff buffer<br/>[spsc.h]"]
  node_node_device{{"ZKTeco device<br/>TCP peer"}}
  node_node_health(("Health check<br/>monitoring endpoint"))
end

subgraph group_group_config["Configuration"]
  node_node_config["Config<br/>settings layer<br/>[config.h]"]
end

subgraph group_group_outbound["Outbound delivery"]
  node_node_worker["Worker<br/>forwarder thread<br/>[worker.h]"]
  node_node_poster["Poster<br/>HTTP client<br/>[poster.h]"]
  node_node_cloud{{"Cloud API<br/>HTTP endpoint"}}
end

subgraph group_group_observability["Observability"]
  node_node_logger["Logger<br/>logging subsystem<br/>[logger.h]"]
  node_node_disk[("Local logs<br/>file outputs")]
end

subgraph group_group_tools["Tools"]
  node_node_test_client(("Test client<br/>utility binary<br/>[test_client.cpp]"))
end

node_node_device -->|"ADMS TCP"| node_node_main
node_node_main -->|"parse"| node_node_parser
node_node_main -->|"serve"| node_node_health
node_node_parser -->|"enqueue"| node_node_queue
node_node_queue -->|"drain"| node_node_worker
node_node_worker -->|"post"| node_node_poster
node_node_poster -->|"HTTP POST"| node_node_cloud
node_node_main -->|"log"| node_node_logger
node_node_parser -->|"warn"| node_node_logger
node_node_worker -->|"failures"| node_node_logger
node_node_logger -->|"persist"| node_node_disk
node_node_config -->|"configure"| node_node_main
node_node_config -->|"configure"| node_node_worker
node_node_config -->|"configure"| node_node_logger
node_node_test_client -.->|"simulate"| node_node_main

click node_node_main "https://github.com/israfil-miya/adms-tcp-listener/blob/main/src/main.cpp"
click node_node_config "https://github.com/israfil-miya/adms-tcp-listener/blob/main/src/config.h"
click node_node_parser "https://github.com/israfil-miya/adms-tcp-listener/blob/main/src/proto/parser.h"
click node_node_queue "https://github.com/israfil-miya/adms-tcp-listener/blob/main/src/queue/spsc.h"
click node_node_worker "https://github.com/israfil-miya/adms-tcp-listener/blob/main/src/http/worker.h"
click node_node_poster "https://github.com/israfil-miya/adms-tcp-listener/blob/main/src/http/poster.h"
click node_node_logger "https://github.com/israfil-miya/adms-tcp-listener/blob/main/src/log/logger.h"
click node_node_test_client "https://github.com/israfil-miya/adms-tcp-listener/blob/main/src/test_client.cpp"

classDef toneNeutral fill:#f8fafc,stroke:#334155,stroke-width:1.5px,color:#0f172a
classDef toneBlue fill:#dbeafe,stroke:#2563eb,stroke-width:1.5px,color:#172554
classDef toneAmber fill:#fef3c7,stroke:#d97706,stroke-width:1.5px,color:#78350f
classDef toneMint fill:#dcfce7,stroke:#16a34a,stroke-width:1.5px,color:#14532d
classDef toneRose fill:#ffe4e6,stroke:#e11d48,stroke-width:1.5px,color:#881337
classDef toneIndigo fill:#e0e7ff,stroke:#4f46e5,stroke-width:1.5px,color:#312e81
classDef toneTeal fill:#ccfbf1,stroke:#0f766e,stroke-width:1.5px,color:#134e4a
class node_node_main,node_node_parser,node_node_queue,node_node_device,node_node_health toneBlue
class node_node_config toneAmber
class node_node_worker,node_node_poster,node_node_cloud toneMint
class node_node_logger,node_node_disk toneRose
class node_node_test_client toneIndigo
```

## Components

### Runtime flow

Live server path from device ingress to cloud delivery

- [Server](https://github.com/israfil-miya/adms-tcp-listener/blob/main/src/main.cpp): binary entrypoint · Starts the ADMS listener, accept loop, and health endpoint · `src/main.cpp`
- [Parser](https://github.com/israfil-miya/adms-tcp-listener/blob/main/src/proto/parser.h): protocol normalizer · Normalizes ADMS payload variants into attendance events · `src/proto/parser.h`
- [SPSC queue](https://github.com/israfil-miya/adms-tcp-listener/blob/main/src/queue/spsc.h): handoff buffer · Lock-free single-producer/single-consumer buffer between ingest and forwarding · `src/queue/spsc.h`
- **ZKTeco device**: TCP peer · ADMS-speaking attendance device connecting over TCP
- **Health check**: monitoring endpoint · Built-in GET /health probe for liveness monitoring

### Configuration

Runtime settings and environment resolution

- [Config](https://github.com/israfil-miya/adms-tcp-listener/blob/main/src/config.h): settings layer · Loads env and .env settings for ports, URLs, timeouts, and logging · `src/config.h`

### Outbound delivery

Asynchronous forwarding to cloud API and failure handling

- [Worker](https://github.com/israfil-miya/adms-tcp-listener/blob/main/src/http/worker.h): forwarder thread · Drains parsed events and coordinates outbound delivery · `src/http/worker.h`
- [Poster](https://github.com/israfil-miya/adms-tcp-listener/blob/main/src/http/poster.h): HTTP client · Posts events to the cloud API with persistent transport behavior · `src/http/poster.h`
- **Cloud API**: HTTP endpoint · Downstream service receiving forwarded attendance events

### Observability

Logging and local audit streams

- [Logger](https://github.com/israfil-miya/adms-tcp-listener/blob/main/src/log/logger.h): logging subsystem · Thread-safe console and file logging with rotation and redaction · `src/log/logger.h`
- **Local logs**: file outputs · Application, attendance, and failure log streams

### Tools

Companion binaries and validation helpers

- [Test client](https://github.com/israfil-miya/adms-tcp-listener/blob/main/src/test_client.cpp): utility binary · Sends sample ADMS payloads to validate parsing and server behavior · `src/test_client.cpp`

## Connections

- ZKTeco device → Server: ADMS TCP · Devices connect to the listener and push payloads
- Server → Parser: parse · Incoming payloads are normalized into event records
- Server → Health check: serve · Server exposes a lightweight health probe
- Parser → SPSC queue: enqueue · Parsed events are handed off without blocking intake
- SPSC queue → Worker: drain · Worker consumes buffered events asynchronously
- Worker → Poster: post · Worker delegates HTTP delivery to the client
- Poster → Cloud API: HTTP POST · Events are forwarded to the configured cloud endpoint
- Server → Logger: log · Server writes operational and event logs
- Parser → Logger: warn · Malformed or edge-case payloads are recorded
- Worker → Logger: failures · Outbound errors are logged for inspection
- Logger → Local logs: persist · Console and file logs are written locally
- Config → Server: configure · Server startup reads runtime settings
- Config → Worker: configure · Outbound worker uses API and timeout settings
- Config → Logger: configure · Log level and file paths come from config
- Test client → Server: simulate · Test tool exercises the server with sample payloads
