Gebaseerd op: User Story #722
Consumers willen op een eenvoudige manier een audit trail kunnen opvragen zoals die nu veelal wordt weergeven in monolithische zaaksystemen.
We hanteren voor het opstellen van een audit trail, de volgende definitie:
De audit trail bevat voldoende gegevens om achteraf te kunnen herleiden (1) welke essentiële handelingen (2) wanneer door (3a) wie of (3b) vanuit welk systeem (4) met welk resultaat zijn uitgevoerd. Tot essentiële handelingen worden in ieder geval gerekend: opvoeren en afvoeren posten, statusveranderingen met wettelijke, financiële of voor de voortgang van het proces, de zaak of de klant beslissende gevolgen.
Bron: NORA
We laten de relatie met logging (in het algemeen) en doelbinding volgens de AVG buiten beschouwing. Hier zijn andere oplossingen voor in de maak, zoals NLX.
De API wordt gerealiseerd als alleen-lezen endpoint binnen de API van het component, waarbij de resource “audittrail” wordt ontsloten als sub-resource van het hoofdobject van de bron.
Voor het ZRC zal dit dus zijn: /api/v1/zaken/<uuid>/audittrail
.
De audit trail bevat dus alle wijzigingen op de zaak, waaronder status wijzigingen, het koppelen of ontkoppelen van documenten, etc.
Rationale
De audit trail API kan worden gerealiseerd op verschillende manieren, t.w.:
We realiseren geen apart component voor de audit trail waar alle componenten hun logging heen sturen. Dit zou een synchrone afhankelijkheid creëeren en er gaat potentieel veel informatie over het netwerk wat veel overhead veroorzaakt, zelfs als niemand deze audit trail ooit raadpleegt. Ten slotte staat deze opzet een eventueel centraal logging component niet in de weg.
De audit trail API wordt dus onderdeel van elk component. Er zijn hierin 3 keuzes te maken, t.w.:
example.com/zrc/api/v1
en example.com/zrc/audittrail/api/v1
).example.com/zrc/api/v1/audittrail
).example.com/zrc/api/v1/zaken/<uuid>/audittrail
).Bij het NRC is voor het ontvangen van notificaties door componenten gekozen voor een zelfstandige OAS (optie 1). Dit voorkomt dat een wijziging voor de audit trail API alle API’s van componenten raakt. Echter, bij het NRC geeft de consumer zelf aan waar deze API te vinden is. Bij de audit trail is hiervan geen sprake en dus moet de API consistent en snel te vinden zijn. Tevens is de audit trail ook echt een onderdeel van het component (optie 2 en 3).
We kiezen voor optie 3 omdat een audit trail typisch wordt opgevraagd van een bepaalde zaak. Dit laat optie 2 overigens mogelijk voor de toekomst.
uuid
(automatisch)
Unieke identificatie van de audit regel.
requestId
(optioneel)
Unieke identificatie van het verzoek in het netwerk om over verschillende gateways heen te kunnen loggen.
Op dit moment wordt alleen de NLX header X-NLX-Request-Id
waarde
overgenomen in dit attribuut bij elke audit regel, indien aanwezig.
bron
(automatisch)
De naam van het component waar de wijziging in is gedaan. Hoewel dit attribuut in de context van de API niet relevant lijkt, aangezien de API onderdeel is van het component. Mocht deze API echter gebruikt worden in een geaggregeerde context, dan blijft het formaat voor consumers gelijk.
applicatieId
(verplicht)
Unieke identificatie van de applicatie, binnen de organisatie.
Deze moet worden gehaald uit het payload attribuut client_id
van het JWT
token. Indien er geen gebruik wordt gemaakt van JWT of het attribuut
client_id
is niet aanwezig dan kan terugvallen worden op de NLX header
X-NLX-Request-Application-Id
.
applicatieWeergave
(optioneel)
Vriendelijke naam van de applicatie. Deze kan worden afgeleid uit het label
attribuut van de Applicatie
resource in het Autorisatie Component (AC).
gebruikersId
(verplicht)
Unieke identificatie van de gebruiker die binnen de organisatie herleid kan
worden naar een persoon. Dit mag bijvoorbeeld het ID zijn van de gebruiker
zoals deze bekend is in Active Directory, of het ID van de gebruiker zoals deze
alleen binnen de applicatie bekend is. In het laatste geval kan de persoon met
behulp van het applicatieId
ook tot een persoon herleid worden.
Deze moet worden gehaald uit het payload attribuut user_id
van het JWT token.
Indien er geen gebruik wordt gemaakt van JWT of het attribuut user_id
is
niet aanwezig dan kan terugvallen worden op de NLX header
X-NLX-Request-User-Id
.
gebruikersWeergave
(optioneel)
Vriendelijke naam van de gebruiker.
Deze moet worden gehaald uit het payload attribuut user_representation
van
het JWT token indien aanwezig.
actie
(verplicht)
De uitgevoerde handeling zoals bij notificaties.
actieWeergave
(optioneel)
Vriendelijke naam van de actie. Bijvoorbeeld als een relatie tussen een document en een zaak wordt aangemaakt: “gekoppeld aan Zaak MOR-000001”.
TODO: Wellicht ook toevoegen aan het NRC (buiten scope)
resultaat
(verplicht)
HTTP status code van de API response van de uitgevoerde handeling. Een HTTP status code van “200” of “201” is bijvoorbeeld een succesvol uitgevoerde handeling, terwijl een “403” aangeeft dat de gebruiker of applicatie het wel geprobeerd heeft maar de handeling is niet uitgevoerd.
hoofdObject
(verplicht)
De URL naar het hoofdobject van een component zoals bij notificaties. Bij het ZRC is dit dus altijd de URL naar een zaak.
resource
(verplicht)
De resource naam zoals bij notificaties.
resourceUrl
(verplicht)
De URL naar het object zoals bij notificaties. Dit is bijvoorbeeld de URL naar een status, een rol, etc.
resourceWeergave
(optioneel)
Vriendelijke identificatie van het object. Bijvoorbeeld de zaak identificatie of de omschrijving van een status. Deze weergave kan bijvoorbeeld gebaseerd zijn op de semantische unieke identificatie zoals deze in het RGBZ staat.
toelichting
(optioneel)
Toelichting waarom de handeling is uitgevoerd. Dit kan handig zijn voor sommige
handelingen waarbij additionele context gewenst is, zoals het ophogen van een
archiveringstermijn of een correctie buiten het reguliere proces om. Deze kan
voor elk verzoek meegegeven als X-Audit-Toelichting
header.
aanmaakdatum
(automatisch)
De datum waarop de handeling is gedaan.
wijzigingen
(verplicht)
Een object met 2 attributen:
oud
- Volledige JSON body van het object zoals dat bestond voordat de actie
heeft plaatsgevonden. De waarde null
wordt gebruikt als er geen oude versie
is (bijvoorbeeld in het geval van het aanmaken van een object).nieuw
- Volledige JSON body van het object na de actie. De waarde null
wordt gebruikt als er geen nieuwe versie is (bijvoorbeeld in het geval dat
het object wordt verwijderd).In het ZRC wordt de audit trail als volgt ontsloten:
GET /api/v1/zaken/<uuid>/audittrail
[
{
"uuid": "311cf2",
"bron": "ZRC",
"applicatieId": "demo-app",
"applicatieWeergave": "Demo applicatie",
"gebruikersId": "14",
"gebruikersWeergave": "Joeri Bekker",
"actie": "create",
"actieWeergave": "",
"resultaat": 201,
"hoofdObject": "https://www.example.com/api/v1/zaken/5ab6e2",
"resource": "status",
"resourceUrl": "https://www.example.com/api/v1/statussen/11cb71",
"resourceWeergave": "Ingediend",
"toelichting": "",
"aanmaakdatum": "2019-05-05T11:53:18.090384Z",
"wijzigingen": {
"oud": null,
"nieuw": { ... },
}
]
Hiermee kan de volgende (eenvoudige) audit regel worden opgesteld:
<aanmaakdatum> <resource> "<resourceWeergave>" is <resultaat> <actie/actieWeergave> in <bron> door <gebruikersWeergave> (<gebruikersId>) via <applicatieWeergave> (<applicatieId)
Dat als instantie vertaald kan worden naar:
5 mei 2019 11:53 Status "Ingediend" is succesvol aangemaakt in ZRC door Joeri Bekker (14) via Demo Applicatie (demo-app).
Tot nu toe hebben we alleen een audit trail besproken van een enkel component. Als er echter bij een zaak ook documenten en besluiten worden gemaakt in andere componenten, dan zou deze idealiter in een volledige audit trail van de zaak terug komen. Afhankelijk van de gebruikersinterface kan dit wel of niet nodig zijn.
Alle componenten gaan de audit trail endpoint ontsluiten. Als de zaak wordt opgevraagd, dan worden ook de gerelateerde documenten en besluiten bekend zoals die leven in respectievelijk het DRC en het BRC. Hiervoor zal dus 1 call per component nodig zijn om de volledige audit trail te verkrijgen.
Overigens wordt dit niet persé eenvoudiger als alles in 1 audit trail component zou zitten. Immers moeten nog steeds alle URLs van de hoofdObjecten bekend zijn en worden opgevraagd.
Als een object wordt verwijderd in het kader van archievering, dan moet ook de audit trail verwijderd worden.