Skip to content

Developer notes

← Overview

app/addons/kv_admin_activity_log/
addon.xml settings, 2 tables, 2 privileges, 1 e-mail template, uninstall function
init.php / func.php hooks, History tab helper, cron info, licence helpers
controllers/backend/kv_admin_activity_log.php log, entry, History tab (AJAX), CSV, verify, purge, cron
controllers/backend/{products,orders,profiles,categories,companies}.post.php History tabs
controllers/backend/kv_admin_activity_log_license.php "Check now" and licence cron
schemas/menu/*.post.php Administration menu, vendor panel menu
schemas/permissions/*.post.php privileges, vendor modes, cron as trusted controller
Tygh/Addons/KvAdminActivityLog/
Config.php settings access
Tracker.php per-request capture: context, before/after snapshots, direct diffs, the single write
Snapshots.php whitelisted fields per object type and the diff
Masker.php secret masking and size limits of the request data
Repository.php append-only storage, hash chain, search, purge, integrity check, retention
Alerts.php alert rules and e-mail
Labels.php / Presenter.php labels, links, diff rows, CSV export
StorageData.php run marks (files instead of storage_data while the full page cache is on)
License/, Upgrade/ licence client, self-healing upgrades
design/backend/templates/addons/kv_admin_activity_log/ views, components, settings info, licence UI
design/backend/css/addons/kv_admin_activity_log/styles.less
var/langs/en/addons/kv_admin_activity_log.po
  1. before_dispatch: for POST requests of the admin and vendor panels (and the GET events profiles.act_as_user, profiles.login_as_vendor, auth.logout) the add-on stores the request context and takes before snapshots of the objects named in the request (product_id, product_ids[], the keys of products_data, tools.update_status table + id and so on). GET requests return after two comparisons, without any database query.
  2. Core *_pre hooks take before snapshots of objects the request did not name; *_post hooks mark ids that had no snapshot as created; delete hooks snapshot the object before it goes. Settings, add-on status, installs/uninstalls and user group memberships are recorded directly from the hook arguments (old and new value).
  3. At the end of the request (register_shutdown_function) the add-on reads the after snapshots, builds the field diff and writes one row into ?:kv_aal_events plus one multi-row insert into ?:kv_aal_objects (the object index of the History tabs). Up to 200 objects per request get diffs; further objects are counted. Every step is wrapped in try/catch: a capture error never breaks a request.

REST API requests (no dispatch) start the context from the first hook. Storefront requests (AREA C) are never recorded.

Table Contents
?:kv_aal_events One row per entry: time, user (ID, type, name and e-mail at the time), company, act-on-behalf flag, source, method, dispatch, action, primary object, counts, result, IP, browser, masked request JSON, changes JSON, alert flag, prev_hash, hash
?:kv_aal_objects (object_type, object_id, event_id): every object of an entry

Both are InnoDB. changes is a JSON list of {t: type, i: id, l: label, o: c|u|d, f: {field: [old, new, flags]}}; flag x = secret (values hidden), h = hash only, t = text excerpt.

before_dispatch, update_product_pre, update_product_post, delete_product_pre, update_category_pre, update_category_post, delete_category_pre, change_order_status, pre_update_order, place_order, delete_order, update_user_pre, update_profile, delete_user, change_usergroup_status_post, update_usergroup_pre, update_usergroup, delete_usergroups_pre, settings_update_value_by_id_pre, update_addon_status_post, install_addon_post, uninstall_addon_pre, update_payment_pre, update_payment_post, delete_payment_pre, update_shipping, update_shipping_post, update_promotion_pre, update_promotion_post, delete_promotions_pre, update_company_pre, update_company, change_company_status_pre, delete_company_pre, tools_update_status_before_query. All exist with the same arguments in 4.17.2 and 4.21.2; update_payment_pre/_post have two extra trailing arguments in 4.21, which the handlers accept as optional.

The core ?:logs table and fn_log_event() are not used or changed.

hash = HMAC-SHA256(prev_hash | the entry's columns) with a key derived from $config['crypt_key'] (config.local.php), so someone with database access only cannot recompute valid signatures. Writes take a short GET_LOCK around reading the last hash and inserting. A purge stores an anchor (the first remaining entry and its prev_hash) that the integrity check compares with. The alerted flag is not signed.

Measured on the development stores (PHP 8.1/8.3, MariaDB): a GET request in the admin panel adds about 0.3 µs; a product save adds about 3.5 ms in total for the snapshots, the diff and the two inserts. The log list uses indexed queries (time, user, object, company, action).

The pages use only the add-on’s own templates under design/backend/templates/addons/kv_admin_activity_log/. CSS classes start with kv-aal-.

fn_kv_admin_activity_log_is_licensed() (License\Client::isActive()) together with the Record activity setting gates the recording and the alert e-mails. The log, the entry pages, the History tabs, the CSV export, the purge, the retention task and the integrity check always work. The licence check itself runs only in the admin panel or from cron (php admin.php --dispatch=kv_admin_activity_log_license.check).