User guide · Modules

Audit log

A read-only trail of every staff action, sign-in and refused request across the hotel, who did what, when, from where, and what changed.
Whole guide

Purpose and who can read it

Super AdminHotel ManagerSecurity

Managers and Security see the trail; nobody edits it.

The audit log answers “who changed this and when?”. Every write to the system leaves a row: bookings, payments, guest edits, room status, staff records, settings, role changes, sign-ins, successful, failed and denied. Rows are written by the server as part of the action itself, so they cannot be skipped by the browser.

Reading it is limited to the admin tier: Super Admin, Hotel Manager, or any role whose matrix has been raised to Settings = Full, plus Security, whose job is access logs. Anyone else gets a 403 and does not see the sidebar entry. Nothing on the page writes; the only action is Export CSV.

Screen anatomy

Four KPI tiles, a filter bar with date range and extra filters, the event table and a detail drawer.

Audit log
1872346
  1. 1
    Page head
    “Every staff action across the hotel, with who / what / when / from where.”
  2. 8
    Export CSV
    Downloads audit-log-2026-09-04.csv with the current filters applied (up to 5,000 rows, newest first).
  3. 7
    KPI tiles
    Events today (with the hotel date), Last 7 days, People active today, Denied this week. Today and Last 7 days set the date range; Denied this week sets Outcome = Denied for the week.
  4. 2
    Filter bar
    “Search actor, action, code, IP…” plus Person (name · role), Role, Module and Action dropdowns.
  5. 3
    Date range and More filters
    From and To date pickers (hotel-local days). More filters reveals HTTP method (POST / PATCH / PUT / DELETE) and Outcome (Succeeded / Denied / Error).
  6. 4
    Event rows
    When · Person (avatar, name, role) · Action (with a Denied or Error badge when it failed) · Record (module badge and record id) · Detail (a three-field summary of the diff) · From (IP). On phones the rows become cards.
  7. 6
    Pager and headers
    Fifty rows a page (25, 50 or 100), numbered pages, and the page, sort and filters live in the address bar. Tap a heading to sort; the Person, Action, Record and Outcome headings carry filter popovers. A Cards view is one click away.

Click a row for the drawer: the person with role and email, then Action (raw name such as booking.checkedin), Module, Record, Outcome with the HTTP status, When, IP address, Request (method and path), Browser (user agent) and a What changed panel that lists every field as before → after (red to green), the person card with browser and IP, a link to the record and the other events on that record, or “No extra detail was stored for this event.”

What is recorded

Named domain events with diffs, plus a generic row for every other write, sign-ins and denials.

One audit row
FieldTypeNotes
ActorThe user id plus a snapshot of the name and role at the time. If the account is later renamed or deleted the row still reads correctly; rows without a snapshot fall back to the current account, or “Unknown”.
ActionA dotted name: booking.checkedin, payment.refunded, settings.updated, auth.login.failed, access.denied, night_audit.closed… Screen labels translate the common ones (“Checked in”, “Refunded payment”, “Access denied”).
Module and RecordThe entity type (booking, invoice, user, hotel, sequence…) and the record’s code or id, BK-1042, INV-…, an email for user events, a slug for settings.
What changedBefore → after per field for edits (bookings, rooms, guests, staff, accounts, settings, roles, housekeeping, maintenance, payments). Creates and older rows show the record that was sent; a night audit stores its snapshot. Secrets are masked: a logo change stores “(image updated)”, a PIN change “(updated)”, hashes read “(changed)”.
Request metadataIP (first address in X-Forwarded-For), browser user agent (240 chars), HTTP method and path (200 chars), and the status code.
OutcomeDerived from the status code: below 400 → OK; 401 or 403 → Denied; any other 4xx/5xx → Error.
WhenServer time, displayed in the hotel’s timezone to the second.
  • Named events are written inside the same transaction as the change, so a booking cannot be checked in without its row.
  • Generic rows: any other POST, PATCH, PUT or DELETE that did not write a named event gets http.post-style rows: Module is the first path segment, Record is any code or id in the path, and the diff holds the path and status. GET requests, health checks, sign-in endpoints, notifications, the audit log itself, demo sandboxes and search are deliberately not logged as actions.
  • Sign-ins and denials: successful and failed email or PIN sign-ins, sign-outs and every request refused by the permission guard are recorded with the same IP and browser details.

Outcomes

Every row is OK, Denied or Error, derived from the HTTP status, not stored.

Outcome by status code
Outcome by status code< 400401 / 403other 4xx / 5xxRequest handledOKDeniedError
  • Request handledOK (< 400)
  • Request handledDenied (401 / 403)
  • Request handledError (other 4xx / 5xx)

Denied is the security view: a role trying a screen or action it does not have, or a wrong password. Error is a business refusal, a check-in on the wrong day, an overbooked room, a validation failure, which is useful when a colleague says “it would not let me”.

Tracing a change

Search the record code, narrow by person or action, open the drawer, read the diff.

  1. 1
    Type the record code in the search box
    BK-1042, INV-2210, a guest code, an email, an IP address or part of an action name. The search matches action, record id, module, actor name, request path and IP.
  2. 2
    Narrow with the dropdowns
    Person lists every account with its role; Role matches the role snapshot on the row (or the account’s current role); Module and Action list the values that exist in the log.
  3. 3
    Set the dates
    From / To are hotel-local calendar days: From starts at 00:00 hotel time, To includes the whole day. Events today and Last 7 days fill them for you.
  4. 4
    Open the row
    The drawer shows who (name, role, browser, IP), the outcome, the request line, a link straight to the record, What changed as before → after pairs, and the other events on the same record so you can walk its history. Raw record opens the stored document for anything older.
  5. 5
    Export if you need a record
    Export CSV honours every filter and writes at, actor, role, action, entity_type, entity_id, outcome, method, path, ip and diff (as JSON text).

Permissions and retention

Admin tier plus Security may read; nobody may edit or delete; rows are kept indefinitely.

Audit access is not a level, it is admin tier (Settings = Full, or Super Admin / Hotel Manager by name) or the Security role
RoleSettings
Super AdminFull
Hotel ManagerEdit
SecurityNone
HR ManagerView
None No accessView View onlyEdit Can editFull Full access
  • A Hotel Manager reads the log even at Settings = Edit, because the role is admin tier by name. A custom role becomes admin tier the moment its matrix is set to Settings = Full.
  • Security always reads it, whatever the rest of its matrix says.
  • There is no write API: rows are appended by the server and never edited. Nothing in the system prunes them, so the trail is complete for the life of the hotel; use Export CSV for off-site copies.
  • Demo sandboxes get their own log, discarded with the sandbox.

Tips

Wildcards, denied spikes and the hotel clock.

Errors you may see

One server refusal and one client-side export failure.

403The audit log is limited to Super Admin, Hotel Manager and Security
Why
Your role is neither admin tier (Settings = Full) nor Security.
Fix
Ask an administrator to grant Settings = Full on your role, or to pull the rows you need.
Could not export the audit log
Why
The CSV download failed, usually the session expired or the connection dropped.
Fix
Reload, sign in again if prompted, and click Export CSV once more.
Admin tier
Super Admin, Hotel Manager, or any role with Settings = Full, the roles that can manage users, roles and the PIN.
Actor snapshot
The name and role copied onto the row when it was written, so history survives renames and deletions.
Diff
The JSON stored with an event describing what was sent or what changed.