Systeem-mailboxen (API en datamodel)

Feiten over de systeem-mailbox-registry: collection, velden, endpoints, scripts, environment.

Voor begrip: zie de explanation. Voor stappen: zie de how-to.

Datamodel

Collection: systemmailboxes op de admin-connectie (mongooseConnectionManager.adminConnection). Niet tenant-gescopt.

Index: unieke index op key.

Velden (zie apps/api/src/api/system-mailbox/SystemMailbox.interface.ts):

Veld Type Default Toelichting
key string (verplicht) Unieke sleutel, bv. 'monitor'
displayName string '' Afzender-naam in From header
azureTenantId string '' Azure AD tenant-id van de mailbox
mailboxAddress string '' E-mailadres, fungeert als from
saveToSentItems boolean false Of Graph een kopie in Verzonden plaatst
rateLimitPerMinute number leeg Override op default 25 calls/min, zie mail rate limit
rateLimitRecipientsPerDay number leeg Override op default 9000 ontvangers/dag, zie mail rate limit
consentStatus.granted boolean false Admin-consent voltooid
consentStatus.lastConsentAt date optioneel Tijdstip laatste succesvolle consent
consentStatus.lastConsentBy string optioneel User-uuid of e-mail van consent-verlener
consentStatus.lastErrorAt date optioneel Tijdstip laatste mailfout
consentStatus.lastErrorMessage string optioneel Foutboodschap bij laatste mailfout

Bekende keys:

Key Doel
monitor Alle monitor-campagne-mails (uitnodiging, 1e en 2e reminder, rapportages)

Velden op andere modellen

MessageTemplate.systemMailboxKey?: string: als gezet, erven nieuwe Messages deze key.

Message.systemMailboxKey?: string: bepaalt of de Message via systeem- of tenant-mailbox gaat. Expliciete waarde overschrijft template-waarde tijdens messageService.create.

Beide additief, default leeg, backward-compatible.

Admin-API

Mount: apps/api/src/api/protectedEndpointRouter.ts, prefix /admin/system-mailboxes. Auth: authenticationService.validateBearerAuth (admin-token).

Method Path Body Response
GET /admin/system-mailboxes - Array van bekende records (vandaag alleen monitor)
GET /admin/system-mailboxes/:key - Record of 404 { message: 'Niet gevonden' }
PUT /admin/system-mailboxes/:key { displayName, azureTenantId, mailboxAddress, saveToSentItems, rateLimitPerMinute?, rateLimitRecipientsPerDay? } Bijgewerkt record, of 400 { errors: [...] }
GET /admin/system-mailboxes/:key/consent-url - { consentUrl, redirectUri } of 400 als AZURE_CLIENT_ID ontbreekt
POST /admin/system-mailboxes/:key/test { to: string } { ok: true, messageId? } of { ok: false, error }

Validatie op PUT:

  • displayName: niet-lege string
  • azureTenantId: niet-lege string
  • mailboxAddress: regex ^[^@\s]+@[^@\s]+\.[^@\s]+$
  • rateLimitPerMinute (optioneel): positief geheel getal
  • rateLimitRecipientsPerDay (optioneel): positief geheel getal

Validatie op POST /test:

  • to: zelfde e-mail-regex. Bij ongeldig: 400 { message: 'Geldig to adres vereist' }.

Mount: apps/api/src/api/publicEndpointRouter.ts, geen auth (Microsoft redirect).

Method Path Query
GET /system/mailboxes/azure/callback admin_consent, tenant, state, error?, error_description?

State-formaat: JSON string { "systemMailboxKey": "<key>" }.

Gedrag:

  • error aanwezig → 400, response geeft de Microsoft-foutmelding terug.
  • admin_consent !== 'true'400, “Admin consent niet verleend”.
  • State niet parseerbaar of zonder systemMailboxKey400.
  • Onbekende key400, “Onbekende system-mailbox”.
  • Tenant uit callback wijkt af van opgeslagen azureTenantId → record wordt bijgewerkt naar de Microsoft-waarde.
  • Succes → consentStatus.granted = true, lastConsentAt = now, factory-cache geïnvalideerd.

