A review for revisionssicher logging asked that the trail answer who, when,
what exactly and from which client IP. Edit asset logged only "Asset
updated", asset and finding actions carried no IP (only logins did), a
deleted user's rows turned into "System/Auto", a manual decommission was
logged as a system action, and a settings change left no row at all.
Every audit row with a user_id now gets the actor's username, client IP and
user agent stamped on insert (before_insert listener, fed by an app-wide
dependency that runs after ProxyHeadersMiddleware), so no writer can forget
them. The username is a snapshot column (migration 065, backfilled), so it
survives delete_user. Rows without a user (sync, scheduler) stay as before.
Asset edits, single and bulk, record each changed field old -> new; a manual
status change carries the user. A settings PUT writes CONFIG_CHANGE with the
changed field names and old/new values whose secret subfields are masked for
every key (ai_config is unprotected and holds api_token). An unchanged
re-save writes nothing. The syslog message carries user=.