Connectors
Connect systems, with GDPR controls
What it is for
Connect other systems to the instance and let people connect their own accounts, with the controls that support GDPR compliance built in. Nothing leaves or enters without a recorded legal basis and a field allowlist; personal data goes out as keyed pseudonyms unless you decide otherwise, the sensitive classes stay withheld, every flow is logged without its payload, and withdrawing consent disconnects the service and purges its credentials. A processing register for Article 30 is generated from the connections. It provides technical controls; it is not legal advice or a certification, and the catalogue says for every service how much of it is implemented.
What the package does and does not do
Connect external systems and let people connect their own accounts, with the controls that support GDPR compliance built in.
Models
connector_provider
A service or protocol a connection can use, from the catalogue shipped with obop
Read group: connectors.user. Write group: connectors.admin.
| Field | Kind | Data class | Personal data | Group | Agents see | Description |
|---|---|---|---|---|---|---|
name | text | none | no | connectors.user | in clear | Name of the provider |
category | select (generic, messaging, payments, developer, calendar_contacts, automation) | none | no | connectors.user | in clear | Kind of service |
maturity | select (working, generic_adapter, definition_only) | none | no | connectors.user | in clear | How much of it exists: working, generic adapter or definition only |
engine | select (webhook_out, webhook_in, rest_pull, csv_export, none) | none | no | connectors.user | in clear | The generic engine that runs it |
auth_kind | select (api_key, bearer_token, basic, oauth2, webhook_in, webhook_out, none) | none | no | connectors.user | in clear | How the connection authenticates |
direction | select (inbound, outbound, both) | none | no | connectors.user | in clear | Whether data flows in, out or both ways |
max_classes | text | none | no | connectors.user | in clear | Data classes the provider may receive at most, comma separated |
purpose | longtext | none | no | connectors.user | in clear | What the provider is used for |
description | longtext | none | no | connectors.user | in clear | How it works and what is tested |
legal_name | text | none | no | connectors.user | in clear | Legal name of the recipient (sub-processor information) |
country | text | none | no | connectors.user | in clear | Country of the recipient |
dpa_url | text | none | no | connectors.user | in clear | Where the provider publishes its data processing agreement |
eu_adequate | select (yes, no, verify) | none | no | connectors.user | in clear | Whether transfers rest on EU or adequate-country processing: yes, no or verify with the provider |
verify_note | longtext | none | no | connectors.user | in clear | What to confirm with the provider before relying on these facts |
allowed_hosts | text | none | no | connectors.user | in clear | Hosts the provider connects to, comma separated; empty means the connection names its own |
config_fields | longtext | none | no | connectors.user | in clear | Settings and credentials the provider needs, as a JSON list |
setup | longtext | none | no | connectors.user | in clear | Setup instructions |
webhook_scheme | select (standard, github, stripe) | none | no | connectors.user | in clear | Signature scheme of inbound webhooks |
oauth_scopes | text | none | no | connectors.user | in clear | OAuth scopes requested, for OAuth providers |
enabled | bool | none | no | connectors.user | in clear | An administrator enabled the provider |
users_may_use | bool | none | no | connectors.user | in clear | People may connect their own accounts with it |
dpa_recorded | bool | none | no | connectors.user | in clear | The agreement with the provider is recorded |
legal_basis | select (consent, contract, legitimate_interest, legal_obligation) | none | no | connectors.user | in clear | Legal basis the administrator set for this provider |
legal_basis_text | longtext | none | no | connectors.user | in clear | Text shown to people when they are asked for consent |
provider_policy
What an administrator decided about one provider: enabled, for whom, legal basis, agreement and OAuth client
Read group: connectors.admin. Write group: connectors.admin.
| Field | Kind | Data class | Personal data | Group | Agents see | Description |
|---|---|---|---|---|---|---|
provider | text | none | no | connectors.admin | in clear | Id of the provider this policy is for |
enabled | bool | none | no | connectors.admin | in clear | The provider may be connected at all |
users_may_use | bool | none | no | connectors.admin | in clear | People with connectors.user may connect their own accounts |
allowed_group | text | none | no | connectors.admin | in clear | Permission group that may use it; empty means connectors.user |
legal_basis | select (consent, contract, legitimate_interest, legal_obligation) | none | no | connectors.admin | in clear | Legal basis recorded for connections of this provider |
legal_basis_text | longtext | none | no | connectors.admin | in clear | Text shown to people when they are asked for consent |
dpa_recorded | bool | none | no | connectors.admin | in clear | A data processing agreement with the provider is in place |
dpa_reference | text | none | no | connectors.admin | in clear | Where the agreement is kept or its reference |
default_policy | longtext | none | no | connectors.admin | in clear | Policy JSON that new connections of this provider start with |
oauth_client_id | text | internal | no | connectors.admin | in clear | OAuth client id you registered with the provider |
oauth_client_secret | longtext | secret | no | connectors.admin | withheld | OAuth client secret; write-only, stored encrypted |
connection
A link to one external system, with its credentials, field allowlist, policy and state
Read group: connectors.user. Write group: connectors.user.
| Field | Kind | Data class | Personal data | Group | Agents see | Description |
|---|---|---|---|---|---|---|
name | text | none | no | connectors.user | in clear | A name that tells you what the connection is for |
provider | text | none | no | connectors.user | in clear | Id of the provider from the catalogue |
owner_scope | select (instance, user) | none | no | connectors.user | in clear | Whether the connection belongs to the instance or to one person |
owner_user | text | internal | yes | connectors.user | masked | The person who owns the connection |
owner_groups | text | none | no | connectors.admin | in clear | Permission groups the owner held when the connection was last changed |
state | select (draft, connected, paused, error, revoked) | none | no | connectors.user | in clear | Where the connection is: draft, connected, paused, error or revoked |
config | longtext | none | no | connectors.user | in clear | Non-secret settings as a JSON object |
credentials | longtext | secret | no | connectors.user | withheld | Credentials as a JSON object; write-only, stored encrypted, never returned |
credentials_hint | text | none | no | connectors.user | in clear | Whether credentials are set, with at most the last four characters |
oauth_tokens | longtext | secret | no | connectors.user | withheld | OAuth tokens; write-only, stored encrypted, never returned |
field_allowlist | longtext | none | no | connectors.user | in clear | Fields that may leave or be accepted, as a JSON object of model to field names; empty means nothing |
policy | longtext | none | no | connectors.user | in clear | Treatment overrides by class or field and impact-assessment acknowledgements, as JSON |
rate_limit_per_hour | number | none | no | connectors.user | in clear | Most flows per hour |
volume_cap_per_day | number | none | no | connectors.user | in clear | Most records per day |
retention_days | number | none | no | connectors.user | in clear | Days flow logs and runs are kept |
created_at | text | none | no | connectors.user | in clear | When the connection was created |
last_sync_at | text | none | no | connectors.user | in clear | When the connection last ran |
last_error | text | none | no | connectors.user | in clear | Summary of the last failure, without payloads |
result | longtext | none | no | connectors.user | in clear | Output of the last command (test, sync, authorisation link); never stored |
consent
The legal basis recorded for a connection: who, why, which data classes, and whether it was withdrawn
Read group: connectors.user. Write group: connectors.user.
| Field | Kind | Data class | Personal data | Group | Agents see | Description |
|---|---|---|---|---|---|---|
connection | ref → connection | none | no | connectors.user | in clear | The connection this basis is for |
owner_user | text | internal | yes | connectors.user | masked | Owner of the connection |
state | select (active, withdrawn, superseded) | none | no | connectors.user | in clear | active, withdrawn, or superseded by a newer record |
subject_kind | select (user, party, instance) | none | no | connectors.user | in clear | Whose basis it is: a user, a party or the instance |
subject | text | internal | yes | connectors.user | masked | Id of the party when the subject is a party |
given_by | text | internal | yes | connectors.user | masked | Who recorded it |
purpose | longtext | none | no | connectors.user | in clear | The purpose the data is processed for |
legal_basis | select (consent, contract, legitimate_interest, legal_obligation) | none | no | connectors.user | in clear | consent, contract, legitimate interest or legal obligation |
note | longtext | none | no | connectors.user | in clear | Explanation; for legitimate interest the balancing test |
classes | text | none | no | connectors.user | in clear | Data classes that may flow under this record, computed from the connection |
fields_summary | longtext | none | no | connectors.user | in clear | Models and fields that may flow, computed from the connection |
recorded_at | text | none | no | connectors.user | in clear | When it was recorded |
withdrawn_at | text | none | no | connectors.user | in clear | When it was withdrawn, if it was |
withdrawn_by | text | internal | yes | connectors.user | masked | Who withdrew it |
sync_run
One run of a connection: when, how many records, and how it ended; never the data
Read group: connectors.user. Write group: connectors.admin.
| Field | Kind | Data class | Personal data | Group | Agents see | Description |
|---|---|---|---|---|---|---|
connection | ref → connection | none | no | connectors.user | in clear | The connection that ran |
owner_user | text | internal | yes | connectors.user | masked | Owner of the connection |
direction | select (inbound, outbound) | none | no | connectors.user | in clear | Whether data went out or came in |
kind | select (manual, event, pull, webhook, test) | none | no | connectors.user | in clear | What started it |
started_at | text | none | no | connectors.user | in clear | When it started |
finished_at | text | none | no | connectors.user | in clear | When it ended |
status | select (running, succeeded, partial, failed, retrying, dead_letter) | none | no | connectors.user | in clear | How it ended |
records | number | none | no | connectors.user | in clear | Records sent or accepted |
rejected | number | none | no | connectors.user | in clear | Records refused |
proposed | number | none | no | connectors.user | in clear | Changes held for approval |
error_summary | text | none | no | connectors.user | in clear | Why it failed, without payloads |
data_flow_log
Append-only record of every flow: when, what, how many, which fields, how treated, and a hash of the payload; never the payload
Read group: connectors.user. Write group: connectors.admin.
| Field | Kind | Data class | Personal data | Group | Agents see | Description |
|---|---|---|---|---|---|---|
connection | ref → connection | none | no | connectors.user | in clear | The connection the flow belongs to |
owner_user | text | internal | yes | connectors.user | masked | Owner of the connection |
at | text | none | no | connectors.user | in clear | When it happened |
direction | select (outbound, inbound) | none | no | connectors.user | in clear | Whether data went out or came in |
model | text | none | no | connectors.user | in clear | The model the records belong to |
record_count | number | none | no | connectors.user | in clear | How many records |
fields_sent | text | none | no | connectors.user | in clear | Fields that left or were accepted, comma separated |
fields_denied | text | none | no | connectors.user | in clear | Fields the policy withheld, comma separated |
masking_mode | text | none | no | connectors.user | in clear | Treatments applied, for example pseudonymise=2;allow=1 |
payload_hash | text | none | no | connectors.user | in clear | SHA-256 of the payload after treatment |
outcome | select (released, received, refused, rejected, erased) | none | no | connectors.user | in clear | released, received, refused, rejected or erased |
reason | text | none | no | connectors.user | in clear | Why a flow was refused or a record rejected |
processing_register
The record of processing activities (GDPR Article 30) generated from the connections; exportable as CSV
Read group: connectors.admin. Write group: connectors.admin.
| Field | Kind | Data class | Personal data | Group | Agents see | Description |
|---|---|---|---|---|---|---|
connection | ref → connection | none | no | connectors.admin | in clear | The connection this row describes |
name | text | none | no | connectors.admin | in clear | Name of the connection |
state | text | none | no | connectors.admin | in clear | State of the connection |
owner_scope | text | none | no | connectors.admin | in clear | Instance or user |
owner_user | text | internal | yes | connectors.admin | masked | Owner of the connection |
provider | text | none | no | connectors.admin | in clear | Provider id |
recipient | longtext | none | no | connectors.admin | in clear | Who receives the data (legal name) |
recipient_country | text | none | no | connectors.admin | in clear | Where the recipient is |
purpose | longtext | none | no | connectors.admin | in clear | Purpose of the processing |
legal_basis | text | none | no | connectors.admin | in clear | Recorded legal basis |
consent_recorded_at | text | none | no | connectors.admin | in clear | When the basis was recorded |
data_subjects | longtext | none | no | connectors.admin | in clear | Categories of data subjects |
personal_data_categories | longtext | none | no | connectors.admin | in clear | Categories of personal data, with class and treatment |
transfer_basis | longtext | none | no | connectors.admin | in clear | Basis for transfers to third countries |
agreement_recorded | text | none | no | connectors.admin | in clear | Whether the agreement with the recipient is recorded |
retention_days | text | none | no | connectors.admin | in clear | Retention of logs, in days |
safeguards | longtext | none | no | connectors.admin | in clear | Technical and organisational measures |
csv | longtext | none | no | connectors.admin | in clear | The register as CSV; filled by the export command, never stored |
egress_policy
Instance-wide switches for data flows: the master switch, EU-only providers, the agreement requirement and the host allow-list
Read group: connectors.admin. Write group: connectors.admin.
| Field | Kind | Data class | Personal data | Group | Agents see | Description |
|---|---|---|---|---|---|---|
flows_enabled | bool | none | no | connectors.admin | in clear | Master switch: when off nothing leaves and nothing is accepted |
eu_only | bool | none | no | connectors.admin | in clear | Personal data only goes to providers with an EU or adequacy basis |
require_dpa | bool | none | no | connectors.admin | in clear | Personal data, even pseudonymised, only goes to providers whose agreement is recorded |
host_allowlist | text | none | no | connectors.admin | in clear | Hosts connections may reach, comma separated; empty means no extra restriction |
default_retention_days | number | none | no | connectors.admin | in clear | Retention for logs of connections that no longer exist |
result | longtext | none | no | connectors.admin | in clear | Output of the last command (checklist, purge); never stored |
privacy_preview
What a sample outbound record looks like after the policy: the exact payload and the treatment of each field
Read group: connectors.user. Write group: connectors.user.
| Field | Kind | Data class | Personal data | Group | Agents see | Description |
|---|---|---|---|---|---|---|
provider | text | none | no | connectors.user | in clear | Provider the preview is for |
connection | text | none | no | connectors.user | in clear | An existing connection to preview, instead of a provider |
target_model | text | none | no | connectors.user | in clear | The model to preview |
record_id | text | none | no | connectors.user | in clear | A record to use as the sample; empty means the first one |
field_allowlist | longtext | none | no | connectors.user | in clear | Fields to include, as a JSON object of model to field names |
policy | longtext | none | no | connectors.user | in clear | Policy JSON to preview |
payload | longtext | none | no | connectors.user | in clear | The payload after treatment, as JSON; never stored |
treatments | longtext | none | no | connectors.user | in clear | Each field with its class and treatment, as JSON; never stored |
Workflows
connection
| Action | Moves | Who may run it | Approval |
|---|---|---|---|
connection.connect | state: draft → connected | connectors.user | yes |
connection.pause | state: connected → paused | connectors.user | yes |
connection.resume | state: paused → connected | connectors.user | yes |
connection.retry | state: error → connected | connectors.user | yes |
connection.revoke | state: * → revoked | connectors.user | yes |
connection.test | - | connectors.user | no |
connection.sync | - | connectors.user | yes |
connection.oauth_start | - | connectors.user | no |
consent
| Action | Moves | Who may run it | Approval |
|---|---|---|---|
consent.withdraw | state: active → withdrawn | connectors.user | yes |
processing_register
| Action | Moves | Who may run it | Approval |
|---|---|---|---|
processing_register.export_csv | - | connectors.admin | no |
egress_policy
| Action | Moves | Who may run it | Approval |
|---|---|---|---|
egress_policy.checklist | - | connectors.admin | no |
egress_policy.purge | - | connectors.admin | yes |
privacy_preview
| Action | Moves | Who may run it | Approval |
|---|---|---|---|
privacy_preview.render | - | connectors.user | no |
Permission groups
Groups used by this app:
connectors.adminconnectors.user
Approval steps
Steps an agent can only propose:
connection.connectconnection.pauseconnection.resumeconnection.retryconnection.revokeconnection.syncconsent.withdrawegress_policy.purge
What agents can and cannot do
An agent can read, search, create and update records of this app, and run the actions that need no approval, within the permission groups of its token.
It can only propose these steps, and a person must approve them: connection.connect, connection.pause, connection.resume, connection.retry, connection.revoke, connection.sync, consent.withdraw, egress_policy.purge, connector_provider.delete, provider_policy.delete, connection.delete, consent.delete, sync_run.delete, data_flow_log.delete, processing_register.delete, egress_policy.delete, privacy_preview.delete.
Personal data is masked as placeholder tokens: connection.owner_user, consent.owner_user, consent.subject, consent.given_by, consent.withdrawn_by, sync_run.owner_user, data_flow_log.owner_user, processing_register.owner_user.
These fields are withheld from agents entirely: provider_policy.oauth_client_secret, connection.credentials, connection.oauth_tokens.
Dependencies
None.
Install
Built in. It is available in every instance and cannot be removed.