Forget me, please? Event sourcing and the GDPR

Forget me, please? Event sourcing and the GDPR

In May 2018, a new piece of EU legislation called the General Data Protection Regulation (GDPR) has come into effect. The GDPR attempts to regulate data protection for individuals within the EU and has very interesting and specific implications for applications that use event sourcing. In that context, the most interesting and challenging part of the regulation is without a doubt Article 17, the ‘right to erasure’: the right for individuals to request that their data be removed from the databases of a company.

In this talk, I’ll discuss my thoughts on the GDPR and give a few helpful pointers and tips!

2f4800411154a8c66dde489448a044d2?s=128

Michiel Rook

October 10, 2018
Tweet

Transcript

  1. 3.
  2. 5.

    ' Regulation (EU) 2016/679 of the European Parliament and of

    the Council of 27 April 2016 on the protection of natural persons with regard to the processing of personal data and on the free movement of such data, and repealing Directive 95/46/EC (Data Protection Directive) -General Data Protection Regulation
  3. 16.

    ' The controller shall implement appropriate technical and organisational measures

    for ensuring that, by default, only personal data which are necessary for each specific purpose of the processing are processed. -GDPR, Article 25
  4. 19.
  5. 21.

    YOU

  6. 24.

    read CQRS / Event Sourcing theory followed a tutorial, built

    a hobby project RAISE YOUR HAND IF YOU HAVE
  7. 25.

    read CQRS / Event Sourcing theory followed a tutorial, built

    a hobby project used it in production RAISE YOUR HAND IF YOU HAVE
  8. 28.
  9. 34.

    Domain UI Event Bus Event Handlers Command Repository Database Database

    Event Store commands events events Aggregates @michieltcs
  10. 35.

    Domain UI Event Bus Event Handlers Command Repository Data Layer

    Database Database Event Store commands events events queries DTOs Aggregates @michieltcs
  11. 37.

    ' Event Sourcing ensures that all changes to application state

    are stored as a sequence of events. -Martin Fowler
  12. 38.

    ACTIVE RECORD VS. EVENT SOURCING Account Id Account number Balance

    1234 12345678 €50,00 ... ... ... Money Withdrawn Account Id 1234 Amount €50,00 Money Deposited Account Id 1234 Amount €100,00 Account Opened Account Id 1234 Account number 12345678 @michieltcs
  13. 39.

    COMMANDS TO EVENTS Deposit Money Account Id 1234 Amount €100,00

    @michieltcs 1 @Value 2 public class DepositMoney { 3 @TargetAggregateIdentifier 4 String accountId; 5 BigDecimal amount; 6 }
  14. 40.

    COMMANDS TO EVENTS Deposit Money Account Id 1234 Amount €100,00

    command
 handler @michieltcs 1 @CommandHandler 2 public void depositMoney(DepositMoney command) { 3 apply(new MoneyDeposited( 4 command.getAccountId(), 5 command.getAmount(), 6 ZonedDateTime.now())); 7 }
  15. 41.

    COMMANDS TO EVENTS Deposit Money Account Id 1234 Amount €100,00

    Money Deposited Account Id 1234 Amount €100,00 command
 handler @michieltcs 1 @Value 2 public class MoneyDeposited { 3 String accountId; 4 BigDecimal amount; 5 ZonedDateTime timestamp; 6 }
  16. 43.

    AGGREGATES @michieltcs 1 class BankAccount { 2 @AggregateIdentifier 3 private

    String accountId; 4 private String accountNumber; 5 private BigDecimal balance; 6 7 // ... 8 @EventHandler 9 public void accountOpened(AccountOpened event) { 10 this.accountId = event.getAccountId(); 11 this.accountNumber = event.getAccountNumber(); 12 this.balance = BigDecimal.valueOf(0); 13 } 14 15 @EventHandler 16 public void moneyDeposited(MoneyDeposited event) { 17 this.balance = this.balance.add(event.getAmount()); 18 } 19 }
  17. 44.

    AGGREGATE STATE Account number Balance 12345678 €0,00 Account number Balance

    12345678 €100,00 Account number Balance 12345678 €50,00 event
 handler event
 handler event
 handler @michieltcs Money Withdrawn Account Id 1234 Amount €50,00 Money Deposited Account Id 1234 Amount €100,00 Account Opened Account Id 1234 Account number 12345678
  18. 45.

    VALIDATING COMMANDS @michieltcs 1 @CommandHandler 2 public void withdrawMoney(WithdrawMoney command)

    throws 3 OverdraftDetectedException { 4 if (balance.compareTo(command.getAmount()) >= 0) { 5 apply(new MoneyWithdrawn( 6 command.getAccountId(), 7 command.getAmount(), 8 ZonedDateTime.now())); 9 } else { 10 throw new OverdraftDetectedException(accountNumber, balance, command. 11 getAmount()); 12 } 13 }
  19. 46.

    TESTING AGGREGATES @michieltcs 1 public class BankAccountTest { 2 private

    FixtureConfiguration<BankAccount> fixture; 3 4 @Before 5 public void createFixture() { 6 fixture = new AggregateTestFixture<>(BankAccount.class); 7 } 8 9 @Test 10 public void noOverdraftsOnEmptyAccount() { 11 fixture.given(new AccountOpened(ACCOUNT_ID, ACCOUNT_NUMBER)) 12 .when(new WithdrawMoney(ACCOUNT_ID, new BigDecimal(20))) 13 .expectException(OverdraftDetectedException.class); 14 } 15 16 private final static String ACCOUNT_ID = "accountId"; 17 private final static String ACCOUNT_NUMBER = "accountNumber"; 18 }
  20. 48.
  21. 49.

    ' Where processing is based on consent, the controller shall

    be able to demonstrate that the data subject has consented to processing of his or her personal data. -GDPR, Article 7
  22. 51.

    ' ...the request for consent shall be presented in a

    manner which is clearly distinguishable from the other matters... -GDPR, Article 7
  23. 53.

    ' The data subject shall have the right to withdraw

    his or her consent at any time. ... It shall be as easy to withdraw as to give consent. -GDPR, Article 7
  24. 64.

    ' The data subject shall have the right to obtain

    from the controller confirmation as to whether or not personal data ... are being processed, and ... access to the personal data ... -GDPR, Article 15
  25. 66.

    ' The data subject shall have the right to obtain

    from the controller the erasure of personal data concerning him or her without undue delay -GDPR, Article 17
  26. 68.

    ' ‘personal data’ means any information relating to an identified

    or identifiable natural person; an identifiable natural person is one who can be identified, directly or indirectly -GDPR, Article 4
  27. 69.
  28. 70.

    ' .. the personal data are no longer necessary ..

    the data subject withdraws consent on which the processing is based -GDPR, Article 17
  29. 72.

    ' .. to comply with a legal obligation .. for

    the establishment, exercise or defence of legal claims (*) -GDPR, Article 17
  30. 75.
  31. 80.
  32. 84.

    @michieltcs Ledger Entry Aug 14 Inventory €15600,00 Accounts Payable €15600,00

    Ledger Entry Aug 14 Inventory €16500,00 Accounts Payable €16500,00
  33. 85.

    @michieltcs Ledger Entry Aug 14 Inventory €15600,00 Accounts Payable €15600,00

    Ledger Entry Aug 14 Inventory €16500,00 Accounts Payable €16500,00 Ledger Correction Entry Aug 14 Inventory €900,00 Accounts Payable €900,00
  34. 86.

    COMPENSATING ACTIONS class MoneyWithdrawn {
 String accountId;
 BigDecimal amount;
 }

    class WithdrawalRolledBack {
 String accountId;
 BigDecimal amount;
 } Typo: too much withdrawn!
  35. 87.

    COMPENSATING ACTIONS class AccountOpened {
 String accountId;
 String accountNumber;
 }

    class DuplicateAccountClosed {
 String accountId;
 } Duplicate account number!
  36. 88.
  37. 92.

    ' .. adequate, relevant and limited to what is necessary

    in relation to the purposes for which they are processed (‘data minimisation’) -GDPR, Article 5
  38. 103.

    VERSIONED EVENT STORE events_v1 [
 {
 "id": "12345678",
 "type": "AccountOpened",


    "aggregateType": "Account",
 "aggregateIdentifier": "1234",
 "sequenceNumber": 0,
 "payloadRevision": "1.0",
 "payload": { ... },
 "timestamp": ...
 ...
 },
 ...
 ] @michieltcs
  39. 105.

    VERSIONED EVENT STORE Loop over existing events Apply upcaster Add

    queued events Use new event store New events Queue @michieltcs
  40. 106.

    VERSIONED EVENT STORE events_v2 [
 {
 "id": "12345678",
 "type": "AccountOpened",


    "aggregateType": "Account",
 "aggregateIdentifier": "1234",
 "sequenceNumber": 0,
 "payloadRevision": "2.0",
 "payload": { ... },
 "timestamp": ...
 ...
 },
 ...
 ] @michieltcs
  41. 108.

    STORE PII EXTERNALLY @michieltcs 1 @Value 2 public class AccountOpened

    { 3 String accountId; 4 String accountNumber; 5 String name; 6 }
  42. 110.

    STORE PII EXTERNALLY @michieltcs AccountOpened External Storage 1 @Value 2

    public class AccountOpened { 3 String accountId; 4 } Account Id Account number Name 1234 12345678 John Doe ... ... ...
  43. 111.

    STORE PII EXTERNALLY @michieltcs AccountOpened External Storage 1 @Value 2

    public class AccountOpened { 3 String accountId; 4 } Account Id Account number Name 1234 12345678 ANON ... ... ...
  44. 112.

    STORE PII EXTERNALLY @michieltcs AccountOpened External Storage 1 @Value 2

    public class AccountOpened { 3 String accountId; 4 } Account Id Account number Name 1234 12345678 ANON ... ... ...
  45. 120.
  46. 122.

    SHEDDING THE KEY Load
 event Find associated encryption key Decrypt

    payload values Process
 event @michieltcs X
  47. 123.

    AXON GDPR MODULE @michieltcs 1 @Value 2 public class AccountOpened

    { 3 @DataSubjectId 4 String accountId; 5 6 @PersonalData 7 String accountNumberIban; 8 9 @PersonalData 10 String firstName; 11 12 @PersonalData 13 String lastName;
 14 }
  48. 128.
  49. 129.
  50. 134.