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

> **Internal · agent reference.** Terse. Confirmed against `hiveops-module-nh-tcr-journal` source 2026-07-01.

## Identity
- Maven artifact: **`hiveops-module-nh-tcr-journal`** (`com.hiveops`, version `1.0.0`, standalone `jar`, parent `hiveops-agent-parent` 4.4.3).
- Agent module id (`getName()`, and the string for **`modules.disabled`**): **`nh-tcr-journal`**.
- Entry class: `com.hiveops.nhtcr.NhTcrJournalModule`, registered via `META-INF/services/com.hiveops.core.module.AgentModule`.
- Follower/parser class: `com.hiveops.nhtcr.TcrJournalMonitor`.
- Log package (`getLogPackage()`): `com.hiveops.nhtcr`.
- Activation gate: `device.type` must equal `NH_TCR` **and** an ext properties entry with `type=NH_TCR` (or legacy `MAINJOURNAL`) + `journal.dir` must exist, **and** `agent.endpoint` or `incident.endpoint` must be set. Any gate failing → module inert, `isEnabled()` returns `false` (no crash).

## Config properties (exact keys)
| Key | File | Default | Required | Notes |
|---|---|---|---|---|
| `device.type` | `hiveops.properties` | *(none)* | **yes** | must be `NH_TCR` (uppercased/trimmed) |
| `nh.tcr.journal.poll.interval.sec` | `hiveops.properties` | `60` | no | poll cadence; **is** applied (`scheduleAtFixedRate`) |
| `type` | ext (`ej.properties`) | *(none)* | **yes** | `NH_TCR` preferred, `MAINJOURNAL` legacy fallback |
| `journal.dir` | ext | *(none)* | **yes** | TCR ejournal directory |
| `filename.format` | ext | *(none)* | recommended | daily template, e.g. `ej_TCR1_{YYYY}{MM}{DD}.txt` |
| `file.format` | ext | `UTF8` | no | `JournalSource` descriptor; follower still decodes bytes as UTF-16 LE |

Shared (not module-specific): `agent.endpoint` (prefix `agent`) else `incident.endpoint` (prefix `incident`); `agent.auth.token`; institution-key chain — all via `HttpClientHelper.loadSettingsFromProperties(props, prefix)`.

## Event types emitted (exact strings)
| Event type | Trigger | Source |
|---|---|---|
| `DISPENSER_JAM` | `CashDispenserStatusChanged` with params `NODISPENSE` | single-line device event |
| `DISPENSER_JAM` | `BNAItemsRefused` (always) | single-line device event |
| `CASSETTE_LOW` | `CashUnitThresholdChanged` (always) | single-line device event |
| `SELF_TEST_FAILED` | `AcceptorStatusChanged` with params != `OK` | single-line device event |
| `OPERATOR_ACTION` | completed TRANSACTION RECORD block (`level 5`, empty name) | multi-line block |

- All four are standard HiveIQ event types (no TCR-specific event strings). `eventType` is a free-form `String` on `CreateJournalEventRequest` (`hiveops-agent-journal` DTO), not validated client-side.
- `eventSource` sent for all events: **`"NH_TCR_JOURNAL"`**.
- `OPERATOR_ACTION` `eventDetails` = `TCR Transaction #<no> | Type: .. | Result: .. | Amount: .. | Balance: .. | Teller: .. | Branch: ..` (`| Error: <code>` appended only if error code present and != `0`).
- Transport: `POST {endpoint}/api/journal-events` via `IncidentEventClient.sendEvent()` — same client/endpoint as `journal-events`.

## Journal format facts
- File: UTF-16 LE text, daily-rotated, resolved via `JournalSource.getCurrentJournalFile()` (filename fixed per model; ATM identity comes from the upload folder, not the filename).
- Line regex: `[YYYY-MM-DD HH:MM:SS-nnn][<level>][TCR]<EventName><params>` (optional leading BOM tolerated).
- TRANSACTION RECORD block opens on a `level 5` line with empty event name; buffered until the next timestamp line, then flushed. Block dropped if both `TRANSACTION NO.` and `TRANSACTION TYPE` are missing.
- Tail-by-byte-offset (`filePosition`), 2 MB read cap per poll, only complete lines processed; offset advanced by `chars * 2`.

## Deployment
- Delivered fleet-wide via **`INSTALL_MODULE`** fleet task (downloads JAR into agent `modules/` dir, restarts agent — `ProcessInstallModule` in `hiveops-file-collection`).
- Disable without uninstalling: add `nh-tcr-journal` to `modules.disabled`, push `CONFIG_UPDATE`.
- Rollout order: lab ATM → pilot → fleet.

## Do NOT
- Do NOT expect events on non-`NH_TCR` devices — inert by design, not a bug to chase.
- Do NOT assume plain UTF-8/ASCII parsing — the follower decodes **UTF-16 LE**; a differently-encoded ejournal parses to nothing silently.
- Do NOT expect retry/queueing on send failure — a failed `sendEvent()` is logged and dropped, not persisted or retried next poll.
- Do NOT expect in-agent de-dup for single-line events (`DISPENSER_JAM` / `CASSETTE_LOW` / `SELF_TEST_FAILED`) — every matching line emits; only the transaction-block buffer holds state.
- Do NOT rely on `MAINJOURNAL` for new installs — use `type=NH_TCR` so `journal-upload` tags uploads for the TCR parser; `MAINJOURNAL` is a compatibility fallback only.
- Do NOT confuse this with `hiveops-module-nh-tcr-events` (`NhTcrEventsModule`) or `hiveops-module-atec-tcr-events` (`tcr-events`) — separate modules, separate formats/pipelines.
- Do NOT assume the poll-interval property is a no-op — here it **is** applied (unlike the ATEC sibling).
