Part 2 · Before Any Code

2 · Design

Decisions made before code is written. This is where the cheapest privacy choices are made and the most expensive mistakes get locked in. A retention default, a region, a subject-ID scheme: minutes at the whiteboard, weeks to undo in production. Seven design-time disciplines follow, none optional, but depth scales with risk.

2.1Privacy by Design & by Default

References

GDPR Art. 25 · EDPB Guidelines 4/2019 on Art. 25 Data Protection by Design and by Default.

The ruleTreat privacy as a non-functional requirement from the first sketch, and ship the most privacy-preserving settings on by default.

Why we care

Art. 25 is the only article that explicitly names the design phase. Regulators read it as "you should have known better at architecture time" and use it to multiply fines when a breach traces back to a design choice that ignored privacy. The "by default" half means new users must land in the safe configuration without having to opt out.

Key patterns

  • Treat privacy requirements as non-functional requirements alongside latency, availability, and cost. Add a "privacy" row to your architecture decision records (ADRs) and your design review template.
  • Default to the narrowest data collection that makes the feature work. If a field is "nice to have for analytics," it does not ship in v1.
  • Default to the shortest retention that satisfies the business purpose. New tables get a TTL or a documented retention job before they get a first write.
  • Default to the smallest audience: private buckets, IAM-scoped queues, VPC-internal endpoints. Public is a deliberate, reviewed exception, not a starting point.
  • Default to encryption at rest and in transit everywhere, with customer-managed keys (CMK) for anything containing personal data above a low-risk threshold.

Anti-patterns / gotchas

  • "We'll add privacy controls in a follow-up sprint." Follow-up sprints do not happen, and Art. 25 specifically faults you for not addressing this at design time.
  • Defaulting newsletter checkboxes, telemetry toggles, or "share with partners" switches to ON. Pre-ticked boxes are not valid consent under Planet49 (CJEU C-673/17) and directly violate "by default."
  • Storing "in case we need it later" fields. If you cannot articulate the purpose now, you do not have a lawful basis now.
Cloud notes: AWS · K8s
  • AWS: Enable S3 Block Public Access at the account level. Use AWS Config rules for s3-bucket-public-read-prohibited, encrypted-volumes, rds-storage-encrypted. Service Control Policies (SCPs) at the Organization level to deny unencrypted resource creation. The Well-Architected Framework's Security Pillar covers this. There's no dedicated "privacy" lens, though the newer Digital Sovereignty Lens is the closest fit.
  • K8s: PodSecurity admission set to restricted, NetworkPolicies default-deny, OPA/Gatekeeper or Kyverno policies for required labels (e.g., data-classification, retention). Default namespaces should not have egress to the internet without an explicit policy.

2.2Data minimization & purpose limitation

References

GDPR Art. 5(1)(b) (purpose limitation) and Art. 5(1)(c) (data minimisation)

The ruleCollect only what a declared purpose needs, and don't silently reuse it for a new one. Data you never collected can't leak.

Why we care

Purpose limitation is what blocks "we already have the user's email from signup, let's use it for the new marketing campaign." That is a new purpose and needs its own lawful basis.

Key patterns

  • Per-field purpose tagging in your schema or data catalogue. Each column carries purpose, lawful_basis, retention, and category (e.g., contact, identifier, behavioural, special-category).
  • Prefer derived or aggregated fields over raw ones. Store age_bracket instead of date_of_birth when only the bracket is used. Store country instead of full IP. Store a coarse device_class instead of the full user-agent string.
  • Pseudonymise at ingestion when downstream consumers only need a stable ID, not the underlying identity. The mapping table lives in a separate, more tightly controlled store.
  • Truncate, hash, or tokenise high-cardinality identifiers before they hit logs, metrics, or analytics warehouses. Full email addresses do not belong in product analytics.
  • Separate operational stores (which need the real data) from analytical stores (which usually do not). The boundary is a great place to drop fields.

