Koppel events (UUIDs, triggers, payloads)

Feiten over de events die de Koppel-feature aanmaakt via eventService. Bedoeld voor beheerders die per event-type een mailtemplate en recipients willen configureren in de admin UI.

Bron-definities: apps/api/src/api/koppel/koppelEventTypes.ts. Alle dispatch-sites zitten in pluginLicenseService.ts.

Auto-registratie

eventService.create() registreert een event-type automatisch bij de eerste fire (UUID is leidend). Er is geen seed of migratie nodig. Na deploy kan een beheerder direct een notificatie (mailtemplate, recipients) koppelen aan elk van onderstaande event-types.

Events per flow

# Flow Event-naam UUID Dispatch
1 Landing Koppel registratie aangevraagd e7b2f1a4-7c1b-4ba4-9e0a-9c1d5a8f2a10 pluginLicenseService.ts:172
2 Landing Koppel registratie duplicaat 2f4c9a6b-0e9d-4a7c-bf7c-6d1e3a9f0b22 pluginLicenseService.ts:136
3 Plugin Koppel plugin eerste activatie 5a3e8d72-1b4f-4c9e-8a07-2d6f9b1c4e83 pluginLicenseService.ts:329
4 Plugin Koppel plugin extra activatie 8b1c4f2a-9d6e-4732-a015-7e8b3c5d2f49 pluginLicenseService.ts:347
5 Plugin Koppel licentie nadert maximum activaties a2e8f4b7-5c91-4d36-b08e-9f2a6d1c3b75 pluginLicenseService.ts:368
6 Plugin / admin Koppel licentie verlopen c4f9e6d1-3a82-4b07-9e5a-1d8c2f6b9a04 pluginLicenseService.ts:235 (via markLicenseExpired)
7 Admin Koppel licentie ingetrokken d7a3b9c5-6e02-4f81-a4d6-3b8c1e9f7d62 pluginLicenseService.ts:513
8 Job (dagelijks) Koppel activatie gedeactiveerd wegens inactiviteit 4d508036-7d1a-4aac-a1f9-8e46cae37253 pluginLicenseService.ts (via deactivateInactiveActivations)

1. Koppel registratie aangevraagd

Trigger: eerste aanvraag op een nieuw e-maildomein via het Koppel-landingsformulier (POST /public/koppel/register). Een activatiecode wordt gemaild.

Veld Type Bron
email string input.email (formulier)
name string input.name (formulier)
organization string input.organization (formulier)
activationKey string (UUID) net-gegenereerd via randomUUID()
expiresAt string (ISO-8601) now + TRIAL_DURATION_DAYS

2. Koppel registratie duplicaat

Trigger: tweede aanvraag op een e-maildomein dat al een pending of active Koppel-licentie heeft. Er wordt géén nieuwe activatiecode verstuurd; auto-enrollment geldt vanaf de tweede activatie.

Veld Type Bron
email string input.email (nieuwe aanvrager)
name string input.name (nieuwe aanvrager)
organization string input.organization (nieuwe aanvrager)
domain string lowercased deel na @ van input.email
existingLicenseId string id van de al bestaande licentie
primaryApplicantEmail string existing.email (originele aanvrager)
primaryApplicantName string existing.name (originele aanvrager)

3. Koppel plugin eerste activatie

Trigger: een activatiecode wordt voor het eerst gebruikt via POST /public/koppel-plugin/activate. Status gaat van pending naar active, gekoppeld aan een Microsoft- en Exact Online-tenant.

Veld Type Bron
name string license.name (uit registratie)
email string input.email (daadwerkelijke activeerder uit de plugin)
applicantEmail string license.email (kan in zeldzame gevallen afwijken van email)
organization string license.organization
activationKey string license.activationKey
microsoftTenantId string input.microsoftTenantId (binding gezet bij deze activatie)
exactOnlineTenantId string input.exactOnlineTenantId

4. Koppel plugin extra activatie

Trigger: een extra gebruiker activeert de plugin binnen een al actieve organisatie-licentie (auto-enrollment).

