| name | ls-logboek |
| description | Logboek Dataverwerkingen voor AVG/GDPR-transparantie. NEN 7513, OpenTelemetry/OTLP, dpl.core, verwerkingenlogging in overheidssystemen. |
| model | sonnet |
| allowed-tools | ["Bash(gh api *)","Bash(gh issue list *)","Bash(gh pr list *)","Bash(gh search *)","Bash(curl -s *)","WebFetch(*)"] |
| metadata | {"created-with-ai":"true","created-with-model":"claude-opus-4-20250514","created-date":"2025-02-12","status":"concept"} |
CONCEPT โ Let op: Deze skill is geen officieel product van Logius. De beschrijvingen zijn informatieve samenvattingen โ niet de officiรซle standaarden zelf. De definities op forumstandaardisatie.nl en Logius zijn altijd leidend. Overheidsorganisaties die generatieve AI inzetten dienen te voldoen aan het Overheidsbreed standpunt voor de inzet van generatieve AI. Zie DISCLAIMER.md en onze verantwoording.
Logboek Dataverwerkingen
Agent-instructie: Deze skill helpt bij het implementeren van logging van dataverwerkingen conform AVG/GDPR. Gebruik OpenTelemetry SDK met de dpl.core namespace attributen. Trace Context headers propageren automatisch over organisatiegrenzen.
Het Logboek Dataverwerkingen is de standaard voor het transparant vastleggen van dataverwerkingen door
overheidsorganisaties. Het biedt een gestandaardiseerde manier om verwerkingsactiviteiten te registreren
en raadplegen, in lijn met de AVG/GDPR verantwoordingsplicht. De standaard is gebaseerd op
OpenTelemetry en W3C Trace Context, waardoor verwerkingen over organisatiegrenzen heen traceerbaar zijn.
Versiemodel
Net als andere Logius-standaarden kent Logboek Dataverwerkingen twee publicatiekanalen (vergelijkbaar met W3C):
- Vastgestelde versie (DEF): officieel goedgekeurd, gepubliceerd op
gitdocumentatie.logius.nl
- Werkversie (draft): werk-in-uitvoering, gepubliceerd op
logius-standaarden.github.io
De normatieve hoofdspecificatie logboek-dataverwerkingen heeft sinds 9 april 2026 een vastgestelde versie v1.0.0. De overige onderdelen (inleiding, juridisch-beleidskader, extensies) hebben nog alleen werkversies. Extensies ontlenen hun status aan de hoofdspecificatie. Logboek Dataverwerkingen is nog niet opgenomen op de lijst van het Forum Standaardisatie.
Repositories
Architectuur
De architectuur volgt een gedecentraliseerd model met drie kerncomponenten:
โโโโโโโโโโโโโโโ
โ Applicatie โ
โ (verwerker) โ
โโโโโโโโฌโโโโโโโ
โ schrijft logregels
v
โโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโ
โ Register โ<โโโโโ Logboek โ
โ (Art. 30) โ ref โ (log store) โ
โโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโ
Log Record Structuur
Elk log record volgt de OpenTelemetry Span-structuur met verplichte en optionele velden:
| Veld | Type | Verplicht | Beschrijving |
|---|
trace_id | 16 bytes | Ja | Uniek trace ID over systemen heen (W3C Trace Context) |
span_id | 8 bytes | Ja | Uniek action ID binnen een verwerking |
parent_span_id | 8 bytes | Nee | ID van de aanroepende actie (voor parent-child relaties) |
status | enum | Ja | Unset, Ok, of Error |
name | string | Ja | Mensleesbare actienaam (bijv. "Opvragen persoonsgegevens") |
start_time | uint64 | Ja | Starttijd in milliseconden sinds Unix Epoch |
end_time | uint64 | Ja | Eindtijd in milliseconden sinds Unix Epoch |
resource | object | Nee | Systeem- en applicatie-identificatie |
attributes | object | Ja | Verwerkingsmetadata in de dpl namespace |
Toelichting:
trace_id en span_id worden automatisch gegenereerd conform W3C Trace Context.
parent_span_id maakt het mogelijk om een boom van gerelateerde acties op te bouwen.
status geeft aan of de verwerking succesvol was; bij Error is aanvullende foutinformatie aan te raden.
resource identificeert het systeem (naam, versie, omgeving) dat de logregel produceert.
attributes bevat de domeinspecifieke metadata in de dpl.core namespace.
Core Attributes (dpl.core namespace)
De dpl.core namespace bevat de verplichte en optionele verwerkingsattributen:
| Attribuut | Type | Verplicht | Beschrijving |
|---|
dpl.core.processing_activity_id | URI | Ja | Verwijzing naar de verwerkingsactiviteit in het Register (AVG Art. 30). Koppelt de logregel aan het doel en de grondslag van de verwerking. |
dpl.core.data_subject_id | string | Ja | Unieke, versleutelde identificerende code van de betrokkene. De specificatie BEVEELT AAN om deze te pseudonimiseren (SHOULD). |
dpl.core.data_subject_id_type | string | Ja | Type identificatie van de betrokkene. Mogelijke waarden: BSN, personeelsnummer, URI, of een ander organisatiespecifiek type. |
dpl.core.foreign_operation.processor | URL | Nee | Link naar de externe applicatie of organisatie die betrokken is bij een cross-organisatie verwerking. Wordt ingevuld wanneer een verwerking een andere partij betreft. |
Voorbeeld attributes object:
{
"dpl.core.processing_activity_id": "https://register.example.org/activiteiten/123",
"dpl.core.data_subject_id": "a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2",
"dpl.core.data_subject_id_type": "BSN",
"dpl.core.foreign_operation.processor": "https://api.andere-organisatie.nl/service"
}
Let op: dpl.core.data_subject_id bevat hier een HMAC-SHA256 hash van het BSN. De specificatie BEVEELT AAN (SHOULD) om de identificerende code te pseudonimiseren. In het implementatievoorbeeld hieronder tonen we HMAC-SHA256 als een mogelijke aanpak; de specificatie schrijft geen specifiek algoritme voor.
Cross-organisatie Flow
Onderstaand voorbeeld toont hoe trace-informatie over organisatiegrenzen stroomt:
Organisatie A: Applicatie vraagt data op
-> Genereert trace_id (bijv. 4bf92f...) en span_id (bijv. 00f067...)
-> Logt verwerking in eigen Logboek met dpl.core attributes
-> Stuurt HTTP-request met traceparent header naar Organisatie B
Organisatie B: Service ontvangt request
-> Ontvangt trace_id (4bf92f...) uit traceparent header
-> Maakt nieuw span_id (bijv. a1b2c3...), zet parent_span_id = 00f067...
-> Logt verwerking in eigen Logboek met zelfde trace_id
-> Kan doorketen naar Organisatie C met traceparent header
Organisatie C: Backend verwerkt aanvraag
-> Ontvangt trace_id (4bf92f...) uit traceparent header
-> Maakt nieuw span_id, zet parent_span_id = a1b2c3...
-> Logt verwerking in eigen Logboek met zelfde trace_id
Resultaat:
- Alle logregels delen hetzelfde trace_id
- Elke organisatie kan alleen het eigen Logboek doorzoeken
- Via trace_id is de volledige verwerkingsketen reconstrueerbaar
- Geen persoonsgegevens verlaten de organisatie, alleen trace-metadata
Protocol
De standaard schrijft geen specifiek transportprotocol voor, maar beveelt OpenTelemetry Protocol (OTLP) aan als transportprotocol voor het aanleveren van logregels aan het Logboek.
Vereisten:
- Het Logboek MOET TLS kunnen afdwingen (capability-eis aan de software). De spec verduidelijkt expliciet dat hiermee niet wordt bedoeld dat TLS verplicht is โ of TLS-connecties daadwerkelijk worden toegepast is een organisatie-keuze.
- Het Logboek MOET elke schrijfactie bevestigen met een bevestigingsbericht (acknowledgement). De applicatie weet hierdoor zeker dat de logregel is opgeslagen.
- OTLP ondersteunt zowel gRPC als HTTP/protobuf als transportlaag (standaard OTLP-poorten: 4317 voor gRPC, 4318 voor HTTP โ niet voorgeschreven door de Logboek-standaard zelf).
Extensies
De standaard is modulair uitbreidbaar via extensies. Elke extensie voegt aanvullende velden of functionaliteit toe aan het basismodel.
Object Extensie
Voegt objectgegevens toe aan logregels. Bruikbaar wanneer verwerkingen betrekking hebben op specifieke objecten (bijv. kadastrale percelen, voertuigen, gebouwen, maar ook andere domeinobjecten). Definieert aanvullende attributes in de dpl.objects namespace.
Lees Extensie
Biedt een gestandaardiseerde API voor het raadplegen van het Logboek. De basisstandaard definieert alleen het schrijven; deze extensie voegt leesoperaties toe. Ondersteunt filteren op trace_id, tijdsbereik en betrokkene.
NEN 7513 Extensie
Zorg-specifieke uitbreiding voor logging conform NEN 7513. Voegt verplichte attributen toe voor de zorgsector, zoals gebruikersidentificatie, patiรซntidentificatie en de specifieke actie op het medisch dossier.
Implementatievoorbeelden
Python Applicatie met OpenTelemetry SDK
import hashlib, hmac, os
from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter
from opentelemetry.sdk.resources import Resource
ORG_SALT = os.environ["DPL_ORG_SALT"]
def pseudonimiseer_bsn(bsn: str) -> str:
"""HMAC-SHA256 pseudonimisering van BSN. Eenrichtings, deterministisch per organisatie."""
return hmac.new(ORG_SALT.encode(), bsn.encode(), hashlib.sha256).hexdigest()
resource = Resource.create({
"service.name": "mijn-applicatie",
"service.version": "1.0.0",
"deployment.environment": "production",
})
provider = TracerProvider(resource=resource)
provider.add_span_processor(
BatchSpanProcessor(OTLPSpanExporter(endpoint="http://logboek:4317", insecure=True))
)
trace.set_tracer_provider(provider)
tracer = trace.get_tracer("mijn-applicatie")
def verwerk_aanvraag(bsn: str, verwerking_id: str):
"""Log een dataverwerking conform Logboek Dataverwerkingen standaard."""
with tracer.start_as_current_span("verwerk-aanvraag") as span:
span.set_attribute("dpl.core.processing_activity_id",
f"https://register.example.com/verwerkingen/{verwerking_id}")
span.set_attribute("dpl.core.data_subject_id", pseudonimiseer_bsn(bsn))
span.set_attribute("dpl.core.data_subject_id_type", "BSN")
resultaat = opvragen_gegevens(bsn)
if resultaat.error:
span.set_status(trace.StatusCode.ERROR, resultaat.error)
span.set_attribute("exception.message", str(resultaat.error))
else:
span.set_status(trace.StatusCode.OK)
return resultaat
Cross-organisatie Verwerking met W3C Trace Context
import requests
from opentelemetry import trace
from opentelemetry.propagate import inject
tracer = trace.get_tracer("organisatie-a")
def vraag_gegevens_op_bij_organisatie_b(bsn: str):
"""Cross-organisatie call met W3C Trace Context propagatie."""
with tracer.start_as_current_span("opvragen-externe-gegevens") as span:
span.set_attribute("dpl.core.processing_activity_id",
"https://register.example.com/verwerkingen/opvragen-brp")
span.set_attribute("dpl.core.data_subject_id", pseudonimiseer_bsn(bsn))
span.set_attribute("dpl.core.data_subject_id_type", "BSN")
headers = {}
inject(headers)
response = requests.get(
"https://api.organisatie-b.nl/v1/personen",
params={"bsn": bsn},
headers=headers,
cert=("pkio_cert.pem", "pkio_key.pem"),
)
span.set_attribute("dpl.core.foreign_operation.processor",
"https://api.organisatie-b.nl/v1/personen")
return response.json()
Ontvangen van Cross-organisatie Requests (FastAPI)
from fastapi import FastAPI, Request
from opentelemetry import trace
from opentelemetry.propagate import extract
app = FastAPI()
tracer = trace.get_tracer("organisatie-b")
@app.get("/v1/personen")
async def get_persoon(bsn: str, request: Request):
"""Ontvang request met W3C Trace Context van andere organisatie."""
context = extract(dict(request.headers))
with tracer.start_as_current_span("verwerk-extern-verzoek", context=context) as span:
span.set_attribute("dpl.core.processing_activity_id",
"https://register.organisatie-b.nl/verwerkingen/leveren-brp")
span.set_attribute("dpl.core.data_subject_id", pseudonimiseer_bsn(bsn))
span.set_attribute("dpl.core.data_subject_id_type", "BSN")
span.set_attribute("dpl.core.foreign_operation.processor",
request.headers.get("origin", "onbekend"))
persoon = database.get_persoon(bsn)
return persoon
Meerdere Betrokkenen per Verwerking
def verwerk_batch(bsn_lijst: list[str], verwerking_id: str):
"""Bij meerdere betrokkenen: apart logregel per persoon."""
with tracer.start_as_current_span("batch-verwerking") as parent_span:
parent_span.set_attribute("dpl.core.processing_activity_id",
f"https://register.example.com/verwerkingen/{verwerking_id}")
for bsn in bsn_lijst:
with tracer.start_as_current_span(f"verwerk-persoon") as child_span:
child_span.set_attribute("dpl.core.data_subject_id", pseudonimiseer_bsn(bsn))
child_span.set_attribute("dpl.core.data_subject_id_type", "BSN")
child_span.set_attribute("dpl.core.processing_activity_id",
f"https://register.example.com/verwerkingen/{verwerking_id}")
verwerk_persoon(bsn)
Foutafhandeling
Status Waarden en Wanneer te Gebruiken
| Status | Wanneer | Voorbeeld |
|---|
| Unset (standaard) | Verwerking afgerond zonder systeemfout, ook als er geen resultaat is | Persoon niet gevonden in BRP |
| Ok | Expliciete succesmarkering (optioneel) | Gegevens succesvol opgehaald |
| Error | Systeemfout tijdens verwerking | Database timeout, API onbereikbaar |
Let op: Een gebruikersannulering is GEEN error. Markeer als Ok met een expliciete actie.
Error Logging met Exception Details
import traceback
with tracer.start_as_current_span("verwerk-gegevens") as span:
span.set_attribute("dpl.core.processing_activity_id", verwerking_url)
span.set_attribute("dpl.core.data_subject_id", pseudonimiseer_bsn(bsn))
span.set_attribute("dpl.core.data_subject_id_type", "BSN")
try:
result = external_api.get(bsn)
except TimeoutError as e:
span.set_status(trace.StatusCode.ERROR, "External API timeout")
span.set_attribute("exception.type", "TimeoutError")
span.set_attribute("exception.message", str(e))
span.set_attribute("exception.stacktrace", traceback.format_exc())
raise
Verplichte Velden Validatie
Een logregel MOET minimaal bevatten:
trace_id (16 bytes) - uniek per verwerkingsketen
span_id (8 bytes) - uniek per actie
name - beschrijvende naam van de actie
start_time en end_time - milliseconden sinds Epoch
status - Unset, Ok, of Error
dpl.core.processing_activity_id - URI naar het register
dpl.core.data_subject_id - (versleuteld) ID van betrokkene
dpl.core.data_subject_id_type - type identifier (BSN, KvK, etc.)
Als een verplicht veld ontbreekt, MOET de software een standaardwaarde invullen om runtime-fouten te voorkomen. Log sampling is NIET toegestaan.
Achtergrondinfo
Zie reference.md voor de architectuurbeschrijving, W3C Trace Context details, Docker demo-omgeving, en extensie-details.
Zie conflicts.md voor bronconflicten en gemaakte keuzes.