Skip to main content

StUF-ZKN/BG Adapter

Pipelinq ships a StUF 0310 SOAP adapter that bridges Pipelinq Requests and Contacts to legacy zaaksystemen (Centric Key2Zaken, Atos PinkRoccade, etc.). The adapter implements the four core ZKN operations (creeerZaak, actualiseerZaak, geefZaakDetails, genereerZaakIdentificatie), embeds documents as base64 inside the envelope, persists every round-trip into an append-only audit log, and isolates failing endpoints with a circuit breaker.

Spec

  • OpenSpec change: openspec/changes/stuf-zkn-bg-adapter/
  • Spec: openspec/changes/stuf-zkn-bg-adapter/specs/stuf-zkn-bg-adapter/spec.md

Architecture

Outbound (creeerZaak):
RequestWorkflow ─StufRequestIntegrationService.registerZaak─▶ StufAdapterService.creeerZaak
├─ CircuitBreakerService.checkEndpoint
├─ StufEnvelopeBuilder.buildLk01CreeerZaak (with WSSE+mTLS)
├─ StufMessageHandler.logOutbound → StufMessage row
├─ StufHttpClient.send (HTTPS only, mTLS)
├─ StufMessageParser.parseBevestiging
└─ persistRequestMapping → ZaaksysteemMapping row

Inbound (Bv01 / Lk02 / Fo02):
Zaaksysteem ─POST /api/stuf/inkomend (WSSE auth)─▶ StufController.inkomend
├─ resolve endpoint + verify WSSE
├─ StufMessageHandler.logInbound → StufMessage row
└─ on Bv01 with crossRefnummer:
StufMessageHandler.transitionStatus(verzonden → bevestigd)

The 503 retry path uses StufRetryJob background job (5s, 30s, 2m, 10m backoff) and reuses the SAME referentienummer for idempotency. After four consecutive transient failures the circuit opens for 5 minutes and a needs-input event is raised against every admin user (Nextcloud Notification).

Data Model

Three OpenRegister schemas live in lib/Settings/register.d/85-stuf-zkn-bg-adapter.json:

SchemaPurpose
stufEndpointOne per zaaksysteem connection (URL, sectormodel, WSSE+mTLS refs, zaaktype-mappings, vrijeBerichten templates).
stufMessageAppend-only audit log entry per envelope (full XML, HTTP status, duration, retries).
zaaksysteemMappingBidirectional link: pipelinq Request ↔ zaak, Contact ↔ NPS/NNP.

Endpoint Configuration

  1. Add a StufEndpoint object (admin UI: Settings → StUF endpoints).
  2. Store the WSSE password and (optionally) the mTLS PEM behind vault references:
    • occ config:app:set --sensitive pipelinq stuf.vault.<sha256(vault://...)> --value '...'
  3. Toggle actief: true.
  4. Map zaaktypeMappings: {request_type → zkn:omschrijving} — required, otherwise creeerZaak throws ZaaktypeNotMappedException BEFORE any transmission.
  5. Optional: register vrijeBerichtenTemplates (zetStatus, geefBetrokkene, ...).

API Surface

EndpointVerbAuthPurpose
/api/stuf/outboundPOSTAdminSend a registered vrijBericht.
/api/stuf/inkomendPOSTPublicPage + WSSEReceive zaaksysteem notifications.
/api/stuf/endpointsGETAdminList endpoints with circuit-breaker health.
/api/stuf/messagesGETAdminQuery the audit log (endpointId, berichtSoort, status, limit).

Frontend

  • Settings → StUF endpoints — list endpoints with health badges (OK, Degraded, Circuit open).
  • Settings → StUF audit log — query the per-call audit log with filters and a full envelope-XML inspection dialog. CSV export available.
  • StufLinkedZaakBadge.vue — drop-in detail-view banner that surfaces a linked zaak or betrokkene id; emits @register so the host page can trigger registration.

Troubleshooting

SymptomLikely causeFix
CIRCUIT_OPEN returned from /api/stuf/outboundEndpoint has had ≥4 consecutive transient failuresWait 5 min OR reset via occ config:app:delete pipelinq stuf.cb.open.<endpointId>
ZaaktypeNotMappedExceptionrequest.type not in endpoint's zaaktypeMappingsEdit the endpoint, add the slug → zkn omschrijving.
PayloadTooLargeExceptionAttached documents exceed 25 MiB pre-base64Strip large attachments OR use DMS-direct URL fallback.
TLS_CERT_LOAD_FAILEDmTLS vault reference unresolvableStore the PEM via the vault storeSecret() helper or admin tooling.
unauthorized on inbound endpointWSSE UsernameToken mismatchVerify zaaksysteem-side credentials against the endpoint's wachtwoordKluisRef.
Outbound stuck in verzondenBv01 never returned OR network dropAudit log → inspect retries[]; if all attempts exhausted, status moves to fout.

VNG Standards Reference