Veld Type Bron
email string input.email (auto-enrollment-gebruiker)
organization string license.organization
activationKey string license.activationKey
microsoftTenantId string input.microsoftTenantId (gevalideerd tegen license)
exactOnlineTenantId string input.exactOnlineTenantId (gevalideerd tegen license)
activationsUsed number nieuwe count, inclusief deze activatie

Geen name-veld: bij auto-enrollment is alleen het e-mailadres van de extra gebruiker bekend.

5. Koppel licentie nadert maximum activaties

Trigger: de active count passeert eenmalig de drempel NEAR_MAX_ACTIVATIONS_THRESHOLD (80 van 100). Trial-licenties tellen niet mee. De strikte ongelijkheid voorkomt herhaling bij elke vervolg-activatie boven de drempel.

Veld Type Bron
licenseId string license.id
name string license.name (aanvrager)
email string license.email (aanvrager, niet de activeerder)
organization string license.organization
activationKey string license.activationKey
activationsUsed number nieuwe count die de drempel passeert
threshold number constante NEAR_MAX_ACTIVATIONS_THRESHOLD (80)
max number constante MAX_ACTIVATIONS (100)

6. Koppel licentie verlopen

Trigger: een licentie wordt als verlopen gemarkeerd. Gebeurt:

  • Automatisch bij activate, validate of checkAccess voorbij expiresAt.
  • Handmatig door een beheerder via PUT /admin/koppel/licenses/:id met status: 'expired'.

Beide paden hergebruiken de helper markLicenseExpired op regel 232, dus de payload is identiek.

Veld Type Bron
licenseId string license.id
name string license.name
email string license.email
organization string license.organization
activationKey string license.activationKey
expiresAt string (ISO-8601) license.expiresAt.toISOString()
activationsUsed number count op moment van verlopen

7. Koppel licentie ingetrokken

Trigger: een beheerder zet de status van een licentie op revoked via PUT /admin/koppel/licenses/:id. Een no-op patch (status ongewijzigd) triggert geen event.

Veld Type Bron
licenseId string existing.id
name string existing.name
email string existing.email
organization string existing.organization
activationKey string existing.activationKey
previousStatus string status voor de update (pending, active of expired)
activationsUsed number count op moment van revoke

8. Koppel activatie gedeactiveerd wegens inactiviteit

Trigger: de dagelijkse job DEACTIVATE_INACTIVE_KOPPEL_ACTIVATIONS (02:15) zet een activatie op inactief (deactivatedAt) zodra die langer dan INACTIVITY_PERIOD_MONTHS (3) niet gebruikt is, mits de licentie active is (geen trial/expired/revoked). Soft-deactivatie is omkeerbaar: hernieuwd gebruik (touchLastActiveAt) wist deactivatedAt. De notificatie is bedoeld voor de organisatie-beheerder, zodat die de medewerker kan laten heractiveren.

Veld Type Bron
licenseId string license.id
organization string license.organization
orgAdminName string license.name (de licentie-aanvrager/eerste gebruiker)
orgAdminEmail string license.email (bedoelde ontvanger van de melding)
deactivatedEmail string activation.email (de medewerker wiens activatie is gedeactiveerd)
activationKey string license.activationKey
lastActiveAt string (ISO-8601) laatste gebruik vóór deactivatie
deactivatedAt string (ISO-8601) moment van deactivatie

Dispatch-mechanisme

Alle koppel-events lopen door één privé-helper: pluginLicenseService.dispatchKoppelEvent (regel 198).

Aspect Gedrag
Aanroep eventService.create(eventType, null, null, [], { data }) (geen user, geen source-doc, geen targets)
Foutbeleid Niet-blokkerend. Errors worden gelogd via loggerService.error, niet doorgegooid. Een falende notificatie blokkeert nooit de onderliggende actie (registratie of activatie).
Tenant-context Publieke Koppel-endpoints draaien zonder tenant-middleware. De helper laadt de Koppel-tenant uit env.KOPPEL_TENANT_UUID en opent een AsyncLocalStorage-scope, zodat de event- en notification-pipeline op de juiste admin-connectie schrijven.
Metric koppelEventCounter (tapster_koppel_event_total) wordt per fire opgehoogd met label event: <name>. Zie apps/api/src/monitoring/koppel-metrics.ts.

