---
module: recon.recon-rules
title: Recon Rules
tab: Architect
order: 30
audience: dev
---

> **Internal · architecture.** How the Recon Rules feature is built, grounded in `hiveops-recon` source (2026-07-01). See [platform.service-ownership], [platform.data-architecture], [platform.kafka].

## Ownership

`hiveops-recon` owns this feature end-to-end — frontend and backend are in the same repo. No other service is involved in rules editing. Recon owns the recon domain exclusively per [platform.service-ownership].

## Components

| Layer | Artifact | Role |
|---|---|---|
| Frontend view | `frontend/src/components/ReconRulesView.svelte` | Table of formats; loads `getReconFormats()` on mount |
| Frontend panel | `frontend/src/components/ReconRulesPanel.svelte` | Per-format detail + full-file YAML view/edit/reload |
| Frontend API | `frontend/src/lib/api.ts` → `reconAPI` | Base `window.__APP_CONFIG__.apiUrl` or `http://localhost:8091/api/recon` |
| Controller | `controller/ReconRulesController.java` | `@RequestMapping("/api/recon/admin")` |
| Service | `service/ReconRulesService.java` | Load/cache/validate/persist rules; format detection |
| Model | `model/ReconRules.java` (`ReplenishmentFormatConfig`) | Deserialized YAML structure |
| Config source | `src/main/resources/recon-rules.yml` (classpath) | Default rules, overridable via file |

## Data flow — rules are a file, not a database row

There is **no DB table** for these rules. `ReconRulesService` is the single source of truth:

1. **Startup** — `@PostConstruct init()` → `loadRules()`. If `recon.rules.path` (`RECON_RULES_PATH`) is set and the file exists, load from there; otherwise load the classpath `recon-rules.yml`. Result is held in a `volatile ReconRules cachedRules`.
2. **Read (table)** — `GET /admin/rules/formats` → `getRules()` maps each `replenishmentFormats` entry to `{name, detectionSentinel, slotStrategy, deduplication, preReplenishmentBlockEnd, description}`.
3. **Read (raw)** — `GET /admin/rules` (text/plain) → `getRulesContent()` returns the raw file text (external path if set, else classpath bytes).
4. **Write** — `PUT /admin/rules` (text/plain) → `saveRulesContent(yaml)`: **validates** by parsing into `ReconRules.class`, then writes to the external `RECON_RULES_PATH` file and calls `loadRules()` to refresh the cache. If `RECON_RULES_PATH` is unset it throws `IllegalStateException` (→ 400) rather than mutate the classpath jar.
5. **Reload** — `POST /admin/reload-rules` → `reloadRules()` re-reads file→cache without editing; returns the current format-name list.

## How the rules are consumed (the point of the feature)

`ReconRulesService.detectFormat(rawLines)` and `getFormatConfig(name)` are called by recon's replenishment parsing path (prefill/sync) when it processes journal `STANDARD REPLENISHMENT` blocks:

- Iterate `replenishmentFormats` in declaration order.
- First format whose `detectionSentinel` is `contains()`-matched in the raw journal text wins.
- A format with a `null` sentinel is retained as the **fallback** (used only if nothing else matches).
- The matched `ReplenishmentFormatConfig` (`slotStrategy` LETTER/DENOMINATION/POSITION, `deduplication`, `preReplenishmentBlockEnd`) governs how cassette BEG/USE/CUR lines are parsed into cash totals.

## Kafka

This feature (rules view/edit) involves **no Kafka**. It's a synchronous file-backed config CRUD. Recon is a **consumer-only** service overall (`hiveops.device.events`, `journal.replenishments`, `hiveops.journal.transactions.recorded`) — those feed the *reconciliation* pipeline, not rules editing. See [platform.kafka].

## Data flow diagram

```
Admin (MSP_ADMIN/BCOS_ADMIN)
   │  ReconRulesView / ReconRulesPanel
   ▼
NGINX /api/recon/admin/*  ──►  ReconRulesController
                                   │
                                   ▼
                         ReconRulesService (volatile cachedRules)
                                   │
                    ┌──────────────┴───────────────┐
                    ▼                               ▼
        recon-rules.yml file            detectFormat()/getFormatConfig()
      (classpath or RECON_RULES_PATH)   used by replenishment parsing
                                        (prefill / sync from hiveops-journal)
```

## Related tables (context, not written by this feature)

Rules parsing feeds the recon pipeline that writes `replenishment_sessions`, `replenishment_cassette_entries`, `reconciliation_cycles`, `atm_cash_positions`, `atm_cassette_configs` in `hiveiq_recon`. See [platform.data-architecture]. The rules file itself is not persisted to Postgres.
