BEFORE TRIGGER on DELETE statement
There are many ways.  All "work":


Add a deleted column.  (This may have performance problems in the long run.)
Have the application move the row to another table.  (Poor man's Trigger; error prone.)
Trigger that copies the row to another table.  (Clumsy, slow, needs transaction.)  And, as you ask, what about the deleting the row.
Stored Procedure to "delete" a row.  (Users must call it; need to deny DELETE PRIVILEGE to everyone except the Procedure.)
Application procedure.
My preference for big, multi-user, applications:


I like the "database layer" in the application.  Instead of letting the users perform actual SQL statements, require them to call APIs in application code (PHP/Java/whatever).  This way, changes to the underlying schema can be changed with little or no retraining of the users.

If the API is "Delete(key)", then the "layer" could deal with a new deleted column, or moving the row to new table or calling a stored proc instead of issuing DELETE FROM tbl ....  Etc.

And if I decide that the solution picked is less than perfect, I can change it without even informing the users.