# Row-Level Integrity

EntryTarget protects your financial data against direct database tampering using cryptographic row-level hashes.

## The Problem

As a customer, you have direct access to the database (RDS credentials). Without protection, it would be possible to alter balances, amounts, or any other field directly via SQL — bypassing all application-layer validation. While consistency queries (sum of balances = 0, debits = credits) detect some categories of tampering, they cannot catch targeted changes that preserve overall consistency (e.g., increasing one balance while decreasing another by the same amount).

## The Solution

Every row in the `account`, `journal`, and `ledger_archive` tables carries a cryptographic hash (HMAC-SHA256) computed from its business fields. Without the cryptographic key (which is embedded in the binary and not accessible to the customer), a direct database edit cannot produce a valid hash.

## Two Validation Layers

### 1. Real-Time Validation (Hot Path)

During every write operation, the system verifies the integrity hash of all involved accounts **before** processing the transaction. If any account's hash does not match:

* All requests involving that account are rejected with `INTEGRITY_VIOLATION` (HTTP 409)
* The account is effectively "locked out" until the issue is resolved
* This makes tampering immediately visible

### 2. Audit Validation (Cold Path)

The `GET /integrity` endpoint performs a comprehensive validation of all entities:

* **Account** — hash verification on every row
* **Journal Entry** — hash verification + referenced accounts must exist
* **Ledger Archive** — hash verification
* **Ledger** — cross-reference with journal entry data (all fields must match)

This runs on the read replica in batches, with no impact on write performance.

## What Gets Detected

| Tampering Type               | Detection Method                             |
| ---------------------------- | -------------------------------------------- |
| Altered account balance      | Row hash mismatch (real-time)                |
| Altered journal entry amount | Row hash mismatch (audit)                    |
| Altered ledger archive data  | Row hash mismatch (audit)                    |
| Altered ledger data          | Cross-reference mismatch (audit)             |
| Deleted account              | Journal entry/ledger reference check (audit) |
| Deleted journal entry        | Ledger reference check (audit)               |
| Deleted ledger rows          | Version sequence gap detection               |

## What is Hashed

Each hash is computed from the row's **business fields only**. The `created_at` timestamp is excluded because it is generated by PostgreSQL at commit time and is not known to the application at insertion.

## Performance Impact

* Hash computation: \~200ns per operation
* In a typical batch of 150 transactions: \~150μs total
* Negligible compared to the Postgres COMMIT time (\~5-15ms)

## Implications for Database Access

You have full read/write access to your RDS database, but:

* **Reading data** — fully supported, no restrictions
* **Direct SQL modifications** — will invalidate the row hash, causing:
  * Immediate 409 errors for affected accounts (real-time check)
  * Violations reported by `GET /integrity` (audit check)
  * Blocked ledger archive operations (integrity pre-check)

{% hint style="danger" %}
If you modify data directly in the database, the affected rows will fail integrity validation. Transactions involving modified accounts will be rejected until the issue is resolved. Contact support if you need to perform direct database corrections.
{% endhint %}

## Complementary Protections

Row hashes work alongside existing consistency mechanisms:

* **Sum of balances = 0** — detects unbalanced modifications
* **Per-asset sum = 0** — detects cross-currency inconsistencies
* **Sequential account versions** — detects deleted ledger rows
* **Balance evolution validation** — detects incorrect post-balance values


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://entrytarget.gitbook.io/docs/security-and-integrity/row-level-integrity.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
