Audit Logs
Trust comes from accountability. Every state-changing action in ABc — a price override, a refund, a role change, a payout-bank edit — gets an immutable audit entry. Finance and owners can replay history when something looks off.
What gets logged
Bookings
Create, edit, status change, manual price override, room reassignment, cancellation, no-show marking.
Payments
Capture, refund initiation, refund completion, failed retries, chargeback events.
Property & rooms
Rate edits, blackout changes, room enable/disable, photo upload/delete.
Team
Invite, accept, role change, scope change, removal, login from new device.
Sensitive identity
Payout bank change, 2FA enable/disable, email/phone change, KYC re-submission.
Channel ops
OTA connect/disconnect, credential rotation, sync failures.
Audit entry — fields
audit_log
- idulid (sortable)
- occurred_attimestamptz
- actor_iduuid → users
- actor_roleenum (snapshot)
- actiontext (dot-notation)
- entity_typetext
- entity_iduuid
- property_id→ properties
- beforejsonb
- afterjsonb
- diffjsonb (computed)
- reasontext · nullable
- ipinet
- user_agenttext
- request_idtext (trace)
Sample entries
{ "action": "booking.price_override",
"actor": "Sneha (manager)",
"entity": "bk_ABC-24806",
"before": { "total": 28728 },
"after": { "total": 25200 },
"diff": { "total": { "−": 3528 } },
"reason": "Returning guest discount, owner approved over phone" }
{ "action": "payment.refund.initiated",
"actor": "Ravi (finance)",
"entity": "pay_xMv…",
"after": { "refund_amount": 22230, "method": "razorpay" },
"reason": "Guest cancellation, flexible policy, >24h before check-in" }
{ "action": "team.role_changed",
"actor": "Rohan (owner)",
"entity": "usr_anjali",
"before": { "role": "front_desk" },
"after": { "role": "manager" } }
{ "action": "payout_bank.changed",
"actor": "Rohan (owner)",
"entity": "usr_rohan",
"before": { "account_last4": "8821" },
"after": { "account_last4": "4412" },
"reason": "Changed primary banking partner" }
Audit log UI
| Time | Actor | Action | Entity | Reason |
|---|---|---|---|---|
| 25 May 17:21 | Sneha · manager | booking.price_override |
ABC-24806 | Returning guest disc. |
| 25 May 15:08 | Ravi · finance | payment.refund.initiated |
pay_xMv9P | Guest cancel · flexible |
| 25 May 12:44 | Rohan · owner | team.role_changed |
Anjali Patel | Promotion |
| 24 May 22:01 | Rohan · owner | payout_bank.changed |
self | Changed bank |
| 24 May 19:30 | system | booking.auto_cancelled |
ABC-24769 | Balance default · T+2d |
| 24 May 18:12 | Sneha · manager | rate.edit |
Deluxe King · Dec 24–28 | Season rate ₹6,500 |
Storage & immutability
- Audit table is append-only — no UPDATE or DELETE permission for the application user.
- The Postgres role used by background reconciliation is read-only.
- A row, once written, can only be deleted by a DBA, and that DBA action is itself logged outside Postgres.
- Each row carries the
request_idfrom our tracing system so we can correlate logs across services. - Daily snapshots are exported to an immutable S3 bucket (Object Lock) — useful if Postgres is ever compromised.
Privacy & redaction
Audit logs can contain sensitive fields (old PAN last-4, bank last-4). We hash these in before/after snapshots so the audit log doesn't become a leak source. The full value lives only in the live record.
Audit entries are retained for at least 7 years — exceeding the typical Indian tax/audit window. Older entries are archived to cold storage with the same immutability guarantees.
Searching and exporting
- Filter by actor, action, entity, property, date range.
- One-click "show all activity by this user in the last 7 days".
- One-click "show all changes to this booking".
- Export filtered view as CSV / JSON — handy for legal or audit requests.