I did it with a timestamp on the tables that was captured at insert time. All reads were against views of the tables that were defined such that the only tuples returned were the "most recent" tuples by appropriate data fields and max(timestamp). "Deleted" records were just indicated by a flag.
This preserved the ability see the full history for a tuple from creation, all mutations, all the way to deletion. This scaled reasonable well up to low millions of tuples on a normal, single database server. But it was for an internal project, so the number of clients hammering at it was quite low.