Leer hoe je een webapp ontwerpt en bouwt die SLA-naleving bijhoudt: definieer metrics, verzamel events, bereken resultaten, waarschuw bij breaches en rapporteer nauwkeurig.

SLA-naleving betekent het halen van de meetbare beloften in een Service Level Agreement (SLA)—een contract tussen een aanbieder en een klant. De taak van je app is om een eenvoudige vraag met bewijs te beantwoorden: Hebben we gedaan wat we beloofden, voor deze klant, in deze periode?
Het helpt om drie gerelateerde termen te scheiden:
De meeste SLA-tracking webapps beginnen met een kleine set metrics die aansluiten op echte operationele data:
Verschillende gebruikers willen dezelfde waarheid, gepresenteerd op verschillende manieren:
Dit product draait om bijhouden, bewijs en rapportage: signalen verzamelen, overeengekomen regels toepassen en auditvriendelijke resultaten genereren. Het garandeert niet de performance; het meet die—nauwkeurig, consistent en op een manier die je later kunt verdedigen.
Voordat je tabellen ontwerpt of code schrijft, wees messcherp over wat “naleving” voor jouw bedrijf betekent. De meeste SLA-tracking problemen zijn geen technische problemen—het zijn requirements-problemen.
Begin met het verzamelen van de bronnen van waarheid:
Schrijf deze als expliciete regels op. Als een regel niet duidelijk geformuleerd kan worden, kan hij niet betrouwbaar worden berekend.
Maak een lijst van de echte “dingen” die een SLA-cijfer kunnen beïnvloeden:
Identificeer ook wie wat nodig heeft: support wil realtime risico op breach, managers willen wekelijkse samenvattingen, klanten willen eenvoudige overzichten (vaak voor een statuspagina).
Houd de scope klein. Kies de minimale set die het systeem end-to-end bewijst, zoals:
Maak een eendelige checklist die je later kunt testen:
Succes ziet er zo uit: twee personen berekenen dezelfde voorbeeldmaand handmatig en je app komt exact overeen.
Een correcte SLA-tracker begint met een datamodel dat kan uitleggen waarom een cijfer is wat het is. Als je een maandelijkse beschikbaarheid niet kunt terugleiden naar de exacte events en regels die zijn gebruikt, krijg je ruzie met klanten en interne onduidelijkheid.
Model minimaal:
Een nuttige relatie is: customer → service → SLA policy (mogelijk via plan). Incidenten en events verwijzen dan naar service en klant.
Tijdbugs zijn de nummer één oorzaak van verkeerde SLA-wiskunde. Sla op:
occurred_at als UTC (timestamp met timezone-semantiek)received_at (wanneer je systeem het zag)source (monitornaam, integratie, manueel)external_id (om retries te dedupliceren)payload (raw JSON voor toekomstige debugging)Sla ook customer.timezone op (IANA-string zoals America/New_York) voor weergave en werkurenlogica, maar gebruik die niet om eventtijd te herschrijven.
Als reactietijd-SLA's buiten werkuren pauzeren, modelleer kalenders expliciet:
working_hours per klant (of per regio/service): dag-van-de-week + start/eindtijdenholiday_calendar gekoppeld aan een regio of klant, met datumbereiken en labelsHoud de regels data-gedreven zodat ops een feestdag kan bijwerken zonder te deployen.
Bewaar raw events in een append-only tabel en sla berekende resultaten apart op (bijv. sla_period_result). Elke resultatenrij moet bevatten: periodeboundaries, inputsversie (policyversie + engineversie) en referenties naar de gebruikte event IDs. Dit maakt recomputatie veilig en geeft je een auditspoor wanneer klanten vragen: “Welke outage-minuten hebben jullie meegeteld?”
Je SLA-cijfers zijn alleen zo betrouwbaar als de events die je binnenhaalt. Het doel is simpel: leg elke verandering vast die ertoe doet (een outage gestart, incident acknowledged, service hersteld) met consistente timestamps en genoeg context om later compliance te berekenen.
De meeste teams halen data uit een mix van systemen:
Webhooks zijn meestal het beste voor realtime nauwkeurigheid en lagere load: het bronsysteem pusht events naar jouw endpoint.
Polling is een goede fallback als webhooks niet beschikbaar zijn: je app haalt periodiek wijzigingen op sinds de laatste cursor. Je hebt rate-limit handling en zorgvuldige “since”-logica nodig.
CSV-import helpt bij backfills en migraties. Behandel het als een volwaardige ingestie-route zodat je historische perioden zonder hacks kunt herprocessen.
Normaliseer alles naar één interne “event”-vorm, zelfs als upstream payloads verschillen:
event_id (verplicht): uniek en stabiel bij retries. Geef bij voorkeur het GUID van de bron; anders genereer een deterministische hash.source (verplicht): bijv. datadog, servicenow, manual.event_type (verplicht): bijv. incident_opened, incident_acknowledged, service_down, service_up.occurred_at (verplicht): de tijd waarop het event plaatsvond (niet wanneer je het ontving), met timezone.received_at (systeem): wanneer je app het inging.service_id (verplicht): de SLA-relevante service die het event raakt.incident_id (optioneel maar aanbevolen): koppelt meerdere events aan één incident.attributes (optioneel): priority, regio, klantsegment, enz.Sla event_id op met een unieke constraint om ingestie idempotent te maken: retries creëren geen duplicaten.
Weiger of quarantineer events die:
occurred_at ver in de toekomst liggen.service_id mappen (of eis een expliciete “unmapped” workflow).event_id dupliceren.Deze discipline voorkomt discussies over SLA-rapporten later—want je kunt wijzen op schone, traceerbare inputs.
Je berekeningsengine is waar “ruwe events” SLA-uitkomsten worden die je kunt verdedigen. Het belangrijkste is om het als boekhouding te behandelen: deterministische regels, duidelijke inputs en een replaybaar spoor.
Zet alles om in één geordende stroom per incident (of per service-impact):
Bereken duur vervolgens door intervallen op te tellen, niet door twee timestamps klakkeloos van elkaar af te trekken.
Definieer TTFR als de verstreken “chargeable” tijd tussen incident_start en first_agent_response (of acknowledged, afhankelijk van de SLA-tekst). Definieer TTR als de verstreken “chargeable” tijd tussen incident_start en resolved.
“Chargeable” betekent dat je intervallen verwijdert die niet meetellen:
Implementatiedetail: bewaar een kalenderfunctie (werkuren, feestdagen) en een regel-functie die een tijdlijn neemt en chargeable intervallen teruggeeft.
Bepaal vooraf of je berekent:
Voor gedeeltelijke storingen, weeg op impact alleen als je SLA-contract dat vereist; behandel anders “degraded” als een aparte breach-categorie.
Elke berekening moet reproduceerbaar zijn. Persist:
Als regels veranderen, kun je berekeningen opnieuw draaien op basis van versies zonder historie te herschrijven—cruciaal voor audits en klantdisputen.
Rapportage is waar SLA-tracking vertrouwen verdient—of verliest. Je app moet duidelijk maken welk tijdsbereik wordt gemeten, welke minuten meetellen en hoe de eindcijfers zijn afgeleid.
Ondersteun de gangbare rapportageperioden die klanten daadwerkelijk gebruiken:
Bewaar perioden als expliciete start/eind timestamps (niet “maand = 3”) zodat je later berekeningen kunt replayen en resultaten kunt uitleggen.
Een veelvoorkomende verwarring is of de noemer de hele periode is of alleen de “in aanmerking komende” tijd.
Definieer twee waarden per periode:
Bereken dan:
availability_percent = 100 * (eligible_minutes - downtime_minutes) / eligible_minutes
Als eligible minutes nul kan zijn (bijvoorbeeld een service die alleen tijdens werkuren wordt gemonitord en de periode bevat er geen), definieer de regel vooraf: ofwel “N/A” of behandel als 100%—maar wees consistent en documenteer het.
De meeste SLA's hebben zowel een percentage als een binaire uitkomst nodig.
Houd ook de “afstand tot breach” bij (overgebleven downtime-budget) zodat dashboards kunnen waarschuwen voordat de drempel wordt overschreden.
Bewaar tenslotte de ruwe inputs (inbegrepen/uitgesloten events en aanpassingen) zodat elk rapport kan beantwoorden “waarom is dit cijfer wat het is?” zonder vaagheden.
Je berekeningsengine kan perfect zijn en nog steeds falen als de UI de basisvraag niet meteen beantwoordt: “Halen we het SLA nu, en waarom?” Ontwerp de app zo dat elk scherm begint met een duidelijke status en laat mensen vervolgens inzoomen op de cijfers en de ruwe events die ze hebben opgeleverd.
Overview-dashboard (voor operators en managers). Begin met een klein aantal tegels: compliance huidige periode, beschikbaarheid, reactietijd-compliance en “overgebleven tijd voor breach” waar van toepassing. Gebruik expliciete labels (bijv. “Availability (this month)” in plaats van alleen “Uptime”). Als je meerdere SLA's per klant ondersteunt, toon dan eerst de slechtst presterende en laat gebruikers uitklappen.
Klantdetail (voor accountteams en klantgerichte rapportage). Een klantpagina moet alle services en SLA-tiers voor die klant samenvatten, met een eenvoudige pass/warn/fail status en een korte uitleg (“2 incidenten meegeteld; 18m downtime meegeteld”). Voeg verwijzingen toe naar /status (als je een klantgerichte statuspagina aanbiedt) en naar een export van het rapport.
Servicedetail (voor diepgaand onderzoek). Hier toon je de exacte SLA-regels, het berekeningsvenster en een uitsplitsing van hoe het compliance-cijfer is gevormd. Voeg een grafiek van beschikbaarheid in de tijd toe en een lijst met incidenten die meetelden voor de SLA.
Incidenttijdlijn (voor audits). Een enkele incidentweergave moet een tijdlijn van events tonen (gedetecteerd, acknowledged, gemitigeerd, opgelost) en welke timestamps zijn gebruikt voor “response” en “resolution” metrics.
Maak filters consistent over schermen: datumrange, klant, service, tier en severity. Gebruik overal dezelfde eenheden (minuten vs seconden; percentages met hetzelfde aantal decimalen). Als gebruikers de datumrange wijzigen, update dan elke metric op de pagina zodat er geen mismatch is.
Elke samenvattende metric moet een “Waarom?”-pad hebben:
Gebruik tooltips spaarzaam om termen te definiëren zoals “Excluded downtime” of “Business hours”, en toon de exacte regeltekst op de servicepagina zodat mensen niet hoeven te raden.
Geef de voorkeur aan gewone taal boven afkortingen (“Reactietijd” in plaats van “MTTA” tenzij je publiek die afkorting verwacht). Combineer statuskleur met tekstlabels (“At risk: 92% van het error budget gebruikt”) om ambiguïteit te voorkomen. Als je app auditlogs ondersteunt, voeg dan een klein “Laatst gewijzigd” vakje op SLA-regels toe met verwijzing naar /audit zodat gebruikers kunnen verifiëren wanneer definities zijn aangepast.
Alerting is waar je SLA-tracking webapp stopt met passieve rapportage en teams helpt boetes te voorkomen. De beste alerts zijn tijdig, specifiek en actiegericht—ze vertellen iemand wat de volgende stap is, niet alleen dat iets “slecht” is.
Begin met drie triggertypes:
Maak triggers configureerbaar per klant/service/SLA, omdat verschillende contracten verschillende tolerantie hebben.
Stuur alerts naar plekken waar mensen daadwerkelijk reageren:
Elke alert moet deep links bevatten zoals /alerts, /customers/{id}, /services/{id} en de incident- of eventdetailpagina zodat responders de cijfers snel kunnen verifiëren.
Implementeer deduplicatie door alerts te groeperen met dezelfde sleutel (customer + service + SLA + period) en herhalingen te onderdrukken voor een cooldown-window.
Voeg quiet hours toe (per teamtijdzone) zodat niet-kritieke “approaching breach” alerts wachten tot werkuren, terwijl “breach occurred” stille uren kan overschrijven als de severity hoog is.
Ondersteun ten slotte escalatieregels (bijv. notify on-call na 10 minuten, escalate naar manager na 30) om te voorkomen dat alerts in één inbox blijven hangen.
SLA-data is gevoelig omdat het interne prestaties en klantspecifieke rechten kan blootleggen. Behandel toegangscontrole als onderdeel van de SLA-“wiskunde”: hetzelfde incident kan verschillende compliance-resultaten opleveren afhankelijk van welke klant-SLA wordt toegepast.
Houd rollen simpel en breid later uit naar fijnmazigere permissies.
Een praktisch default is RBAC + tenant scoping:
Wees expliciet over klant-specifieke data:
Begin met e-mail/wachtwoord en eis MFA voor interne rollen. Plan SSO later (SAML/OIDC) door identiteit (wie ze zijn) te scheiden van autorisatie (wat ze mogen). Voor integraties geef je API-keys uit gekoppeld aan een service-account met beperkte scopes en rotatiemogelijkheid.
Voeg immuteerbare auditentries toe voor:
Bewaar wie, wat er veranderde (voor/na), wanneer, waar (IP/user agent) en een correlatie-ID. Maak auditlogs doorzoekbaar en exporteerbaar (bijv. /settings/audit-log).
Een SLA-tracking app is zelden een eiland. Je wilt een API waarmee monitoringtools, ticketingsystemen en interne workflows incidenten kunnen aanmaken, events pushen en rapporten ophalen zonder handwerk.
Gebruik een versioned base path (bijv. /api/v1/...) zodat je payloads kunt evolueren zonder bestaande integraties te breken.
Essentiële endpoints die de meeste use cases dekken:
POST /api/v1/events om state-changes te ingesteren. GET /api/v1/events voor audits en debugging.POST /api/v1/incidents, PATCH /api/v1/incidents/{id} (acknowledge, resolve, assign), GET /api/v1/incidents.GET /api/v1/slas, POST /api/v1/slas, PUT /api/v1/slas/{id} om contracten en thresholds te beheren.GET /api/v1/reports/sla?service_id=...&from=...&to=... voor compliance-samenvattingen.POST /api/v1/alerts/subscriptions om webhooks/e-mailtargets te beheren; GET /api/v1/alerts voor alert-historie.Kies één conventie en gebruik die overal. Bijvoorbeeld: limit, cursor-paginering, plus standaardfilters zoals service_id, sla_id, status, from en to. Houd sortering voorspelbaar (bijv. sort=-created_at).
Retourneer gestructureerde fouten met stabiele velden:
{ "error": { "code": "VALIDATION_ERROR", "message": "service_id is required", "fields": { "service_id": "missing" } } }
Gebruik duidelijke HTTP-statussen (400 validatie, 401/403 auth, 404 not found, 409 conflict, 429 rate limit). Voor event-ingestie, overweeg idempotentie (Idempotency-Key) zodat retries geen duplicaten creëren.
Pas redelijke rate limits per token toe (en strengere limieten voor ingestie-endpoints), sanitize inputs en valideer timestamps/tijdzones. Geef de voorkeur aan beperkte API-tokens (read-only rapportage vs write-access voor incidents) en log altijd wie welk endpoint aanroept voor traceerbaarheid (details in je auditlog-sectie).
SLA-cijfers zijn alleen nuttig als mensen ze vertrouwen. Testen van een SLA-tracking webapp moet minder gericht zijn op “laadt de pagina” en meer op “gedraagt tijd-wiskunde zich precies zoals het contract zegt.” Behandel je berekeningsregels als een productfeature met een eigen testsuite.
Begin met unit-tests voor je SLA-berekeningsengine met deterministische inputs: een tijdlijn van events (incident geopend, acknowledged, gemitigeerd, opgelost) en een duidelijk gedefinieerde SLA-regelset.
Gebruik vaste timestamps en “freeze time” zodat je tests nooit afhankelijk zijn van de klok. Dek randgevallen die vaak SLA-rapportage breken:
Voeg een klein aantal end-to-end tests toe die de volledige flow doorlopen: ingest events → bereken compliance → genereer rapport → render UI. Deze vangen mismatches tussen “wat de engine berekende” en “wat het dashboard toont.” Houd de scenario's beperkt maar van hoge waarde, en asserteer op eindcijfers (availability %, breach ja/nee, tijd-naar-ack).
Maak testfixtures voor werkuren, feestdagen en tijdzones. Je wilt reproduceerbare gevallen zoals “incident gebeurt vrijdag 17:55 lokale tijd” en “een feestdag verschuift reactietijd-telling.”
Testen stopt niet bij deploy. Voeg monitoring toe voor job-fouten, queue/backlog-grootte, herberekeningsduur en foutpercentages. Als ingestie achterloopt of een nightly job faalt, kan je SLA-rapport fout zijn, ook als de code correct is.
Het uitrollen van een SLA-tracking app draait minder om fancy infra en meer om voorspelbare operatie: je berekeningen moeten op tijd draaien, je data moet veilig zijn en rapporten reproduceerbaar.
Begin met managed services zodat je je op correctheid kunt concentreren.
Houd omgevingen minimaal: dev → staging → prod, elk met eigen database en secrets.
SLA-tracking is niet puur request/response; het hangt af van geplande taken.
Draai jobs via een workerproces + queue, of een managed scheduler die interne endpoints aanroept. Maak jobs idempotent (veilig om te herhalen) en log elke run voor auditability.
Definieer retentie per datatype: bewaak afgeleide compliance-resultaten langer dan raw eventstreams. Voor exports: bied eerst CSV aan (snel, transparant), later PDF-templates. Wees duidelijk: exports zijn “best-effort formatting”, terwijl de database de bron van waarheid blijft.
Als je je datamodel, ingestieflow en rapportage-UI snel wilt valideren, kan een vibe-coding platform zoals Koder.ai je helpen om snel naar een werkend end-to-end prototype te gaan zonder je direct op een volledig engineeringtraject vast te leggen. Omdat Koder.ai volledige applicaties genereert via chat (web UI plus backend), is het een praktische manier om op te zetten:
Zodra de requirements en berekeningen bewezen zijn (het moeilijke deel), kun je itereren, de broncode exporteren en overgaan naar een traditioneel build-and-operate-traject—terwijl functies zoals snapshots en rollback beschikbaar blijven tijdens snelle iteratie.
Een SLA-tracker beantwoordt één vraag met bewijs: heb je de contractuele verplichtingen voor een specifieke klant en periode gehaald?
In de praktijk betekent het het binnenhalen van ruwe signalen (monitoring, tickets, handmatige updates), het toepassen van de regels van de klant (werkuren, uitsluitingen) en het produceren van een auditvriendelijke pass/fail met ondersteunende details.
Gebruik:
Modelleer ze apart zodat je betrouwbaarheid (SLO) kunt verbeteren zonder per ongeluk de contractuele rapportage (SLA) te wijzigen.
Een sterk MVP volgt meestal 1–3 metrics end-to-end:
Deze mappen goed naar echte databronnen en dwingen je om vroege implementatie van lastige onderdelen (perioden, kalenders, uitsluitingen) te doen.
Fouten in requirements ontstaan vaak door onduidelijke regels. Verzamel en noteer:
Als een regel niet helder uit te drukken is, probeer het dan niet in code te ‘infereren’—flag het en vraag om opheldering.
Begin met saaie, expliciete entiteiten:
Streef naar traceerbaarheid: elk gerapporteerd getal moet linken naar en .
Sla tijd correct en consistent op:
occurred_at in UTC met timezone-semantiekreceived_at (wanneer je het binnenkreeg)Maak perioden expliciet (start/eind timestamps) zodat je rapporten later kunt reproduceren—ook over DST-wisselingen heen.
Normaliseer alles naar één interne event-vorm met een stabiele unieke ID:
event_id (uniek, stabiel bij retries)source, event_type, , Bereken duur door intervals op te tellen op een tijdlijn, niet simpelweg twee timestamps van elkaar af te trekken.
Definieer “chargeable time” expliciet door intervallen te verwijderen die niet meetellen, zoals:
Bewaar de afgeleide intervallen en redencodes zodat je precies kunt uitleggen wat er is meegeteld.
Houd twee noemers expliciet bij:
Bereken dan:
availability_percent = 100 * (eligible_minutes - downtime_minutes) / eligible_minutes
Bepaal ook wat er gebeurt als eligible minutes nul is (bijv. toon ). Documenteer die regel en pas hem consequent toe.
Laat de UI in één oogopslag antwoord geven op “halen we het SLA, en waarom?”:
Voor alerts: prioriteer actiegerichte triggers: approaching breach, breach occurred en repeated violations—elk met links naar relevante pagina's zoals /customers/{id} of .
occurred_atservice_idincident_id en attributesHanteer idempotentie met een unieke constraint op event_id. Voor ontbrekende mappings of out-of-order aankomsten: quarantine/flag ze—verander de data niet stilletjes.
/services/{id}