Anti-patterns / gotchas

  • SELECT * ETL into the warehouse, then "we'll figure out which columns we actually need." The warehouse is now your largest privacy exposure.
  • Reusing a production dataset for ML training without re-checking purpose. "Improving the service" is not a magic incantation; the original collection purpose has to cover it, or you need a new basis (often legitimate interests with a balancing test).
  • Free-text fields where users paste anything. A "notes" column ends up containing passport numbers, health details, and other people's data. If you must have one, classify it as high-risk and apply the same controls as special-category data.
Cloud notes: AWS · K8s
  • AWS: Glue Data Catalog with column-level tags; Lake Formation for column- and row-level access control; Macie to detect personal data drifting into S3 where it should not be.
  • K8s: Schema-aware sidecars or service-mesh filters that strip PII from logs before they leave the pod. OpenTelemetry processors (attributes, redaction) configured centrally.

2.3Data flow mapping & RoPA

References

GDPR Art. 30

The ruleKeep a living map of where personal data enters, lives, moves, and leaves, derived from infrastructure, not a yearly spreadsheet. It's the first thing a regulator asks for.

Why we care

Two reasons. First, every other GDPR obligation ( DSARs, breach notification, retention, transfers) requires you to know where the data actually is. Second, the Record of Processing Activities (RoPA) is the first thing a supervisory authority asks for in an investigation; if it does not exist or is obviously wrong, the conversation gets worse immediately.

Key patterns

  • A RoPA entry per processing activity (not per system) describing: purpose, lawful basis, data categories, data-subject categories, recipients (including processors and sub-processors), transfers outside the EEA, retention, and a high-level description of security measures.
  • Treat the data-flow diagram as code. Tools like pyDataFlow, threagile, or even Mermaid diagrams checked into the repo beat a Visio file that nobody can find. Update on PR.
  • Tag resources at provisioning time with the processing activity they belong to. A Terraform data_processing_activity tag on every bucket, queue, table, and topic lets you reconstruct the map from infrastructure-as-code.
  • Distinguish controller-mode and processor-mode activities in the same register. The columns required differ slightly (Art. 30(1) vs Art. 30(2)).
  • Re-derive the RoPA from infrastructure regularly. If the manually-maintained register disagrees with what the cloud accounts actually contain, the cloud wins; treat the diff as a finding.

Anti-patterns / gotchas

  • A spreadsheet maintained once a year by Legal with no input from engineering. It will be wrong within a quarter and useless within two.
  • Forgetting sub-processors. If your processor (e.g., a SaaS vendor) uses AWS, AWS is your sub-processor and belongs in the chain. The chain has to be visible all the way down.
  • Forgetting backups, DR replicas, analytics copies, and dev/test environments. Each is a "place the data lives" and each must appear on the map.
Cloud notes: AWS · K8s
  • AWS: Resource Groups and Tag Editor to enforce a processing-activity tag taxonomy; AWS Config to detect untagged resources; Resource Explorer for cross-account discovery. Macie for "where did personal data end up in S3" sweeps.
  • K8s: Labels and annotations on every namespace, workload, and PVC; OPA/Gatekeeper to enforce them at admission. Kubernetes' own audit log is part of the flow map (it can contain personal data in request bodies).

2.4Data Protection Impact Assessment

References

GDPR Art. 35

The ruleIf processing is likely high-risk (profiling with significant effects, special-category at scale, large-scale monitoring), run and document a DPIA before you start, and re-run it on material change.

Why we care

A DPIA is not a legal-team-only artefact. The engineering decisions (what data, what retention, what access controls, what third parties, what fallback when the model is wrong) are exactly what the DPIA documents. If you cannot articulate those decisions, the DPIA cannot be completed, and the project cannot lawfully start.