Event-initiator (User)

Sinds 2026-05 heeft elk koppel-event een User-initiator (event.user). Bij KOPPEL_REGISTRATION_REQUESTED en KOPPEL_REGISTRATION_DUPLICATE is dit de aanvrager (een NOT_ACTIVATED user, automatisch aangemaakt in de KOPPEL_TENANT). Bij KOPPEL_PLUGIN_ACTIVATED_FIRST en _ADDITIONAL is dit de geactiveerde plugin-gebruiker. Bij KOPPEL_LICENSE_EXPIRED, KOPPEL_LICENSE_NEAR_MAX_ACTIVATIONS en KOPPEL_LICENSE_REVOKED is dit de license-eigenaar.

Notificaties naar de initiator

Configureer een NotificationType met recipient-role 'OWNER' om de initiator (event.user) te bereiken. Let op: de 'SOURCE'-role is herkend maar niet geïmplementeerd in getRecipientsHelper.ts, dus gebruik altijd 'OWNER'.

Levenscyclus van koppel-users

  • Aangemaakt bij registratie of activatie (state NOT_ACTIVATED, role default).
  • Bij license-revoke of activation-delete: state wordt TO_BE_REMOVED, behalve als de user nog andere actieve activations heeft. Na 14 dagen anonimiseert de bestaande anonimiseer-gebruikers-job ze permanent.
  • Bij license-expired: een dagelijkse job (MARK_EXPIRED_KOPPEL_USERS) markeert users als TO_BE_REMOVED zodra expiresAt + 30 dagen grace verstreken is. Daarna volgt de bestaande 14-dagen anonimisering, dus totaal 44 dagen tussen expiry en permanent verwijderen.

Configuratie en gedrag

Aspect Status
Feature flags op event creation Geen. Alle 8 events vuren altijd zodra de trigger geldt.
Per-tenant toggles Geen. Koppel-events horen bij de Koppel-tenant.
Per event-type configureerbaar Ja, via admin UI: mailtemplate (UUID), recipients (rollen), digest-flag.
Idempotency Notificaties worden gededupliceerd via idempotency-key in taskService.
Rate-limit Notificaties: 120/minuut per tenant. Event-creation zelf is niet gethrottled.

Constanten

Gedefinieerd in apps/api/src/api/koppel/pluginLicenseModel.ts:

Constante Waarde Gebruikt door
TRIAL_DURATION_DAYS 14 expiresAt bij events 1 en 6
MAX_ACTIVATIONS 100 max in event 5
NEAR_MAX_ACTIVATIONS_THRESHOLD 80 threshold in event 5
INACTIVITY_PERIOD_MONTHS 3 inactiviteitsgrens voor event 8 (in pluginLicenseActivationRepository.ts)

Velden die in templates beschikbaar zijn

Let op bij het schrijven van mailtemplates:

  • activationKey zit in alle 7 events.
  • licenseId zit in events 3 niet, en in 1, 2, 4 niet (alleen 5, 6, 7).
  • name zit in events 4 (auto-enrollment) niet.
  • email zit in alle 7 events, maar de betekenis verschilt:
    • Events 1, 2, 5, 6, 7: email is de aanvrager.
    • Event 3: email is de activeerder; applicantEmail is de aanvrager.
    • Event 4: email is de auto-enrollment-gebruiker, er is geen aanvrager-veld.

Bron-bestanden

  • Event-type definities: apps/api/src/api/koppel/koppelEventTypes.ts
  • Dispatch en triggers: apps/api/src/api/koppel/pluginLicenseService.ts
  • Routers: apps/api/src/api/koppel/{koppelPublicRouter,koppelPluginRouter,koppelAdminRouter}.ts
  • EventService: apps/api/src/api/event/eventService.ts
  • Metric: apps/api/src/monitoring/koppel-metrics.ts
  • Constanten: apps/api/src/api/koppel/pluginLicenseModel.ts