Audit Logging
Fiscal compliance demands that every invoice can be traced end to end. The middleware logs everything: inbound requests, outbound calls, data conversions and issued invoices — all tied together by a single transaction ID.
The transaction ID
Every inbound HTTP request is assigned a UUID transaction ID by the RequestResponseLoggingFilter, before authentication. That ID is attached to:
- The inbound request log entry
- The store tagging (once SellerName resolves to a store)
- The conversion log entries
- The outbound Chrilan request/response entries
- The final response log entry
One ID, complete story. When a store disputes a receipt, this is the key that reassembles the event.
What is stored, where
api_transactions
Full HTTP-level audit for every request and response, inbound and outbound:
| Column group | Contents |
|---|---|
| Identity | transaction_id (UUID), store_id |
| Route | source API, target API, endpoint, HTTP method |
| Payloads | request headers + body, response headers + body (LONGTEXT) |
| Outcome | HTTP status code, success flag, error message |
| Timing | response time in milliseconds, created timestamp |
conversion_logs
Data-transformation audit trail for every Taxint ↔ Chrilan conversion:
| Column group | Contents |
|---|---|
| Identity | transaction_id, store_id, conversion type |
| Formats | source format, target format, full source and target data |
| Rules | mapping rules applied |
| Outcome | validation errors, success flag, processing time |
fiscal_invoices
Every issued invoice, kept for refund lookups and audit:
| Column group | Contents |
|---|---|
| Identifiers | audit_number, receipt_number (ZRA rcptNo), sdc_id |
| Attribution | store_id, tpin, currency |
| Refunds | is_refund flag, original_receipt_number linkage |
| Buyer address | buyer_house_no, buyer_street, buyer_province (for POS check printing) |
Logging configuration
| Property | Default | Controls |
|---|---|---|
middleware.request-logging.enabled | true | Inbound request capture |
middleware.response-logging.enabled | true | Response capture |
middleware.transaction-logging.enabled | true | api_transactions writes |
middleware.conversion-logging.enabled | true | conversion_logs writes |
Application logs use SLF4J/Logback with the pattern %d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n. Code standards prohibit System.out and printStackTrace() — all logging goes through the logger, and all API transactions go through LoggingService.
Retention
CleanupOldTransactions stored procedure exists for deliberate, manual purges only (e.g. after a data-retention decision by management).
Querying the audit trail directly
The portal's Reports screens cover daily needs. For deeper analysis, two database views and three stored procedures are provided — see Database schema:
transaction_statisticsview — aggregated success/failure countsconversion_statisticsview — conversion outcomesGetTransactionStatistics,GetFailedTransactions,CleanupOldTransactionsprocedures
What gets logged for a single invoice
1. api_transactions ← POS request (headers + full Taxint body)
2. (store tagged: transaction updated with store_id)
3. conversion_logs ← Taxint → Chrilan mapping (source, target, rules)
4. api_transactions ← Chrilan request + response (full bodies, timing)
5. fiscal_invoices ← receipt_number, sdc_id, audit_number persisted
6. conversion_logs ← Chrilan → Taxint response mapping
7. api_transactions ← response returned to POS