The row in users. Then orders, with the delivery address and phone. Then nginx access logs with emails inside GET parameters of an old unsubscribe endpoint. That is how far I got in the first ten minutes of drawing where one user’s data lives on one project, and the map did not fit on one page.
May 25 is close and everyone discusses consent banners. The lawyers can have the banners. The engineering part is the right to erasure. “Delete the user” sounds like one DELETE statement until you sit down with a pen.
The rest of my map: application logs where somebody dumped whole request bodies “for debugging”. Redis queue payloads, serialized with name and email inside. The analytics events table. A denormalized customer_name column in orders, copied at purchase time so old orders keep the name from that moment. Backups of all of the above. The mail provider with its own delivery logs.
It helps to classify: source of truth, derived data, audit records. For derived data the answer is usually simple, delete it or let it expire. Audit and financial records are the opposite case. Accounting law requires keeping orders for years, so the user is anonymized and the transaction stays. Which also means no naive ON DELETE CASCADE from users, or one erasure request eats order history you are legally required to keep. Foreign keys do not know about accounting law.
Backups are the honest edge case. You cannot edit last month’s dump. The workable answer is retention: backups expire after N days, so erasure is fully complete after N days. Write that into the policy instead of pretending backups do not exist.
Draw the map before the first real request arrives. It is an afternoon of work when nobody is waiting. The “for debugging” log line, by the way, was mine, from 2016. It is still there.