Feature Wiki
Tabs
Data: Privacy Data Types
Page Overview
[Hide]- 1 Initial Problem
- 2 Conceptual Summary
- 3 User Interface Modifications
- 4 Additional Information
- 4.1 Involved Authorities
- 4.2 Technical Aspects
- 4.3 Privacy
- 4.4 Security
- 4.5 Contact
- 4.6 Funding
- 5 Discussion
- 6 Implementation
- 6.1 Description and Screenshots
- 6.2 Test Cases
- 6.3 Privacy
- 6.4 Approval
Introduction and Scope
This entry has generated some controversy, and a number of the concerns raised in the comments and in the subsequent discussions (for example with the Privacy Expert Group) stem from a misunderstanding of what this proposal actually aims to do. The following notes are intended to clarify the scope before going into the details.
This is not a proposal to implement a specific GDPR article. It has been pointed out that this feature "has nothing to do with privacy" in the legal sense — that it does not, on its own, satisfy any obligation that the GDPR imposes. That is correct: the proposal does not directly cover any legal requirement. What it does is automate an existing manual process, namely the creation and maintenance of the per-component PRIVACY.md files. These files are already written and maintained by hand today. If one takes the position that this proposal is not a privacy topic, then one would, by the same logic, have to conclude that the current manual authoring of the PRIVACY.md files is not a privacy topic either. The proposal simply moves an already-accepted privacy documentation task from manual work to a generated artifact.
The core value is the typing of data. There appears to be broad agreement that giving personal data an explicit type is a good idea in itself, and that it would be worth rolling this out across components for that reason alone. The main practical benefit is that, once data is typed and each access states its purpose, the privacy documentation (the PRIVACY.md files) can be generated automatically per component, rather than kept in sync by hand — which is where documentation tends to go out of date.
On the Logger interface. Some of the discussion has focused heavily on the logging functionality (see the PrivacyLoggerinterface in the PR). This needs to be clarified: the ILIAS core would almost certainly not ship its own implementation of this interface. The interface only provides the possibility for someone — for example via a custom component — to build such a logger if they need one. Shipping a core implementation would raise significant challenges: logging every resolve of a personal-data value could produce a very high volume of data (storage) and could affect overall performance. The interface is therefore an extension point, not a feature that is switched on in the core.
Technical vs. legal framing, and how to proceed. I approach this primarily from the technical side, not the legal side. The most relevant reference for understanding the proposal is therefore the pull request #11818 rather than this wiki entry. The feature request exists here mainly because this is the established process at ILIAS. In terms of scale this would qualify as a "Big Project"; however, we propose a somewhat different route: rather than a single large project, a task forcethat dedicates itself to the gradual roll-out and submits the pull requests for the individual components.
1 Initial Problem
ILIAS processes large amounts of personal data — user IDs, email addresses, names, phone numbers, postal addresses, session data, forum posts, course memberships, access logs.
Today this data circulates as bare PHP primitives (int, string, array). There is no machine-readable way to answer questions that data protection increasingly requires:
- Which components store personal data, and in which database tables?
- Which components display personal data to end users?
- Which components forward personal data to other components, and why?
Answering these questions currently requires a manual code audit per component. This is expensive, error-prone, and does not scale as ILIAS grows. It also makes the component-level privacy documentation expected under the GDPR hard to produce and keep up to date.
2 Conceptual Summary
Introduce Privacy Data Types: a small set of value-object wrappers in the ILIAS\Data\Privacy namespace that make personal data machine-readable at the PHP type level.
A wrapped value carries two pieces of metadata:
- Source — where the value came from (e.g. the usr_data.email column).
- Purpose — why it is being accessed, stated at the point of access.
The raw value is reachable only through resolve(Purpose $purpose). Each call logged and is statically analysable (used to generate documentation).
The feature has no end-user-facing behaviour. It is a developer-facing infrastructure component plus tooling.
Rollout strategy: We deliberately start with a single, rarely-used data type — for example a user's postal address, possibly the email address — to prove the pattern end to end at low risk. The hard part, should we decide to do it, is UserId: it is read in likely thousands of places across the codebase, so migrating it is by far the largest and most disruptive step. Starting small lets us validate the concept before committing to that scale.
2.1 2.1 Technical possibilities and potential implementation
The system has four interlocking parts:
- Typed wrappers — UserId, EmailAddress, PhoneNumber, PostalAddress, … all extending an abstract base type. Replaces bare primitives in method signatures.
- Typed sources — DbTableColumn, UserInput, ExternalApi, SessionData. A central KnownSources registry maps known ILIAS columns to named methods (KnownSources::user()->email()) instead of string literals.
- Typed purposes — StoreInTable, DisplayToUser, PassToComponent, TechnicalProcessing. Passing the wrong purpose is a static-analysis error.
- Logging and static analysis — a PrivacyLogger interface records every access. A PHPStan extension collects all access calls and a CLI script generates a PRIVACY.md per component.
A reference implementation already exists (interfaces, concrete types, source registry, logger, PHPStan rules/collector, doc generator, unit tests). This feature request asks only for an in-principle decision on the idea. See https://github.com/ILIAS-eLearning/ILIAS/pull/11818
3 User Interface Modifications
3.1 List of Affected Views
- None in the first phase. The feature is infrastructure only and introduces no GUI changes.
Possible later, out of scope here: a backend/administration view that renders the generated privacy access log for a given user (to support GDPR Art. 15 self-disclosure requests).
3.2 User Interface Details
Not applicable for this phase.
3.3 New User Interface Concepts
None.
3.4 Accessibility Implications
None — no UI is added.
4 Additional Information
4.1 Involved Authorities
- Jour Fixe / Technical Board — new shared infrastructure in ILIAS/Data, cross-component conventions, a new PHPStan extension and a new CLI script under scripts/Privacy/.
- Mid-term: all authorities whose components handle personal data. As the pattern is adopted incrementally, every component maintainer working with privacy-relevant data will be involved in migrating their own component.
If this request is related to multiple components, please list both authorities for all related components.
4.2 Technical Aspects
New namespace ILIAS\Data\Privacy in the ILIAS/Data component. New PHPStan extension (rules + collector + return-type extension). New CLI script under scripts/Privacy/ producing PRIVACY.md per component, intended to run in CI. PHP 8.x required (readonly properties, enums, generics in PHPDoc). Adoption is incremental: existing repositories are migrated component by component; new code uses the types from acceptance onward.
As mentioned above: ILIAS most probably wont ship any logger itself. but it creates the possibility to "attach" a logger if needed.
4.3 Privacy
This is a privacy-enabling feature.
__toString() on any wrapper returns a masked representation, preventing accidental leaks into log files, stack traces, or string interpolation.
The generated documentation gives a per-component overview of which personal data is stored, displayed, and forwarded.
4.4 Security
PHPStan rules forbid passing a wrapper directly to var_dump, print_r, var_export, json_encode, serialize, reducing accidental disclosure.
Out of scope: passwords and authentication secrets are explicitly not wrapped by this feature.
No new external interfaces or network surface introduced.
4.5 Contact
Person to be contacted in case of questions about the feature or for funding offers: Maintainer: to be filled in. Component: ILIAS/Data.
4.6 Funding
Funding status and funding parties are listed in the block 'Status of Feature' in the right column of this page.
5 Discussion
Schmid, Fabian [fschmid], 23 JUL 2026: Open questions to resolve with the community:
- Null values — should the wrapper allow T = null, or is a separate nullable wrapper preferable (relevant for nullable columns such as usr_data.birthday)?
- Bulk operations — exports and reports resolve the same type thousands of times in a loop. Should the logger offer a batch API to avoid log spam and performance impact?
- Static vs. instance API for KnownSources — the reference implementation is currently inconsistent and needs a decision.
- Inter-component contracts — when component A passes a wrapper to B and B resolves it, the recorded source is A’s but the file/line is in B. Confirm this is acceptable.
- External repositories (LDAP, Shibboleth) — naming conventions for ExternalApi sources need to be agreed before the User migration.
- PHPStan enforcement timeline — proposed staged rollout: warning → error → no suppressions allowed.
Falkenstein, Rob [rob], 24 JUL 2026:
Hi @fschmid,
thanks a lot for this proposal. I find it a little hard to grasp the extent of this feature request since imo this rather sounds like the beginning of a Big Project than like a feature request. I do understand the need to comply with the GDPR but I am not sure if ILIAS can currently implement this as a core feature. This request brings up a lot of additional work for all authorities that is not (fully) specified in this request like:
- How to extend the currently proposed datatypes?
- How to migrate all affected components to this implementation
- How does this affect performance?
- What is expected from the authorities?
- Which steps should be done next?
I don't think that we can stem this project without a clear timeline, project management and solid financing. Additionally, there is a definite need to bring other big projects to an end that have been lingering around for a while instead of opening the core for another big project that has a log of potential to slowly increase in size over time.
Becker, Maximilian [mbecker], 27 JUL 2026:
Hello @fschmid!
I appreciate the efforts to promote a privacy first design of ILIAS, but I must second all points @rob made.
Furthermore, by definition of article 4 of the GDPR, "‘personal data’ means any information relating to an identified or identifiable natural person (‘data subject’);". The feature request covers this in section 1. Consequentially, when looking over ILIAS and its purpose, I would consider the vast majority of data that we process to be personal data. In an empty ILIAS, we may have system settings outnumbering the personal data, but once a sizable number of users becomes active, the non-personal-data quickly become a minority. I would opt to intentionally overlook it and would rather consider every single information as if it was personal data and err on the side of caution.
There is in fact a requirement of the GDPR to provide an audit trail (in article 30), and we should in time look into that. I do not think this requires such an elaborate approach to document the motion of singular data items between components. It appears more to answer a question about human interaction with data. Who did what and when, so a more abstract "User X, successfully downloaded certificate Y of user Z" would, in my opinion, fulfill that requirement and in order to do achieve that, an "audit logger" would probably do the trick and provide valuable insights at a much lower integration effort.
Schmid, Fabian [fschmid], 4 AUG 2026:
Thanks to both of you for the honest feedback — both points are valid and I don't want to play them down. Your comments were of course written before the concrete PR existed; in the meantime there's now an RFC in #11818 that makes a lot of this more tangible — and we already presented the concept at the Jour Fixe on 27 July. Some of the points can be placed in a clearer context now.
On Rob's point (scope/financing): Yes, rolling out the data types across the board is indeed a larger undertaking — I don't want to portray it as anything else. But the PR shows exactly the kind of well-defined entry point: a single type (PostalAddress) across five components (User, Maps, Certificate, MyStaff, LegalDocuments), with the existing string accessors deprecated but still fully functional. This makes the "unclear extent" visible on a real, manageable example, and nothing is switched over all at once.
In my view the migration can largely be done AI-assisted — if the authorities accept the respective PRs, the effort for the conversion per component should be fairly low. And we did deliberately propose doing this in the form of a task force — rather than, as with other projects, having each authority do it themselves, which means the exploration and onboarding phase has to be repeated per component and is therefore usually considerably more expensive. It's exactly this overhead that we want to avoid with a coordinated approach.
One important point here: the introduction of the infrastructure (the types themselves) and the component-wide implementation can absolutely be considered separately. The core of the feature — the type level — stands on its own, regardless of how quickly or how broadly it gets rolled out.
On the type level (the actual core): My primary concern is type safety and self-documenting code. A primitive string/intbecomes a value object (PostalAddress, EmailAddress, …) that carries its origin and its purpose along as metadata — checkable via the PHPStan extension, with clear contracts between components. This benefit (type safety, static checkability, fewer errors when passing values around) exists completely independently of any logging obligation and is, for me, the central value of the feature.
On Maximilian's point (almost everything is personal data): Absolutely correct under Art. 4. That's precisely why the core is not a simple "is personal data" flag, but data lineage: through the interfaces we make the origin (Source) and purpose (Purpose) of a piece of data machine-readable. A value only releases its raw content via an explicit resolve() with a specified purpose — which makes it machine-traceable where a specific piece of data comes from and what it is used for or passed on to. That's the information that actually helps us at the sensitive points (passing data to external APIs, cross-component handovers).
On the audit logger as an alternative: That solves a different problem. An action logger answers "who did what and when" — not "which specific piece of data was passed where and for what purpose". For part of the GDPR requirements (traceability of user actions) I do agree with you that the simpler logger is sufficient and cheaper to operate. I see the two approaches as complementary, not as competing.
I'd be glad if you could reflect your points once more against the concrete PR — comments and questions there are explicitly welcome.
Statement of the Privacy Expert Group, 6 AUG 2026:
The privacy expert group looked into this feature request and found that the privacy data types do not directly correlate to any legal requirement imposed on ILIAS or its users by EU-DSGVO/GDPR or BDSG. As an initiative to further validate and enhance the privacy.md's, which we consider a most helpful tool in development and deployment of ILIAS, we still support this request due to its utility for the review and update of the files. We do not support the creation of a new logging mechanism that creates a collection of personal data with no requirement imposed by the laws.
Becker, Maximilian [mbecker] for the Technical Board, 10 AUG 2026:
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.)
Killing, Alexander [alex], 10 Aug 2026:
- What is a GDPR audit trail? This part does not seem to be a requirement of the GDPR.
- From the top section: "What it does is automate an existing manual process, namely the creation and maintenance of the per-component PRIVACY.md files.", Question: How could this replace the hand-written PRIVACY.md automatically? There is lot of information in these documents, that does not seem to be covered by this approach. Could you provide some kind of mock PRIVACY.md here on the feature wiki page that would be generated by this automatism for any component, please? I currently assume that many information would be missing, like a readable explanation to whom and why personal data is presented, which settings are important to control this etc.
Schmid, Fabian [fschmid], 10 Aug 2026:
- What is a GDPR audit trail?
I removed mentioning that since it's not a phrase we should use here (as people seem to look for references to the GDPR). As mentioned above: Logging won't be a feature the core delivers.
JourFixe, ILIAS [jourfixe], 10 AUG 2026: We highly appreciate Fabian's concept for specific data types that could replace primitive data types, e.g. in the context of privacy. But we do not want to rush into a quick decision and postpone the discussion the next Jour Fixe. Until then, we would highly appreciate to get a kind of mockup report that shows how a privacy.md file would like when it is autogenerated using the new data types – in a first step with placeholders in a current md file and how in a final stage. And Chris and Fabian will try to clarify the terms used in this FR to avoid misunderstandings especially in relation to the privacy rules and their implications.
6 Implementation
Feature has been implemented by {Please add related profile link of this person}
6.1 Description and Screenshots
Reference implementation lives under:
- components/ILIAS/Data/src/Privacy/ — types, sources, purposes, logger
- components/ILIAS/Data/PHPStan/Privacy/ — rules, collector, doc generator
- components/ILIAS/Data/tests/Privacy/ — unit tests
- scripts/Privacy/generate-privacy-docs.php — CLI doc generator
No screenshots — the feature has no UI. The visible output is the generated PRIVACY.md file per component (Markdown tables: stored / displayed / passed / technical, plus a GDPR-relevance summary).
6.2 Test Cases
Test cases completed at {date} by {user}
- Test cases to be defined after implementation.
6.3 Privacy
Covered under 4.3. Implementation must guarantee no raw value is written to the audit trail and that masking holds for every concrete type. Audit-trail retention policy to be implemented per the agreed policy.
6.4 Approval
Approved at {date} by {user}.
Last edited: 10. Aug 2026, 14:40, Kunkel, Matthias [mkunkel]