What it does
avo-audit_loggingWhen finance asks who changed a balance, or support asks who looked at an account, the answer is on the record. Turn it on, opt a resource in with one line, and Avo records every visit, edit, delete, attach, detach, and action run on it, with the author and the time. A Timeline in the record's sidebar shows the trail, and a click on any entry opens the full payload.
It sits on top of paper_trail or audited, whichever your app already has, so the per-attribute history stays in tables you know. With paper_trail, an update shows its changeset as a diff and an admin can undo it, within their own permissions. A change made over the MCP server, the API, or the AI chat is tagged with where it came from, so the timeline reads "Ada Lovelace through MCP connection" next to the clicks. Your agent writes the opt-in; the trail, the diff, and the undo come with the foundation.
What it looks like in your resource
Two switches, both on: the global flag in the initializer, then the opt-in on each resource or action you want tracked. The Timeline tool and the activities table are how the record shows what happened to it.
# config/initializers/avo.rb
Avo::AuditLogging.configure do |config|
config.enabled = true
end
# app/avo/resources/product.rb
class Avo::Resources::Product < Avo::BaseResource
self.audit_logging = { activity: true }
def fields
panel do
card do
field :name, as: :text
field :price, as: :number
end
sidebar do
tool Avo::ResourceTools::Timeline
end
end
field :avo_activities, as: :has_many
end
end
What you get
-
Every
index,show,create,update,destroy,attach,detach, and action run on an opted-in resource, recorded with its author, a timestamp, and a payload. Trim any of them with theactions:key, or decide per request with a lambda. -
A
Timelinesidebar tool on the record, anavo_activitiestable, anavo_authoredtable on the user resource for everything one person did, and anavo_activityresource for a global feed in the menu. -
A changeset diff on update activities and an Undo action that restores the previous version, with paper_trail. Both follow the record's policy: no
update?, no undo, and fields the policy hides stay out of the diff and the payload. -
An origin on activity that didn't come from a click in the admin:
mcp_connection,api_token(orapi, for a request your own scheme let in without a token), andai_chatare tagged automatically and link to the connection, token, or chat. Name your own withAvo::AuditLogging::Origin.with. -
Avo::AuditLogging.recordfor a change made by a job, an importer, or a service object, so the trail covers the work nobody clicked. -
One or several author models through
config.author_models, an install generator that adds paper_trail when it isn't already in the app, and an upgrade generator that writes only the migration you are missing.
When paper_trail or audited alone is enough
Avo's audit logging runs on one of them, so this is not a choice between the two. It is whether you need the layer on top. Often you don't.
- You need model history, not admin activity.
- paper_trail and audited record a change wherever it happens: a controller, a console session, a background job. Avo's layer records what happens in the admin, plus whatever you send it through
record. If nobody acts on your data through Avo, the versions table already tells the whole story. - Only engineers will ever read it.
- Both gems store rows you query in the console, and you can show them as an association on the resource. If "who changed this" is a question an engineer answers once a quarter, that is enough. The layer on top is for the week when support, finance, or an auditor need the answer without you.
- Nobody asks who viewed a record.
- A versions table records writes. Index and show visits exist only in Avo's activities, and that is the question health, finance, and HR data tends to get asked. If your bar stops at changes, skip the layer.
- You are on Community or Pro.
- Audit logging is an Enterprise feature. On Community or Pro, show paper_trail's versions or audited's audits as a
has_manyon the resource, through a small resource for the version model, and your team has a readable change history inside the admin today. With paper_trail, also set the whodunnit in Avo's controllers, or the history won't say who.
Why it pays off
- Permissions decide who sees what, the AI chat waits for someone to click Confirm, and every change leaves a trail your team can read back. The policy that scopes a record scopes its history too.
- Your agents leave the same trail as your team. A write over MCP, the API, or the AI chat is tagged with where it came from, with nothing to configure, so you can hand an agent the admin and still answer "who did this" on Monday.
- The compliance question becomes a lookup. When an auditor, a partner bank, or a customer asks what happened to a record, the answer is its timeline, in your own database, instead of a search across logs.
-
Built for many apps, so the edge cases are handled: a job with no current user, an author model that is not
User, a field the policy hides, an upgrade that needs only the migration it is missing.