Mailer-routing

apps/api/src/common/services/mail-provider-service/MailProviderService.ts:

const mailer = message.systemMailboxKey
  ? await mailerFactory.getMailerForSystemMailbox(message.systemMailboxKey)
  : await mailerFactory.getMailer();

mailerFactory.getMailerForSystemMailbox(key) (zie MailerFactory.ts):

  • Cache-key: key. Aparte cache (systemCache) naast tenant-cache.
  • Throwt Error('System mailbox "X" is not configured') als record ontbreekt of azureTenantId of mailboxAddress leeg is.
  • Throwt Error('System mailbox "X" consent not granted') als consentStatus.granted !== true.
  • Bij succes: MicrosoftGraphMailer({ tenantId, fromEmail, fromDisplayName, saveToSentItems }), gewrapt met RateLimitedGraphMailer (zie mail rate limit).
  • Cache-hash bevat ook rateLimitPerMinute en rateLimitRecipientsPerDay, dus een wijziging via de admin-UI invalideert de cache zonder pod-restart.

mailerFactory.invalidateSystemMailbox(key?) leegt cache voor één key, of alle systeem-cache als key leeg is.

Foutlogging op het record

MailProviderService.send catch-pad (alleen als systemMailboxKey op de message stond):

  • Foutboodschap matcht \b(401|403)\bsystemMailboxService.logAuthFailure(key, msg). Dit zet granted: false, plus lastErrorAt/Message.
  • Anders → systemMailboxService.logError(key, msg). Alleen lastErrorAt/Message.

Original error bubble-t door zodat messageService.send de message-status op ERROR zet.

Scripts

Seed: apps/api/scripts/seed-system-mailbox-monitor/script.ts

npm run seed:system-mailbox-monitor -w apps/api

Idempotent. Maakt het record monitor aan met lege configuratie, of laat het bestaande record ongemoeid.

Templates taggen: apps/api/scripts/tag-monitor-templates/script.ts

npm run tag:monitor-templates -w apps/api

Itereert alle tenants. Per tenant: verzamelt template-uuids uit ParticipationMonitorCampaign.messageTemplate, messageTemplateFirstReminder en messageTemplateSecondReminder. Update via MessageTemplate.updateMany alleen templates zonder bestaande systemMailboxKey. Idempotent. Geeft per tenant { uniqueTemplateUuids, modified, skipped } terug.

Environment

Variabele Doel
AZURE_CLIENT_ID App-registratie voor admin-consent. Verplicht voor GET /:key/consent-url. Gedeeld met tenant-flow.
AZURE_CLIENT_SECRET App-secret voor app-only token-acquisitie via MicrosoftGraphTokenProvider.

Beide bestaan al voor de tenant-flow, geen nieuwe variabelen geïntroduceerd.

Frontend

Feature: apps/frontend/src/app/features/admin/mailboxes/.

Route: /admin/systeem-mailboxen (list) en /admin/systeem-mailboxen/:key (detail). Geregistreerd in admin.routes.ts onder path: 'systeem-mailboxen'. Sidebar-menu in tapster-sidebar.component.ts. Beschermd door adminGuard op de parent-route.

HTTP-client: SystemMailboxService in data-access/system-mailbox.service.ts. Base-URL: ${apiV7Url}/admin/system-mailboxes.

Bron-bestanden

  • Backend module: apps/api/src/api/system-mailbox/
  • Mailer-routing: apps/api/src/common/services/mail-provider-service/{MailerFactory.ts,MailProviderService.ts}
  • Message-velden: apps/api/src/api/message/messageModel.ts, apps/api/src/api/message-template/messageTemplateModel.ts
  • Message-erving: apps/api/src/api/message/messageService.ts (zoek op systemMailboxKey)
  • Public callback: apps/api/src/api/publicEndpointRouter.ts (/system/mailboxes/azure/callback)
  • Frontend: apps/frontend/src/app/features/admin/mailboxes/