Skip to content

RFC: Privacy Data Types - #11818

Open
chfsx wants to merge 7 commits into
ILIAS-eLearning:trunkfrom
srsolutionsag:proposal/12/privacy-data-types
Open

chfsx wants to merge 7 commits into
ILIAS-eLearning:trunkfrom
srsolutionsag:proposal/12/privacy-data-types

Conversation

@chfsx

@chfsx chfsx commented Jul 23, 2026 •

Copy link
Copy Markdown
Member

What this does

Personal data is wrapped in privacy data types (ILIAS\Data\Privacy). A wrapped value knows where it came from and hands out the raw value only through resolve(), stating a technical requirement: store it, present it, export it, hand it to another component, process it.

Each technical requirement carries the phrases a reader of the privacy documentation needs, and they are required:

$address = $profile->getPostalAddress()->resolve($requirements->displayToUser(
    'on the public profile of the person',           // where
    'persons who can see the public profile',        // to whom
    'show the profile the person has published',     // what for
    'the person has published it in their profile'   // condition (optional)
));

scripts/Privacy/generate-privacy-docs.php collects these calls statically (PHPStan) and renders a PRIVACY_DATA.md per component with the sections of How to write a PRIVACY.md: one sentence per distinct set of phrases, e.g. "If the person has published it in their profile, the postal address is presented on the public profile of the person to persons who can see the public profile, to show the profile the person has published." Nothing is written by hand; when the code changes, the documentation changes with it. The file is generated alongside the handwritten PRIVACY.md, grows with every type, and is meant to replace it once it covers everything; until the authority of a component switches, the handwritten file stays authoritative.

Data that belongs together is grouped: a compound type holds several fields (PostalAddress), a bundle holds several types (the profile of a user). A component defines its own personal data in a source catalogue next to its code and, where only it has such data, in its own types.

Documentation: components/ILIAS/Data/src/Privacy/README.md.

Try it: php scripts/Privacy/generate-privacy-docs.php --run-phpstan --check.

Example

What it is not

  • Not a legal instrument: a technical requirement describes what the code does, not the purpose or legal basis of processing in the sense of the GDPR.
  • No logging: resolve() returns the value and nothing else happens at runtime. Wrapping and resolving is a few object constructions; measured below half a microsecond per row (100 000 rows).
  • No obligation: components without types are untouched; no CI gate.

Commits

  1. Data: types, sources, technical requirements, bundles; scripts/: generator and PHPStan rules
    2.–7. One commit per component: User, AuthShibboleth, Certificate, LegalDocuments, MyStaff, Maps, each reviewable by its authority.

Changes for users

  • Maps: the marker of a person now shows the zip code when the person has published it in the profile (public_zipcode), like the public profile does. Before, it checked public_zip, which only the XML user import and export use.
  • Otherwise none: same data, same conditions.

Changes for developers

  • ILIAS\User\Profile\Data::__construct(): the four address strings are replaced by ?PostalAddress $postal_address. Calls with positional arguments after the address break (the core has none; plugins should use named arguments). The old getters and withers stay @deprecated.
  • New optional constructor parameters (with defaults) in the profile fields Street, City, ZipCode, Country, Location, in UserCountry, UserCountryDefinition and ilDefaultPlaceholderValues; existing callers are unchanged.
  • ilMStListUser: address getters/setters removed (internal, no callers).

Known limits

  • Only data handled through privacy data types appears. Today these are the fields of the user profile; user IDs and content created by persons are not typed, so for most components the generated file starts small.
  • "Data being deleted", "General information" (settings) and data passed to third parties outside ILIAS have no counterpart in the code yet and stay in the handwritten file.
  • Phrases must be literal strings or constants; other expressions are shown as "…" and listed in the notes for authors.
  • Callers of deprecated accessors (e.g. ilObjUser::getStreet()) are not listed while the accessors exist.
  • What happens with a raw value after resolve() is not visible to the analysis.
  • The source of a value (getSource()) has no consumer yet; it documents the origin in the code. If there is no agreed use, it can be removed.
  • The PHPStan rules (privacy.neon) are opt-in.

