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
Summary
Spree::Addressrows 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, andreverse_charge_statuswere 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
spree_addressestable. 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.Open Questions
solidus_gdpris 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