Privacy by design as a task in code, not in a contract
GDPR demands far more from development teams than a privacy policy. Data minimization in the database schema, a right to erasure that actually works across backups and third parties, and the ability to report within 72 hours exactly which data was affected are concrete engineering tasks. This article shows how to implement these requirements in code and in Magento architecture.
Table of Contents
- 1. Privacy by Design and by Default as a Technical Obligation
- 2. Data Minimization in the Database Schema
- 3. Pseudonymization vs. Anonymization
- 4. Right to Erasure: The Real Challenge
- 5. Erasure in Backups, Logs, and Caches
- 6. Wiring Third Parties and Processors In Technically
- 7. Notification Readiness: Preparing the 72-Hour Clock Technically
- 8. Magento Customer Data: EAV, Exports, and Erasure Tools
- 9. Technical Requirements Compared
- 10. Summary
- 11. FAQ
1. Privacy by Design and by Default as a Technical Obligation
Art. 25 GDPR requires data protection by design and by default, framed as a legal obligation but substantively a pure architecture question. Privacy by design means, concretely: before the first line of code is written, it must be clear which personal data is actually needed for which purpose, how long it will be retained, and who may access it. If this question is only asked after a data model is already in production, every later correction becomes an expensive migration instead of a deliberate design decision.
Privacy by default additionally requires that, without any active action by the user, the most privacy-friendly setting applies automatically: a newly created customer account must not be transmitted to marketing tools by default, a profile field must not be publicly visible by default. In practice, this means developers should implement the most data-sparse variant first for every new feature and make extensions such as additional tracking parameters or extended profile data explicitly opt-in, not opt-out.
2. Data Minimization in the Database Schema
Data minimization under Art. 5(1)(c) GDPR is not an abstract principle, it shows up directly in the database schema: every column that holds personal data must be tied to a clearly documented purpose. A common mistake in Magento projects is adding extra customer attributes "for later," such as a free-text field for internal notes that can in practice hold arbitrary personal information without any erasure concept for it. Every additional field expands both the attack surface and the complexity of a later erasure equally.
In practice, data minimization in schema design means: limiting required fields to what is legally and operationally necessary, encoding retention periods directly as a TTL mechanism in the system rather than only documenting them in a privacy policy, and scheduling regular data cleanup as a cron job instead of a manual, often-forgotten process. A db_schema.xml that annotates every personal-data column with a comment on its processing purpose makes later audits and DPIA assessments considerably easier.
<!-- app/code/Mironsoft/CustomerPrivacy/etc/db_schema.xml -->
<!-- Data minimization: every PII column documents its processing purpose -->
<schema xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/schema.xsd">
<table name="customer_marketing_consent" resource="default" engine="innodb"
comment="Stores only the minimum required for consent proof, no raw campaign payloads">
<column xsi:type="int" name="entity_id" padding="10" unsigned="true" nullable="false" identity="true"
comment="Purpose: primary key"/>
<column xsi:type="int" name="customer_id" padding="10" unsigned="true" nullable="false"
comment="Purpose: link to customer, required for erasure cascade"/>
<column xsi:type="boolean" name="marketing_opt_in" nullable="false" default="false"
comment="Purpose: consent flag, no raw tracking data stored here"/>
<column xsi:type="timestamp" name="consent_timestamp" nullable="false"
comment="Purpose: proof of consent timing, required for Art. 7(1) accountability"/>
<column xsi:type="varchar" name="consent_version" nullable="false" length="16"
comment="Purpose: which banner/policy version was accepted"/>
<!-- Deliberately no free-text "notes" column: no undocumented PII sink -->
<constraint xsi:type="primary" referenceId="PRIMARY">
<column name="entity_id"/>
</constraint>
<constraint xsi:type="foreign" referenceId="MARKETING_CONSENT_CUSTOMER_ID"
table="customer_marketing_consent" column="customer_id"
referenceTable="customer_entity" referenceColumn="entity_id"
onDelete="CASCADE"/>
</table>
</schema>
3. Pseudonymization vs. Anonymization
These two terms are frequently confused by development teams, even though the legal distinction is significant. Pseudonymization replaces direct identifiers with a pseudonym, while re-identification remains possible with additional knowledge, for example a separately stored mapping table. Pseudonymized data therefore still counts as personal data under GDPR and remains subject to all its requirements, but it does provide an additional protective mechanism, for instance when analytics data is processed with a customer ID instead of a real name and email address.
Anonymization, by contrast, irreversibly removes the link to a person, so that re-identification is no longer possible even with additional knowledge. True anonymization is technically far more demanding than often assumed: simply deleting name and email is not enough if a combination of IP address, order history, and timestamp still allows unique identification. Only genuinely anonymized data falls outside the scope of GDPR, which is why many supposedly "anonymized" analyses turn out, on closer inspection, to be merely pseudonymized.
4. Right to Erasure: The Real Challenge
Art. 17 GDPR requires erasure of personal data upon request, unless a statutory retention obligation applies, for example commercial or tax law retention periods for invoice data. The technical difficulty rarely lies in erasing a single record from the primary table, but in completeness: in a modern e-commerce architecture, a customer exists not only in customer_entity, but in search indexes, caches, analytics databases, email marketing tools, CRM systems, and log files. An erasure routine that only cleans the primary database table does not satisfy the requirement.
A sound erasure concept therefore requires a central data map documenting in which systems a customer's personal data can exist at all. This map is the foundation for an erasure routine that systematically works through every system, instead of researching from scratch on each request where data might live. For data subject to a statutory retention obligation, such as invoices, restriction of processing under Art. 18 GDPR is the correct mechanism instead of full erasure: the data remains stored but is blocked from all purposes except the statutory retention.
<?php
declare(strict_types=1);
namespace Mironsoft\CustomerPrivacy\Model;
use Magento\Customer\Api\CustomerRepositoryInterface;
use Magento\Framework\Exception\NoSuchEntityException;
/**
* Executes a right-to-erasure request across the primary customer record
* while respecting statutory retention obligations for invoice data.
*/
final class ErasureRequestProcessor
{
public function __construct(
private readonly CustomerRepositoryInterface $customerRepository,
private readonly RetentionObligationChecker $retentionChecker,
private readonly PiiAnonymizer $anonymizer,
private readonly ErasureAuditLogger $auditLogger
) {
}
/**
* Anonymizes erasable fields and logs the action, but keeps invoice-linked
* records intact and merely restricts them per Art. 18 GDPR.
*
* @param int $customerId Entity ID of the customer requesting erasure
* @return void
* @throws NoSuchEntityException When the customer no longer exists
*/
public function process(int $customerId): void
{
$customer = $this->customerRepository->getById($customerId);
if ($this->retentionChecker->hasActiveInvoiceRetention($customerId)) {
// Cannot fully erase: statutory retention for invoices still applies
$this->anonymizer->restrictProcessing($customer);
$this->auditLogger->logRestriction($customerId, 'invoice_retention_active');
return;
}
$this->anonymizer->anonymizeCustomer($customer);
$this->customerRepository->save($customer);
$this->auditLogger->logErasure($customerId);
}
}
5. Erasure in Backups, Logs, and Caches
Backups are the most common blind spot when implementing the right to erasure. A customer record deleted today from the live database still exists in every backup created before the deletion, potentially for months depending on the backup rotation policy. The pragmatic solution is rarely to immediately scrub every individual backup, but rather a documented, short backup retention period combined with a commitment that backups are only reactivated during a restore, paired with a process to re-apply erasure to restored records after any recovery.
Log files often unintentionally contain personal data: IP addresses, email addresses in error messages, or names in GET request URL parameters. Structured log rotation with a short retention period significantly reduces this risk, but is not sufficient on its own when a single customer requests targeted erasure. Caches such as Redis sessions or Varnish fragments holding personal data should have a short TTL so they clean themselves up within a few hours, rather than being yet another system an erasure routine must explicitly serve.
#!/usr/bin/env bash
# find-pii-in-logs.sh - Locate a customer's PII across log files for a targeted erasure request
set -euo pipefail
EMAIL="${1:?Usage: find-pii-in-logs.sh customer@example.com}"
LOG_DIRS=("/var/www/html/var/log" "/var/log/nginx")
REPORT="/tmp/pii-audit-$(date +%Y%m%d%H%M%S).txt"
echo "PII audit for: $EMAIL" > "$REPORT"
echo "Generated: $(date -u +%Y-%m-%dT%H:%M:%SZ)" >> "$REPORT"
echo "---" >> "$REPORT"
for dir in "${LOG_DIRS[@]}"; do
[[ -d "$dir" ]] || continue
echo "[scanning] $dir"
grep -rl --include="*.log" -F "$EMAIL" "$dir" 2>/dev/null | while read -r file; do
count=$(grep -c -F "$EMAIL" "$file" || true)
echo "${file}: ${count} occurrence(s)" >> "$REPORT"
done
done
echo "[done] Report written to $REPORT"
echo "[note] Review manually before deciding on redaction vs. log rotation"
6. Wiring Third Parties and Processors In Technically
Every extension, payment provider, and newsletter tool that processes customer data is a data processor under Art. 28 GDPR and must be wired into the erasure concept both contractually and technically. The most common technical mistake: a customer is transmitted to a payment provider or newsletter tool via API at checkout, but no reverse path exists that removes the external record at the provider when an erasure request comes in. Without a documented, automated erasure API integration, erasure stays confined to your own system while the data persists indefinitely at the third party.
In practice, this means for every integration: checking whether the provider offers an erasure or anonymization API, wiring that API into your own erasure pipeline, and attaching concrete technical deadlines for data erasure to the data processing agreement (DPA) rather than relying on generic wording alone. For providers without an erasure API, a manual request via support ticket often remains the only option, which should be an explicit, documented step with deadline tracking in every erasure process.
7. Notification Readiness: Preparing the 72-Hour Clock Technically
Under Art. 33 GDPR, a personal data breach must be reported to the supervisory authority within 72 hours of becoming aware of it. The technical prerequisite for a timely, substantively correct report is a system that can answer, at any point in time, which data was affected to what extent, not only after days of manual analysis. Without structured logging of data access and without a current data inventory (a record of processing activities under Art. 30), the deadline passes while the team is still figuring out which tables were even affected.
Notification readiness concretely means: audit logs documenting who accessed which customer records and when, a current inventory of all systems holding personal data, and a prepared template for the initial report that can be filled in with incomplete but provisional information. The report may explicitly be filed in stages, but only if an initial, timely report is possible at all, which rarely succeeds without technical preparation.
{
"breach_readiness_checklist": {
"data_inventory": {
"last_updated": "2026-07-12",
"systems": [
{ "name": "magento_customer_db", "pii_categories": ["name", "email", "address", "order_history"] },
{ "name": "newsletter_provider", "pii_categories": ["email", "consent_status"] },
{ "name": "payment_gateway", "pii_categories": ["masked_card", "billing_address"] },
{ "name": "application_logs", "pii_categories": ["ip_address", "email_in_error_traces"] }
]
},
"access_audit_logging": {
"enabled": true,
"retention_days": 180,
"covers": ["admin_grid_customer_view", "api_customer_export", "support_ticket_lookup"]
},
"notification_template_ready": true,
"authority_contact": {
"name": "Data Protection Authority",
"notification_channel": "online_portal",
"sla_hours": 72
},
"dpo_escalation_minutes": 30
}
}
8. Magento Customer Data: EAV, Exports, and Erasure Tools
Magento's EAV data model (Entity-Attribute-Value) spreads customer attributes across multiple tables by data type, which complicates erasure routines that naively address only customer_entity. Custom customer attributes end up in customer_entity_varchar, customer_entity_int, customer_entity_text, or customer_entity_datetime depending on their type, and complete erasure requires either using the standard repository methods that correctly handle this distribution, or explicitly checking every EAV table in a custom implementation. In addition, customer data remains in sales_order, sales_order_address, and related tables even after a customer account is deleted, since order data is subject to its own retention periods.
For data export under Art. 15 GDPR (right of access), a central service that aggregates all relevant data sources is preferable to manually searching database tables on every request. Importantly, such an export service must also account for custom modules: every custom module holding a customer_id foreign key relationship must plug into the central export and erasure process, ideally via a defined interface that is mandatory during module development.
<?php
declare(strict_types=1);
namespace Mironsoft\CustomerPrivacy\Api;
/**
* Contract every module storing customer-linked PII must implement so the
* central export and erasure pipeline can discover and process its data.
*/
interface CustomerDataProviderInterface
{
/**
* Exports all personal data this module holds for a given customer.
*
* @param int $customerId Entity ID of the customer requesting a data export
* @return array<string, mixed> Structured data, ready to include in an Art. 15 export
*/
public function exportData(int $customerId): array;
/**
* Erases or anonymizes all personal data this module holds for a given customer.
*
* @param int $customerId Entity ID of the customer requesting erasure
* @return bool True if fully erased, false if restricted due to retention obligations
*/
public function eraseData(int $customerId): bool;
}
9. Technical Requirements Compared
Many GDPR requirements are implemented in practice only formally, without becoming technically effective. The following overview contrasts common misconceptions with the technical implementation actually required.
| Requirement | Not Sufficient | Technically Correct | Why |
|---|---|---|---|
| Right to Erasure | Only delete customer_entity | Central erasure pipeline across all modules/systems | Data lives in EAV, logs, caches, third-party systems |
| Privacy by Default | Marketing opt-in pre-selected | All non-essential processing off by default | Art. 25(2) requires a data-sparse default setting |
| Notification Readiness | Manual research during the incident | Current data inventory plus audit logs | 72 hours is not enough for after-the-fact research |
| Anonymization | Only remove name/email | Check combination risk (IP, history, timestamp) | Re-identification via data combination is possible |
| Third-Party Data | DPA without a technical erasure API | Automated erasure API integration anchored in the contract | A contract alone does not delete any records |
Mironsoft
GDPR technical audits and privacy engineering for Magento stores
Is GDPR actually covered technically?
We review your data model for data minimization, build a central erasure and export pipeline across all modules and third parties, and prepare your team for the 72-hour notification deadline with a current data inventory.
Data Model Audit
Reviewing data minimization and retention periods in the schema
Erasure Pipeline
Building a central erasure and export interface for all modules
Notification Readiness
Setting up a data inventory and audit logging for the 72-hour deadline
10. Summary
The technical requirements of GDPR are not solved by an updated privacy policy, but by concrete architecture decisions. Privacy by design and by default require thinking about data minimization from the very first schema decision, rather than fixing it retroactively. The right to erasure is only technically fulfilled once a central pipeline reaches every system where personal data can exist, including backups, logs, caches, and third-party integrations, not just the primary customer table.
Notification readiness under Art. 33 GDPR is a question of preparation, not reaction speed in an emergency: without a current data inventory and audit logging, the 72-hour deadline passes while the team is still figuring out which systems were even affected. For Magento stores, this concretely means wiring EAV attributes, sales data, and custom modules into export and erasure processes through a unified interface, instead of researching from scratch on every request where customer data might live.
GDPR Technical Requirements, the Key Points at a Glance
Privacy by Design
Data minimization from the first schema decision onward, a data-sparse default without any active action by the user.
Right to Erasure
A central pipeline across the database, backups, logs, caches, and third parties, not just the primary table.
72-Hour Deadline
A current data inventory and audit logging are prerequisites for a timely, substantively correct report.
Magento EAV
Erasure and export across all EAV tables and custom modules via a unified interface, not just customer_entity.