Skip to content

Single-owner copy-on-write addresses #6591

Description

@jarednorman

Summary

Spree::Address rows are considered immutable value objects. They deduplicated and shared across owners. Multiple users, orders and other records that hold references to addresses may all hold references to the same rows if they all share the same address data. Because of this, addresses can't really be considered as "owned" by anyone and cannot be safely modified or deleted.

This RFC proposes making every address row belong to exactly one logical owner. Addresses will remain immutable under this proposal. We can keep the value-based comparison semantics. What changes is that we don't reuse addresses across owners and that we use copy-on-write semantics for mutations.

Motivations

Under various privacy laws, we need to be able to delete or partially delete addresses. Under the existing system, we may have addresses where we simultaneously need to keep and delete/obfuscate an address because it's owned by multiple owners. We can remove the join record, but that still preserves the data in the system. This was primarily discussed in #6108.

Sharing also leads to data leakage. Operators may wish to augment the address records with additional data, like tax IDs or other information. If they aren't careful in implementing this, this could leak data between users. The API also can't support temporary (non-persisted) checkout addresses (#2845) partly because order and address book rows are so entangled.

We're actually already storing some user-specific data on these rows. vat_id, email, and reverse_charge_status were added to addresses last year. These are attributes of some person's address, not just a location. These fields are in the deduping key (so this works correctly), but they demonstrate how this design doesn't make sense. Any future owner-specific field faces the same hazard. Single ownership removes this class of problem structurally.

Proposal

  • When an operation is semantically creating an address (which can currently result in a reference to an existing address), it will create an address.
  • When an operation is semantically updating an address (which can currently result in a reference to an existing address), it will create a new address with attributes copied from the existing address.
  • Addresses stay immutable. If a user makes a purchase, then later "updates" their default shipping address, this creates a new record and doesn't mutate the data of the existing order.
  • We can provide a way to clean up unreferenced rows if we want. This is optional, but is a good idea. This would require an extensible registry so that extensions that have their own foreign keys into the spree_addresses table. We need to be careful with this, but it would give an avenue to cleaning up the large number of addresses that can pile up under the current system. This must be opt-in.
  • We implement compliant address anonymization in core. Store operators have a legitimate interest to preserve certain information but can fully remove other information. If a customer makes a deletion request, we should be able to remove addresses with no references (as determined by the registry) and anonymize addresses where the operator has a legitimate interest in partial address data.

Open Questions

  • How much of the anonymization work belongs in core? solidus_gdpr is great, but as more regions have adopted similar legislation, I believe we should provide base functionality that covers a broad number of cases in Solidus itself.

Related Issues

Prior Work

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions