Make the site GDPR-compliant with a plugin of its own #297

Closed
opened 2026-09-23 11:11:48 +00:00 by tiagoagueda · 0 comments
Owner

Postulo keeps a lot of personal data on a person's behalf -- contacts and their phone numbers,
addresses, documents, CVs, letters, everything a capture brings in. On a self-hosted instance the
operator is the controller for everything in the database, and where the instance is in the EU, or
holds data of EU data subjects, GDPR applies to it. The site currently has no built-in way to meet
any of that: nothing in the repository names the regulation yet, and this is the issue that changes
that.

The account holder's own rights are already met -- the account archive carries every row and file
the account owns, and account deletion removes them. What is missing is the rest: the data the site
keeps about other people, and the duties that sit with the instance itself.

The shape

A plugin of the internal kind -- one that ships in the box, in the company of the other feature
plugins (several phone numbers, several email addresses, employer structure) -- declared as a
FeaturePlugin, registered under postulo.features, with its own manifest and its own locale, and
importing nothing but postulo.plugins.api. As with every feature, it is switched on and off, and
it governs what the site offers and uses, not what the database holds.

What it offers

  • What the site keeps about one contact. A data-subject-style export of everything the instance
    holds on one person -- rows, documents, files, and every plugin's own rows -- with the archive's
    discipline: what a plugin owns and cannot answer for is named as not_carried rather than
    silently dropped. This is the answer to "what do you have on me?".
  • Erasure. Deleting a contact removes everything that points at them: their rows, their
    documents and files, and each plugin's own rows for them -- the same guarantee the uninstall
    machinery already demands of a plugin before it may go. Off never deletes; this does, and it says
    what it deleted.
  • Retention. A setting for how long records are kept, and a dry run that reports what the policy
    would touch before anything is deleted.
  • The record of processing. The Article 30 page: what the instance processes, why, and who
    receives it. Much of this is already derivable -- every installed plugin, and every notifier,
    outbox, store and sync, is a purpose or a recipient in its own right -- so the page is drawn from
    the registry and the connections, not from a second list to keep in sync.
  • The notice. The instance's privacy text, shown wherever the site promises to keep something.

Not in scope (yet)

The account holder's own data stays with the archive and the account deletion that already exist.
The operator's legal bases and the legal opinion are the operator's, not the plugin's.

Done when

  • The plugin ships in the box under src/postulo/plugins/, with its manifest and locale, and is
    found by the registry like every other.
  • tests/test_plugin_surface.py passes: it imports the surface only, and owns its catalogues.
  • The export names what it could not carry; erasure is complete and says what it deleted; the
    retention dry run deletes nothing.
  • The record of processing is drawn from the installed plugins and the connections.
  • The wiki has a design note, as every part of a feature does.
Postulo keeps a lot of personal data on a person's behalf -- contacts and their phone numbers, addresses, documents, CVs, letters, everything a capture brings in. On a self-hosted instance the operator is the controller for everything in the database, and where the instance is in the EU, or holds data of EU data subjects, GDPR applies to it. The site currently has no built-in way to meet any of that: nothing in the repository names the regulation yet, and this is the issue that changes that. The account holder's own rights are already met -- the account archive carries every row and file the account owns, and account deletion removes them. What is missing is the rest: the data the site keeps about *other people*, and the duties that sit with the instance itself. ## The shape A plugin of the internal kind -- one that ships in the box, in the company of the other feature plugins (several phone numbers, several email addresses, employer structure) -- declared as a `FeaturePlugin`, registered under `postulo.features`, with its own manifest and its own locale, and importing nothing but `postulo.plugins.api`. As with every feature, it is switched on and off, and it governs what the site offers and uses, not what the database holds. ## What it offers - **What the site keeps about one contact.** A data-subject-style export of everything the instance holds on one person -- rows, documents, files, and every plugin's own rows -- with the archive's discipline: what a plugin owns and cannot answer for is *named* as `not_carried` rather than silently dropped. This is the answer to "what do you have on me?". - **Erasure.** Deleting a contact removes everything that points at them: their rows, their documents and files, and each plugin's own rows for them -- the same guarantee the uninstall machinery already demands of a plugin before it may go. Off never deletes; this does, and it says what it deleted. - **Retention.** A setting for how long records are kept, and a dry run that reports what the policy would touch before anything is deleted. - **The record of processing.** The Article 30 page: what the instance processes, why, and who receives it. Much of this is already derivable -- every installed plugin, and every notifier, outbox, store and sync, is a purpose or a recipient in its own right -- so the page is drawn from the registry and the connections, not from a second list to keep in sync. - **The notice.** The instance's privacy text, shown wherever the site promises to keep something. ## Not in scope (yet) The account holder's own data stays with the archive and the account deletion that already exist. The operator's legal bases and the legal opinion are the operator's, not the plugin's. ## Done when - The plugin ships in the box under `src/postulo/plugins/`, with its manifest and locale, and is found by the registry like every other. - `tests/test_plugin_surface.py` passes: it imports the surface only, and owns its catalogues. - The export names what it could not carry; erasure is complete and says what it deleted; the retention dry run deletes nothing. - The record of processing is drawn from the installed plugins and the connections. - The wiki has a design note, as every part of a feature does.
tiagoagueda added this to the 0.5.0 milestone 2026-09-25 12:58:52 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
Postulo/postulo#297
No description provided.