Separate your notion of the model's source data, and the current display data of an instance of that model.
The source model is like a platonic ideal. Perfect, archetypal, and unchanging.
You do not sully this perfect ideal with every wiggle of a transform handle. You do not write to it at all, unless the user specifically asks you to "apply" or "bake" the transformation down into the source data.
You store the transformation components of an instance of the model separately, along with the positions of its transformed vertices. The instance stores a reference back to its source data, and many differently-transformed instances can refer back to the same source data.
When the transformation data changes (position, rotation, scale, or other more exotic transformations if you use them), you read the source data, run it through the transformation matrix, and write it into the transformed data. No data is lost this way because you do not overwrite the source data.
This also prevents rounding errors from accumulating and distorting your model.
If you want to apply changes the user makes to the transformed vertices back to the source model data, you can run the new vertex positions through the inverse transformation matrix to put them back in the source data's coordinate space. You'll just need a little special handling for the case where the user makes the matrix non-invertable, by flattening the model into a plane for instance - there they can still move the vertex in the two axes parallel to the plane, just not perpendicular to the plane, and you can still map those back to a corresponding position in the source model.