When required (Art. 35(3) and the WP29 / EDPB criteria)

  • Systematic and extensive evaluation including profiling that produces legal or similarly significant effects (credit scoring, fraud detection that blocks accounts, automated hiring filters).
  • Large-scale processing of special-category data (Art. 9) or criminal-conviction data (Art. 10): health, biometrics, ethnicity, sexual orientation, political opinions, religious belief, trade-union membership, genetics.
  • Systematic monitoring of a publicly accessible area on a large scale (CCTV, smart-city sensors).
  • Each EU supervisory authority publishes a national "blacklist" of operations that always require a DPIA (Art. 35(4)), and may publish a "whitelist" of operations that never do (Art. 35(5); not all have). Check your lead authority's list.
  • The EDPB's nine criteria (evaluation/scoring, automated decision-making with significant effects, systematic monitoring, sensitive data, large scale, matching/combining datasets, vulnerable data subjects, innovative technology, prevents data subjects from exercising a right or using a service): two or more usually triggers a DPIA.

Who runs it

  • The controller (your company, in most cases) runs the DPIA. The DPO advises and reviews (Art. 35(2)). Engineering provides the technical reality: data inventory, flows, security measures, residual risks. Product owns the purpose and necessity argument. Legal owns lawful basis and rights.

Engineer's role

  • Provide the data flow diagram and RoPA entry as input. Do not let the DPIA invent a parallel one.
  • Enumerate technical mitigations actually in place (encryption, access control, pseudonymisation, retention, monitoring) and the residual risks after those mitigations.
  • Surface the things that cannot be mitigated technically (e.g., "the model is a black-box vendor API; we cannot explain individual decisions") so they appear in the residual-risk section honestly.
  • Track DPIA action items like any other engineering work (tickets, owners, deadlines). A DPIA with "TBD" mitigations that ship to production is worse than no DPIA at all.
  • Re-trigger the DPIA on material change: new data category, new purpose, new region, new sub-processor, new automated decision boundary.

Anti-patterns / gotchas

  • Treating the DPIA as a one-off form to be filed and forgotten. It is a living document; if the system changes meaningfully, the DPIA is stale.
  • Running the DPIA after launch. Art. 35(1) says "prior to the processing." Retroactive DPIAs are a regulatory red flag.
  • DPIA-shopping: writing the DPIA to justify a decision that has already been made. The point is to surface risks early enough that the design can change.
Cloud notes: AWS · K8s
  • AWS: Use Audit Manager with a custom GDPR framework to evidence controls referenced in the DPIA; export AWS Config compliance status as appendices.
  • K8s: Cluster-level evidence often missed: admission policies, network policies, secret-management posture. Tools like Kubescape or Trivy can produce signed reports that attach to the DPIA.

2.5Data residency & international transfers

References

GDPR Chapter V, Art. 44-49

The ruleDefault to an EU region, and don't let personal data leave the EEA without a valid mechanism (adequacy / SCCs + TIA / BCRs). Region choice is nearly irreversible, so get it right in hour one.

Why we care

Region choice is one of the few decisions you make in the first hour of a project and cannot reverse without a migration. Transfer mechanisms (SCCs, adequacy, DPF) are not free-form: they require diligence, contracts, and sometimes supplementary measures. Getting this wrong is the single most common source of complaints to EU DPAs since Schrems II.

The framework in one paragraph

  • Personal data may be transferred outside the EEA only if (a) there is an adequacy decision for the destination country (Art. 45), (b) appropriate safeguards are in place (Art. 46, most commonly Standard Contractual Clauses or Binding Corporate Rules), or (c) a narrow derogation applies (Art. 49: explicit consent, contract necessity, important public interest, legal claims). After Schrems II (CJEU C-311/18), even SCCs require a Transfer Impact Assessment (TIA) and, where the destination's surveillance law is problematic, supplementary measures (encryption with EU-held keys, pseudonymisation, contractual and organisational measures).

Adequacy decisions to know (current as of July 2026)

  • Andorra, Argentina, Brazil (adopted January 2026, the first mutual adequacy: Brazil recognises the EU in return), Canada (commercial organisations), Faroe Islands, Guernsey, Israel, Isle of Man, Japan, Jersey, New Zealand, Republic of Korea, Switzerland, United Kingdom (adequacy renewed in December 2025 through to 27 December 2031), Uruguay, and (under the EU-US Data Privacy Framework) the United States for organisations self-certified to the EU-US Data Privacy Framework. The DPF replaced Privacy Shield in July 2023; the EU General Court upheld it in September 2025 (the Latombe challenge was dismissed), but an appeal is pending at the CJEU (Case C-703/25 P), so treat it as "valid today, verify before relying on it."

