heygrc
GDPR data protection by design and by default in code

The default setting is the one everyone gets.

Data protection by design and by default, Art. 25, has two halves. By design: privacy is built into how a feature works, not bolted on later. By default: without anyone touching a setting, the system processes only the personal data the purpose needs, and does not make a person's data accessible to more people than necessary. The second half is the one that lives in a diff, because a default is a literal value in code, and whatever it is becomes the setting for every user who never opens the settings page.

How it shows up in a diff

The shapes the same control failure takes.

Art. 25 rarely breaks with a setting nobody offers. It breaks because the default value of a setting points the wrong way, or processing starts wider than it needs to. The recurring shapes:

  • A visibility default ships open

    A new profile, post, or document field defaults to public, shared, or discoverable, so a person's data is exposed to an indefinite audience unless they find the toggle and change it.

  • An opt-out where it should be opt-in

    A consent flag, a marketing setting, or a data-sharing option defaults to on, so processing happens for everyone who does not actively turn it off.

  • A broad scope is the default selection

    A new feature defaults to the widest data scope (all contacts, the whole org, every field) where the narrow one would have served the purpose.

  • A privacy control is added but defaults off

    A redaction, an audience limit, or a retention bound is built (by design) but ships disabled by default, so the protection exists only for users who enable it.

  • A safer default is loosened to help adoption

    An existing private-by-default value is flipped to public or shared to make a feature feel more useful, widening exposure for everyone at once.

Worked example

A profiles feature that ships public by default.

A new public-profiles feature lets people show a name, bio, and photo. The migration that adds the visibility column defaults it to 'public', so every existing and new user's profile is visible to anyone, and being private is something you have to go into settings to choose.

migrations/0042_add_profiles.sql+1 -0
ALTER TABLE profiles  ADD COLUMN bio text,+  ADD COLUMN visibility text NOT NULL DEFAULT 'public';
heygrcGDPR Art. 25(2)

This makes every profile visible to an indefinite audience without the person choosing it, because 'public' is the default. Art. 25(2) (data protection by default) expects the privacy-protective option to be the default: a person's data should not be made accessible to more people than necessary without their intervention. Default the column to 'private' and let users opt in to public, rather than making them opt out.

What an auditor does with this

By default means the value in the code.

A data-protection review does not just check that a privacy setting exists, it checks what it does when nobody touches it. The standard is the default state: what data is processed, and who can see it, for a user who never opens a settings page. A control that is technically present but defaults to the less protective option is the kind of default-state gap Art. 25(2) is aimed at, and the default is set in a migration, a model, or a config line, one feature at a time. That is the line a review of the diff can catch, before it becomes the experience every user got.

What this is, and is not

A review, not legal advice.

heygrc flags changes where a default exposes more personal data than necessary and cites the article so the choice is made in the pull request. It does not run your data-protection impact assessment or render a legal determination. It catches the moment a default points the wrong way, at the diff, while it is still one line to change. heygrc is in early access.