Developer notes
File map
Section titled “File map”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 upgradesdesign/backend/templates/addons/kv_admin_activity_log/ views, components, settings info, licence UIdesign/backend/css/addons/kv_admin_activity_log/styles.lessvar/langs/en/addons/kv_admin_activity_log.poHow a request is recorded
Section titled “How a request is recorded”before_dispatch: for POST requests of the admin and vendor panels (and the GET eventsprofiles.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 ofproducts_data,tools.update_statustable + id and so on). GET requests return after two comparisons, without any database query.- Core
*_prehooks take before snapshots of objects the request did not name;*_posthooks 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). - 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_eventsplus 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 intry/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.
Tables
Section titled “Tables”| 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.
Core hooks used
Section titled “Core hooks used”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 chain
Section titled “Hash chain”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.
Performance
Section titled “Performance”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).
Template overrides
Section titled “Template overrides”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-.
License check
Section titled “License check”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).