---
module: agent.nh-tcr-journal
title: NH TCR Journal — transaction + fault events from Nautilus Hyosung Teller Cash Recyclers
tab: Internal
order: 20
audience: dev
---

> **Internal · ops/support.** Written 2026-07-01 from `hiveops-module-nh-tcr-journal` source. Verify against code before relying on specifics.

## What this module is

`hiveops-module-nh-tcr-journal` (Maven artifact `hiveops-module-nh-tcr-journal`, agent module id **`nh-tcr-journal`**) is an **agent drop-in module**, not a backend service. It runs inside the HiveIQ Agent process on **Nautilus Hyosung TCR (Teller Cash Recycler) devices only**, and it self-disables unless the ATM's `device.type` is `NH_TCR`.

It tails the NH TCR ejournal file the recycler software already writes on disk (UTF-16 LE text), turns each teller transaction record and specific device-fault lines into HiveIQ journal events, and sends them to the incident pipeline via the shared agent HTTP client. It does not talk to the recycler hardware directly and it does not reconcile cash totals — it is a read-only journal follower.

> Not to be confused with `hiveops-module-nh-tcr-events` (a separate NH TCR module) or `hiveops-module-atec-tcr-events` (ATEC/LG TCRs). Different modules, different log formats.

## What it monitors

A single poll loop (default every 60s) tails one daily-rotated ejournal file resolved through the agent's standard `JournalSource` (directory + `filename.format`, e.g. `ej_TCR1_{YYYY}{MM}{DD}.txt`). The filename is fixed per machine model — ATM identity comes from the device-specific upload folder, not the filename.

The follower recognizes two kinds of content:

1. **Single-line device events** — lines shaped `[timestamp][level][TCR]EventName,params`. It maps four of these to HiveIQ events:
   - `CashDispenserStatusChanged` with params `NODISPENSE` → dispenser fault.
   - `BNAItemsRefused` → dispenser fault (possible note jam / validation failure).
   - `CashUnitThresholdChanged` → cash-unit low.
   - `AcceptorStatusChanged` with any non-`OK` status → acceptor self-test failure.
   - All other event names are ignored.
2. **Multi-line TRANSACTION RECORD blocks** — a `level 5` line with no event name opens a block; the module buffers following lines until the next timestamp line, then extracts transaction number, type, result, amount, machine balance, teller ID, branch number and error code into a one-line summary and emits it as a teller-action event.

## Config properties it registers

| Property | Where | Default | Meaning |
|---|---|---|---|
| `nh.tcr.journal.poll.interval.sec` | `hiveops.properties` | `60` | Poll interval in seconds for the ejournal tail loop. |
| `device.type` | `hiveops.properties` | *(none — required)* | Must equal `NH_TCR` for the module to activate; any other value → module inert. |

The journal location and filename come from an **ext properties file** (the standard `ext/ej.properties`), not from `hiveops.properties`:

| ext key | Default | Meaning |
|---|---|---|
| `type` | *(required)* | Must be `NH_TCR` (preferred) or `MAINJOURNAL` (legacy fallback). |
| `journal.dir` | *(required)* | Directory containing the TCR ejournal files. |
| `filename.format` | *(none)* | Daily filename template, e.g. `ej_TCR1_{YYYY}{MM}{DD}.txt`. |
| `file.format` | `UTF8` | Journal file encoding descriptor read by `JournalSource` (the follower itself decodes the raw bytes as UTF-16 LE). |

It also reuses the shared agent HTTP settings — `agent.endpoint` (preferred) or `incident.endpoint` (legacy fallback), `agent.auth.token`, and the institution-key chain — the same properties every other event-reporting module uses. There are no TCR-specific auth properties.

> Prefer `type=NH_TCR` over `MAINJOURNAL` on new installs: the `journal-upload` module uses the same `type` to tag uploads so the server routes them to the TCR parser. `MAINJOURNAL` only exists so pre-existing ATM configs keep working.

## How it's enabled / deployed

- It only activates on ATMs configured with `device.type=NH_TCR` **and** a matching ext properties entry (`type=NH_TCR`/`MAINJOURNAL` with `journal.dir` set). Missing either → the module logs a warning and disables itself; it does **not** crash agent startup.
- Delivered like any other agent module: uploaded to the fleet artifact store and pushed via an **`INSTALL_MODULE`** fleet task, which downloads the module JAR into the agent's `modules/` directory and restarts the agent (see `ProcessInstallModule` in `hiveops-file-collection`). Standard rollout order applies: lab ATM → pilot device → fleet.
- Can be disabled fleet-wide without removing the JAR by adding `nh-tcr-journal` to the comma-separated `modules.disabled` property and pushing a `CONFIG_UPDATE`.
- Event types it emits (`OPERATOR_ACTION`, `DISPENSER_JAM`, `CASSETTE_LOW`, `SELF_TEST_FAILED`) are all standard HiveIQ event types shared with other modules and normally already registered in hiveops-incident's Event Types settings.

## Common failure modes / what to check

- **No TCR events ever appear for a customer ATM** — first check `device.type` on that ATM's config; if it isn't `NH_TCR`, the module is intentionally inert. Not a bug.
- **Module loaded but silent** — confirm the ext properties file exists with `type=NH_TCR` (or `MAINJOURNAL`) and a valid `journal.dir`; a missing/wrong ext entry disables the module at startup with a log warning, no crash. Look for `nh-tcr-journal: monitoring <dir>` in agent logs to confirm what it is tailing.
- **Events stopped after midnight / around rollover** — the follower resets its read position on daily filename rollover. If the recycler's filename convention differs from the configured `filename.format`, it will look for a file that never appears and go silent. Check `nh-tcr-journal: switched to <file>` in agent logs.
- **Garbled details / no events despite an active journal** — this follower decodes the file as **UTF-16 LE**. If a given customer machine writes the ejournal in a different encoding, line parsing will fail silently. Confirm the raw file encoding before assuming a bug.
- **HTTP send failures** — `IncidentEventClient.sendEvent()` failures are caught and logged (`nh-tcr-journal: failed to send ...`) but **not** retried or queued; a transient outage drops that single event rather than backing it up for a later poll.
- **A slot/dispenser fault fires once but not repeatedly** — single-line events are emitted every time the matching line appears in the unread tail; there is no in-agent de-dup for these (unlike the block state). High-frequency `CashUnitThresholdChanged` lines can therefore produce repeated `CASSETTE_LOW` events.