Feature wiki and vote

@matthiaskunkel

Copy link
Copy Markdown
Member

Jour Fixe, 27 JUL 2026: Fabian gave an overview on the pull request and the concept behind the privacy data types. He highly appreciates to get feedback from authorities and the TB about this proposal to implement a general infrastructure for a ‚privacy by design‘ approach in ILIAS.
This infrastructure should help developers to track all changes in their components that have an impact on privacy and to prevent that privacy documentation is going outdated by the forgoing development.
Fabian has tested to make the code changes of data types by using AI and was impressed about the results. If authorities accept related PRs he guess the amount of workload for the changes would be not very high.
All authorities and developers are invited to add their comments and questions to this PR in the next two weeks.

@chfsx

chfsx commented Jul 27, 2026

Copy link
Copy Markdown
Member Author

VOTING
As there isn’t really a way to vote on GitHub, I’d like to try the following approach for now:
I welcome any written feedback in general, but I’d also like to ask everyone to ‘mark’ this comment with a Thumbs-Up 👍 or Thumbs-Down 👎 to indicate whether you think the project is worth supporting or not, even if it’s somewhat separate from the code currently proposed.

In other words, whether you generally

  • want to wrap data that needs protecting
  • make it machine-readable and analysable

That gives us an idea of how we should proceed from here.

@chfsx chfsx changed the title Proposal/12/privacy data types RFC: Privacy Data Types Jul 27, 2026
@mjansenDatabay

Copy link
Copy Markdown
Contributor

Hi @chfsx,

thanks for your contribution.

First: I am not a GDPR expert, I am just a developer with an opinion :-). So for this review I'll leave any GDPR angle aside for now (or at least I try to). I'm not in a position to judge that properly. Accordingly, I won't give a 👍 or 👎 on the voting criteria yet either.

This comment is only about the technical proposal. Once people with data-protection expertise have given feedback here and decisions have been made (also by the Technical Board and the Jour Fixe), I'll follow up with more feedback from the domain perspective.

  • Wrapping personal data as typed values with mandatory Source/Purpose is in my opinion, a clean way to make privacy-relevant access paths first-class and machine-checkable.
  • I like introducing strong data types instead of passing primitives through all layers of the product.
  • In spirit this is close to PHP's #[\SensitiveParameter] / SensitiveParameterValue, which allows marking sensitive values so they do not leak casually (e.g. into stack traces). Your proposal goes further, the sensitivity is carried by the value itself across layers, and releasing it requires an explicit purpose.
  • That makes personal data visible in the type system instead of opaque strings/arrays, which is good and fits the ILIAS direction of value objects, explicit domain types, and less primitive obsession.
  • Without a logger backend, runtime accountability is still aspirational. This is fine for an RFC, but we should not oversell the audit trail here, yet.
  • I have, without being able to prove it yet, performance considerations when handling bulk User data, e.g. in lists of any kind (tables, typeahead suggestions, etc.): wrapping/resolving many privacy values per row could add overhead if every field pays the factory/logger/purpose tax.

Best regards,
Michael

@selyesa selyesa added the privacy label Aug 5, 2026
@mbecker-databay

Copy link
Copy Markdown
Contributor

I like to point to the remark of @selyesa in the feature wiki about the position of the privacy experts group.

The Technical Board supports the further use of specific data types over primitive data types in general. The premise, if such leads to an expectation that authorities will be required to review pull requests at no cost, communicated by a society organ, is part of an ongoing discussion and cannot be answered here.
(We are currently working on addressing this and some other aspects related to Big Projects.)

@chfsx
chfsx force-pushed the proposal/12/privacy-data-types branch from 39fabc6 to bd1f72e Compare October 12, 2026 12:40
@chfsx

chfsx commented Oct 13, 2026

Copy link
Copy Markdown
Member Author

@mjansenDatabay the audit trail is removed entirely. Cost: wrapping and resolving is below half a microsecond per row (100 000 rows); the MyStaff list only resolves the address when an address column is shown.

The description above is updated to the current state: the privacy documentation is now generated from the use of the types in the code, see the Maps example there.

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants