Skip to content
Deedboxlatest

Erase a person

This guide shows you how to store personal data so that you can erase one person later, even when their data sits inside streams you must keep.

public record ReviewerInvited(
string ManuscriptId,
[property: DataSubject] string ReviewerId, // whose data this is
[property: PersonalData] string ReviewerName, // encrypted under ReviewerId's key
[property: PersonalData] string? ReviewerEmail);

[DataSubject] marks whose data the event carries. Each [PersonalData] field is encrypted under that subject’s own key. A personal-data property must be a string or nullable, because it reads as null after erasure.

Use person IDs, not role IDs, as subjects. One erasure then covers every role a person has.

// Several subjects in one event: name each field's subject property.
public record CoAuthorAdded(
string ManuscriptId,
string AuthorId,
[property: PersonalData(Subject = "AuthorId")] string AuthorName,
string EditorId,
[property: PersonalData(Subject = "EditorId")] string? EditorNote);

Start-up fails until you choose one (DBX025).

services.AddDeedbox(es => es
.UsePostgres(connStr)
.Keys(keys => keys.StoreInDatabase())
.Stream<Manuscript>(s => s.Events<ReviewerInvited, CoAuthorAdded>()));

StoreInDatabase keeps the master key in the same database. Erasure works, but a copy of the database exposes personal data. Move to a key ring or Azure Key Vault before production:

// DEEDBOX_MASTER_KEY holds a key ring: v2:<base64 of 32 random bytes>,v1:<older key>
services.AddDeedbox(es => es
.UsePostgres(connStr)
.Keys(keys => keys
.FromEnvironment("DEEDBOX_MASTER_KEY")
.RedactWith("[erased]"))
.Stream<Manuscript>(s => s.Events<ReviewerInvited, CoAuthorAdded>()));

See rotate keys to move between modes.

// Their data reads as erased as soon as this returns; the job finishes the rest.
var jobId = await erasure.EraseSubjectAsync("person:8421");
  1. Deedbox deletes the subject’s key and clears the stored state of every stream with their data, in one transaction. From then on, every read returns their fields as null (or the RedactWith placeholder).
  2. A job appends a SubjectErased event to each of those streams and stores rebuilt state. Handle SubjectErased in your projections to scrub what they stored.
  3. The job resumes after a crash.

From the CLI: deedbox erase person:8421 --tenant acme.

  • Backups taken before an erasure still hold the subject’s key until they age out. Set your backup retention with this in mind.
  • Metadata and subject IDs are not encrypted. Use pseudonymous IDs such as person:8421.
  • Only top-level properties are encrypted.
  • Data written about the subject after the erasure uses a new key and stays readable.