Admin Audit Trail on Practitioner Records - hmislk/hmis GitHub Wiki

Admin — Audit Trail on Practitioner Records

Every practitioner record in HMIS captures who created it and who retired it, with timestamps. This article describes the fields, where they are surfaced in the UI, and how to use them for audit.

The audit fields on a Staff record

All Staff records (and therefore Doctor and Consultant records too) carry the following audit fields:

Field Type When set
creater WebUser Set once when the record is first saved. Captures the user who created the record.
createdAt Timestamp Set once at creation.
retirer WebUser Set when the record is soft-deleted via any of the Delete actions.
retiredAt Timestamp Set at soft-delete time.
retireComments String Free-text comment field that can hold a reason for retirement. Not exposed on every delete dialog.
dateRetired Date A second, date-only retirement field used by some HR retirements. Distinct from retiredAt.

Note that creater is spelt with one t in the schema (legacy naming). Do not "fix" it; controller code references the same column name.

Where audit fields appear in the UI

Consultant edit screen — Edit tab

In admin_doctor_consultant.xhtml, the consultant edit panel has an Edit tab next to Basic Details. It shows:

Label Value source
ID current.id
Creator current.creater.webUserPerson.nameWithTitle
Created At current.createdAt (Asia/Colombo, long date-time pattern)

This is the cleanest in-app place to read the creator stamp on a consultant.

Staff Bulk Delete grid

In staff_bulk_delete.xhtml, the Created By column shows the creator name — useful for spotting batches uploaded by a particular user when you need to mass-retire them.

Staff List / Doctor lists

The standard list grids do not show creator or retirement fields by default — these screens prioritise operational data (name, code, EPF). To audit by creator, use the database directly or use the Bulk Delete screen filter on Created By.

Retired records

Retired records are excluded from active lists, so their retirement timestamp and retirer are not visible in the UI without database access. The data is intact and queryable; an administrator can produce a report on demand.

Sample audit queries

When the in-app surfaces are not enough, use these JPQL or SQL queries:

-- All retired doctors retired in the last 90 days, with who retired them and when
SELECT s.id, p.name, w.web_user_person_id AS retirer_user, s.retired_at
FROM staff s
LEFT JOIN person p ON p.id = s.person_id
LEFT JOIN web_user w ON w.id = s.retirer_id
WHERE s.retired = TRUE
  AND s.retired_at >= NOW() - INTERVAL 90 DAY
  AND s.dtype IN ('Doctor', 'Consultant')
ORDER BY s.retired_at DESC;

-- Staff created by a specific user
SELECT s.id, p.name, s.created_at
FROM staff s
LEFT JOIN person p ON p.id = s.person_id
WHERE s.creater_id = :userId
ORDER BY s.created_at DESC;

(Column names may differ in your installation; verify against the schema.)

What audit fields do NOT capture

The current schema captures creation and retirement. It does not capture:

Event Captured?
Field-level edits (who changed the name, when) No
Signature upload / removal No (only the current image is stored)
Linked-user change No
Re-instatement (clearing retired) No — only the most recent retirement is recorded

If you need full change history (who edited what when), you must implement an external audit layer or rely on database transaction logs.

Practical audit workflows

Question How to answer
Who added this consultant? Open the Consultant editor, switch to the Edit tab, read Creator and Created At.
Who retired this doctor last week? Run the SQL above filtered to the previous week.
Was this batch of staff added by an upload? Query for staff with created_at within the upload's clock window and the same creater_id. Compare to the spreadsheet you ran.
Who keeps retiring my test doctor by accident? Restore (clear retired), then look at retirer_id if it happens again.
Has anyone been tampering with one specific record? The schema only shows the most recent creation/retirement events. Use database transaction logs for richer history.

Limitations and design notes

  • Audit data lives on the same row as the record. There is no separate audit-log table.
  • There is no editor for the audit fields in the UI; they are read-only by design.
  • retireComments is rarely populated because the Delete confirmation dialog does not collect a comment. To make use of it, scripts or a custom screen are required.
  • dateRetired (date-only) and retiredAt (timestamp) can fall out of sync if data has been edited directly. Treat retiredAt as authoritative.

Recommended administrator hygiene

  • Periodically run the retired in the last 90 days query to confirm only authorised users have retired staff.
  • Match the creator IDs on records created during bulk uploads to the user who ran the upload — flag mismatches.
  • After any direct database operation that bypasses the UI, document it externally; the schema does not record manual interventions.

Related articles

Back to Admin — Practitioner Module Configuration Overview