Who can generate a compliance export
Generating a compliance export bundle requires thereports.view capability. The seeded Administrator, Credit Manager, and Branch Manager roles all carry it, so any of the three can generate a bundle. The export action checks reports.view, then re-validates the filter input with a Zod schema before the bundle runs, so a request cannot smuggle a cross-workspace or malformed filter past the gate.
There is a separate audit.export capability that the platform reserves for the Administrator role as a compliance privilege, but it only controls whether the Audit log link appears in the navigation. It does not gate the export itself. A Credit Manager or Branch Manager does not see the nav link and reaches the audit trail at /admin/audit-viewer directly, where reports.view enables both the view and the export.
Do not confuse the compliance export bundle with the quick CSV or JSON export on the same page. The quick export is a fast, unsigned download of up to 1,000 rows for internal work. The compliance bundle described here is the signed, hash-chained, immutably-stored archive that a regulator can verify offline.
How to generate an export bundle
Open the Audit log
In the navigation, under Administration, click Audit log. The page header reads Audit trail. If you do not see the nav link, you hold
reports.view but not audit.export; open /admin/audit-viewer directly.Filter to the records you need
Use the filter bar to narrow the audit records to the time range and scope you want to export. For a BoJ examination of loan decisions, you might filter by:
- Event type:
adjudication.decision.recorded - Time range: the calendar year under review
Generate the bundle
In the toolbar, click Export bundle. A dialog titled Compliance export opens, currently marked Beta. Confirm the filters, then click Generate bundle. The platform builds the bundle, which takes a few seconds.To restrict the bundle to large loan decisions, expand the Advanced disclosure and set Restrict to loan decisions at or above (JMD), for example
5,000,000. This scopes the bundle to loan applications whose requested amount is at or above the threshold, which is the basis for a query such as “every loan decision over JMD $5M last year.”Download the bundle
When generation is complete, the dialog shows your download link along with the Export ID, the row count, the Manifest signature (the first 32 characters of the bundle’s RSA-SHA256 signature, for reference), and when the link expires. Click Download to save the ZIP file.
Provide the bundle to the examiner
Share the downloaded ZIP file with the BoJ examiner or auditor. They can verify it completely offline using the Verifying a bundle section below. They need no access to your system.
What the bundle contains
Every compliance export bundle is a ZIP archive with four files. The files are stored uncompressed inside the archive, in STORE mode, so each file’s SHA-256 hash is stable and any standard tool can verify it.manifest.json
The signed envelope for the entire bundle. It lists the three data files (
audit-entries.csv, audit-entries.jsonl, and chain-proof.json) with each file’s SHA-256 hash and carries an RSA-SHA256 digital signature from the platform. Verifiers check the signature first, then re-hash each listed file to confirm nothing has been altered.audit-entries.csv
A flat 22-column spreadsheet view of the audit records in a stable, documented column order. It is ideal for spot-checks, quick searches in Excel, and ad-hoc queries. It does not include the full event payload. Use the JSONL file for that.
audit-entries.jsonl
The full audit records in newline-delimited JSON, one object per line. It includes complete event payloads and decision rationales. The full risk and rate inputs behind each decision live on the loan application’s RiskAssessment and RateComputation rows, which the bundle does not export. It supports streaming queries with tools like
jq without loading the entire file into memory.chain-proof.json
The hash-chain bracket for the exported range, with the keys
startSequence, endSequence, startPreviousChainHash, and endChainHash. It proves that the exported records are a contiguous, unmodified slice of the audit log.If your filters match no records, the platform still produces a complete, signed bundle with a row count of zero and a chain proof whose start and end sequence are both
0. An empty bundle is positive evidence: it shows an examiner that the answer to their query is genuinely “no matching records,” signed and verifiable like any other bundle.Verifying a bundle
An examiner or auditor can verify the bundle completely offline. Verification proves four things: the bundle structure is valid, every file is unmodified since it was signed, the audit rows form an unbroken hash chain, and the manifest was signed with the platform’s key.Re-hash each file and compare to the manifest
For each file listed in Each computed hash must match the corresponding
manifest.json, compute its SHA-256 hash and compare it to the value in manifest.files:sha256 value in manifest.json. A mismatch means a file was altered after the bundle was signed.Verify the RSA-SHA256 signature on the manifest
The
manifest.json file contains the public key (signature.publicKeyPem) and the base64-encoded signature (signature.value). To verify:- Parse
manifest.jsonand remove thesignaturefield. - Serialize the remaining body as canonical JSON, with keys sorted at every level.
- Decode
signature.valuefrom base64. - Verify the decoded bytes against
signature.publicKeyPemusing RSA-SHA256.
Walk the hash chain
Check that the audit rows form an unbroken chain across the export range. The JSONL rows use snake_case keys: the event body is under
payload, and the chain fields are payload_hash, previous_chain_hash, and chain_hash. For each row in audit-entries.jsonl in sequence order:- Recompute
SHA-256(canonicalJson(payload))and confirm it matches the row’spayload_hash. - Recompute
SHA-256(payload_hash + previous_chain_hash)and confirm it matches the row’schain_hash. For the very first row in the log,previous_chain_hashis null, so concatenate an empty string rather than the textnull.
chain_hash must match endChainHash in chain-proof.json. Any mismatch means records were tampered with after the bundle was generated.Retention
All compliance export bundles are stored in secure cloud storage with a 7-year compliance-mode retention lock. Seven years is the Bank of Jamaica minimum for loan records. The retention lock is set when the bundle is created and cannot be shortened retroactively. Even administrators cannot delete a bundle before its retention period expires. The 7-year retention applies to the stored bundle in cloud storage. Your downloaded copy is yours to manage under your own data retention policies.Generating a compliance export is itself recorded as an audit event (
audit.exported) in the immutable audit log. The record shows which user generated the export, when, what filters they applied, and how many rows were included. The export chain of custody is itself auditable.