Key patterns

  • Pick an EU region as the primary region for any EU-personal-data system, even if your company's centre of gravity is elsewhere. Defaulting to us-east-1 is the most common avoidable mistake.
  • Maintain a transfer register parallel to the RoPA: source country, destination country, mechanism (adequacy / SCCs / BCRs / derogation), TIA outcome, supplementary measures, sub-processor chain.
  • Choose customer-managed keys held in an EU KMS for any data that touches non-EU infrastructure, even for ancillary services (CDN, observability, support tooling). "Encrypted with keys we control in the EU" is the strongest supplementary measure.
  • Confirm sub-processor regions explicitly. A SaaS that runs in eu-west-1 but uses a US-only support backend has a transfer you may not have noticed.
  • Re-evaluate transfers when destination countries change posture (UK adequacy was renewed to 2031 in December 2025; the US DPF survived its first court challenge in September 2025 but faces a pending CJEU appeal). Build the assumption that mechanisms can be invalidated into your design, and keep an exit path.

Anti-patterns / gotchas

  • Treating "we use AWS Frankfurt" as a complete answer. Control plane operations, IAM, billing metadata, support data, and certain global services (CloudFront, Route 53, IAM, STS) involve US processing regardless of data-plane region. Document those flows.
  • Relying on Art. 49 derogations as a routine basis. They are exceptions, not patterns. "Explicit consent" for transfers is fragile; "necessary for the performance of a contract" is narrow.
  • Confusing data residency with data sovereignty. Residency = data sits in region X. Sovereignty = data and access to it are governed by region X's law and not reachable by foreign government orders. The CLOUD Act means a US-headquartered provider may be compelled to produce data even when stored in the EU. Sovereign-cloud offerings exist to address this.

