Libraries for tracking changes to records?

I’m trying to implement a feature in my LiveView app that shows “activity” for that record such as changes and comments. Ideally, any changes will show the before/after values in an easy-to-read format, similar to git commit changes. Here’s an example from Airtable:

I’m wondering if there are any libraries that can help me with this, or if it’s something I’ll have to tackle all from scratch? There are quite a lot of models in my app that I need this form of paper-trail tracking implemented for, so just doing it as a feature per model seems like a bad approach.

1 Like

The most righteous solution, if you are using Postgres, would be to implement a trigger function which writes the changes to a separate table.

Otherwise you would be at the mercy of the application code actually logging 100% of the time.

Well, obviously I’m not much for being righteous because I’m using SQLite for storage on this app (for a lot of other very good reasons) :sweat_smile:

Assuming you’re using Ecto to manage your data schemas, you could utilize a library like ecto_diff to determine the differences between ecto structs, then build a simple model to record the lifecycle changes.

You can use something like

old_words = String.split(old_text)
new_words = String.split(new_text)
diff = List.myers_difference(old_words, new_words)

There is also paper_trail. :slight_smile:

The thing about using paper_trail is that if you have a mixture of PKs that are integers and uuids, you need two version tables to track them. It’s best to pick one format and stick with it and pray you never change.

I haven’t tried it with tracking compound pk entities, but I suspect it is also problematic.

1 Like

Thanks, and then I’d just wrap each context that needs a diff with a transaction that saved both the diff and the model?

Paper trail seems interesting, I’m not sure that I necessarily need to keep every historical version of every record. I’m thinking maybe I can just make a Ecto Repo that has Repo.insert() and Repo.update() insert “changes” into the database in a transaction