Region selection cheat-sheet

  • Default to an EU region (Ireland, Frankfurt, Paris, Stockholm, Milan, Madrid, Zurich, Warsaw, Brussels; availability varies per provider).
  • Pick two EU regions for DR. Crossing the EEA border for DR is a transfer.
  • For latency-sensitive workloads serving both EU and non-EU users, consider per-region data partitioning at the application layer: EU users' data stays in the EU, non-EU users' data stays out. (This is a residency/performance optimisation, not a test of whether GDPR applies. Under Art. 3, GDPR follows data subjects who are in the EU when you offer them goods or services, regardless of citizenship or where the bytes sit. Partitioning shrinks the transfer problem; it doesn't remove you from scope.)
  • For SaaS and managed services, verify the "control plane" location separately from the data plane. Some services (e.g., certain serverless and ML APIs) have implicit US dependencies.
🇪🇺 Sovereign cloud options
  • AWS European Sovereign Cloud: Announced October 2023, planned as a physically and logically separate AWS partition operated by EU personnel and EU-headquartered parent entities, with the first region in Brandenburg, Germany. It reached general availability in January 2026 (first region in Brandenburg, Germany), with Local Zones announced for Belgium, the Netherlands, and Portugal. Where a separate partition isn't required, the standard AWS Europe regions (Frankfurt/Paris/Stockholm/Ireland/Milan/Spain/Zurich) plus CMK with external key store (XKS) and Nitro Enclaves remain the pragmatic baseline.
  • Google Sovereign Cloud offerings: Tiered: "Data Boundary for the EU" (data residency and access controls), "Sovereign Controls by Partners" (operated by Thales/T-Systems/Telecom Italia/Minsait depending on country), and "Local Controls" delivered via Google Distributed Cloud air-gapped/connected appliances. Partner-operated offerings (T-Systems in Germany, Thales/"S3NS" in France, and others) are at varying stages of availability, so confirm the current status for your country before committing.
  • Microsoft Azure EU Data Boundary: Completed in February 2025: customer data, pseudonymised data, and professional-services/support data plus system logs for in-scope services now stay within the EU/EFTA. Note that the EU Data Boundary is a residency commitment, not a sovereignty guarantee. Microsoft as a US-headquartered entity is still subject to US legal process. For higher sovereignty, look at Bleu (Microsoft + Capgemini + Orange) in France and Delos Cloud (Microsoft + SAP + Arvato) in Germany, both based on Azure Stack; Delos began phased productive operation across 2025–2026 (Microsoft services first, SAP services following).
  • Other EU-only providers: OVHcloud, Scaleway, IONOS, Hetzner, Exoscale, T-Systems Open Telekom Cloud. Often relevant when sovereignty matters more than feature parity. GAIA-X labelling is an emerging signal of sovereign posture.
Cloud notes: AWS · K8s
  • AWS: Frankfurt (eu-central-1), Ireland (eu-west-1), Paris (eu-west-3), Stockholm (eu-north-1), Milan (eu-south-1), Spain (eu-south-2), Zurich (eu-central-2). Use AWS PrivateLink and VPC endpoints to avoid traffic leaving the region. AWS KMS XKS for keys held outside AWS. SCPs to deny resource creation outside an allow-list of EU regions.
  • K8s: Node-pool affinity and topology spread constraints to keep workloads in EU zones. If using a managed control plane (e.g., EKS), confirm where the control plane itself runs and where its audit logs land. These are easy to overlook.

2.6User identity model

References

GDPR Not a single article, but it is what makes Art. 15 (access), Art. 16 (rectification), Art. 17 (erasure), Art. 20 (portability), and Art. 30 (records) operationally feasible.

The ruleGive every data subject one opaque, immutable internal ID, carry it in every store and log, and keep a resolver from external IDs to it, or every DSAR becomes archaeology.

Why we care

A 30-day DSAR clock (Art. 12(3)) is unwinnable if "finding the user" requires joining across email, phone, user_id, anonymous_id, device_id, account_id, customer_id, and "the spelling they used in support tickets." Identity sprawl is the single biggest operational cost of GDPR compliance, and it is fully a design-time decision.

Key patterns

  • One internal, opaque, immutable subject ID (e.g., a UUID v4 or v7) generated at first contact with the person. Never reuse, never expose externally as a stable handle if you can avoid it, never derive from PII.
  • Every store with personal data carries the subject ID as a first-class column or attribute. Logs, events, analytics, support tickets, ML features, ML predictions, audit trails: all of them. A field called user_id that means different things in different services is the bug.
  • A central identity-resolution service that maps external identifiers (email, phone, OAuth subject claims, anonymous cookie IDs, device IDs, loyalty numbers) to the canonical subject ID. This is what DSAR and erasure jobs query to enumerate scope.
  • Handle the pre-authentication ("anonymous user") case explicitly. When an anonymous visitor signs up, stitch the anonymous_id to the new subject ID at the moment of signup, and propagate the stitch to downstream systems. Without this, behavioural data collected pre-signup is orphaned and hard to delete.
  • Treat the subject ID as personal data itself when it can be linked back to a person via your systems, which is the whole point. Pseudonymisation under GDPR (Art. 4(5)) reduces risk but does not exit the regime.

Anti-patterns / gotchas

  • Using email as the primary key. Emails change, get reused, are case-sensitive in some systems and not others, and leak the person's identity into every log line. If a downstream system needs an identifier, give it the subject ID, not the email.
  • Per-service ID generation with no cross-service mapping. You will discover at DSAR time that the marketing platform's contact_id, the billing system's customer_id, and the product database's user_id have no documented relationship.
  • Soft-deleting the identity mapping but leaving the subject ID in downstream stores. After erasure, the downstream records become orphans that you cannot link back to a request, and cannot prove you deleted. Either erase end-to-end or replace with a tombstone ID that is auditable.
  • Letting third-party SDKs (analytics, ads, A/B testing) generate their own IDs and not capturing the mapping. When the user asks for erasure, you have no way to tell the third party which record to delete.
Cloud notes: AWS · K8s
  • AWS: Cognito user pools generate a stable sub (UUID). Use it as the canonical ID, not the email. DynamoDB partition key on subject_id; GSIs for lookup by external identifiers. AWS Entity Resolution for stitching when historical sprawl exists.
  • K8s: Subject ID is an application-layer concern, but ensure it propagates through service-mesh headers (e.g., x-subject-id baggage in OpenTelemetry) so every span and log line in the request chain carries it. Do not put email or other direct identifiers in the baggage, only the opaque subject ID.

2.7Transparency & the right to be informed

References

GDPR Art. 13 (data collected from the subject) and Art. 14 (data obtained from third parties). Read with Art. 12 (clear, plain language) and the transparency principle, Art. 5(1)(a).

The ruleEvery user gets a privacy notice that matches what your systems actually do, and engineering owns keeping the two in sync, not just legal.

Why we care

This is the one right that's really a documentation-vs-reality problem, and that makes it an engineering problem. The notice is written once by legal, then drifts the moment you add a telemetry field, a sub-processor, or an analytics pipeline. A notice that says less than your systems do is a transparency violation, and it's the easiest one to catch: a regulator or journalist just reads the notice and watches the network tab.

Key patterns

  • Derive the notice from the RoPA (2.3); don't author it independently. Data categories, purposes, recipients, retention, transfers already live in the RoPA. Treat the user-facing notice as a rendered view of that source, so a new processing activity forces a notice review.
  • Version the notice as a first-class artifact and bind consent records to the version shown (3.5). A material change is a re-prompt trigger, not a silent swap.
  • Make data-flow changes fail CI until the notice is reviewed. Flag PRs that add a personal-data field, a sub-processor, or a new purpose; require a "notice impact: none / updated" checkbox. Cheap, and it catches drift at the source.
  • Plain language, child-readable where relevant. Art. 12 requires non-experts can understand it; if under-16s use the service, they must too (ties to the child-consent pattern in 3.5).
  • Art. 14 timing for data you didn't collect directly. Enriching from brokers, partners, or public sources still owes notice, generally within a month, or at first contact. Build that notification into the enrichment pipeline.

Anti-patterns / gotchas

  • Notice and data map maintained separately. They diverge within a quarter. One source of truth (the RoPA), or it rots.
  • Burying telemetry and third-party SDKs. If the app loads analytics, ads, or session-replay, the notice must name them. "We may use third parties" is not specific.
  • Treating it as legal's job only. Legal writes the words; engineering owns the fact that the words are still true after the last deploy.
Cloud notes: AWS · K8s
  • AWS: There's no "privacy notice" service. This is a documentation discipline wired to your RoPA tooling (see 2.3 cloud notes). Render the notice from the same tagged-resource inventory, and alert when a new processing-activity-tagged resource appears with no corresponding notice entry.
  • K8s: A new workload carrying a data-classification label and an external egress destination is a signal the notice may need updating, so surface it via an admission-policy annotation or a periodic audit.

Design review checklist

Pin this to the wall of every design review for a new service or a material change:

  • What personal data does this system process, and under what lawful basis?
  • Is the data minimised to what is necessary for the declared purpose? Which fields would we drop if forced?
  • Where does the data live (regions, accounts, third parties), and is the RoPA updated?
  • Does this trigger a DPIA? If yes, who owns it and what is the timeline?
  • Does any data leave the EEA? Under which transfer mechanism, with what supplementary measures?
  • What is the retention, and what enforces it (a TTL, a scheduled job, a vendor configuration)?
  • What is the canonical subject ID, and is it propagated through every store and log this system writes?
  • What happens on DSAR / erasure? Can we enumerate and act on every record in 30 days?
  • What is the default for the user, and is it the privacy-preserving option?
  • Which sub-processors are introduced, and are they covered by a DPA?
  • Does the privacy notice still match what this change makes the system do (new field, purpose, recipient)?

If any answer is "we'll figure that out later," you are not yet at design-time done.

At a glance

7  design-time disciplines

Art. 25, 30, 35  by design, RoPA, DPIA

Art. 44-49  international transfers

The series

Part 2 of 5

Foundations → Design → Build → Operate → Respond. Design-time is where the cheapest privacy choices (and the most expensive mistakes) get locked in.