Skip to content

unified webhook event envelope + after lifecycle hooks#245

Merged
Polliog merged 10 commits into
developfrom
feat/webhook-envelope
Jun 11, 2026
Merged

unified webhook event envelope + after lifecycle hooks#245
Polliog merged 10 commits into
developfrom
feat/webhook-envelope

Conversation

@Polliog

@Polliog Polliog commented Jun 11, 2026

Copy link
Copy Markdown
Collaborator

What this does

Unifies every outbound webhook payload into one typed event envelope (#218 follow-up) and adds the missing after-* lifecycle hook phases (#216 follow-up).

BREAKING: unified webhook event envelope

Every dispatcher delivery now serializes to:

{
  "id": "evt_<uuid>",
  "type": "alert.triggered",
  "version": 1,
  "occurredAt": "<ISO8601>",
  "organizationId": "<uuid>",
  "projectId": "<uuid or null>",
  "data": { }
}
  • Event types: alert.triggered (anomalies distinguished by data.baseline_metadata), incident.created, error.detected, monitor.status_changed, channel.notification (generic channel deliveries), channel.test.
  • Per-type data keeps the previous snake_case fields minus event_type/timestamp (now type/occurredAt on the envelope).
  • Envelope + per-type data Zod schemas ship in @logtide/shared (webhookEnvelopeSchema, parseWebhookEvent); producers are schema-locked in tests.
  • New X-Logtide-Event-Version: 1 header; HMAC signing unchanged, covering the serialized envelope; beforeWebhookDispatch still mutates pre-serialization so hook changes are signed.
  • The envelope id doubles as the dedup eventId when callers do not pass one; all existing producers keep their explicit eventIds.
  • Channel test deliveries now carry the channel's real organization id end to end.
  • Replayed pre-envelope deliveries re-send their stored payload (documented).

after-* lifecycle hook phases

afterIngest (batch counts + rejection reasons, no log content; fires on every completed batch including all-rejected and hook-filtered paths), afterAlertTriggered (post-persist trigger facts, threshold and rate-of-change), afterWebhookDispatch (per delivery attempt result, queued and sync paths, fired inside deliverOnce).

Semantics: fire-and-forget (handler errors logged, never block), frozen read-only contexts, hasHandlers guards keep the no-handler hot path at zero overhead, registration via HOOKS_MODULES identical to before-* phases. run() is now type-restricted to before-phases; after-phases go through runAfter().

Docs

docs/webhooks.md gains the envelope reference and event catalog; docs/lifecycle-hooks.md documents the three new phases.

Tests

59 shared schema tests (round-trips and rejections for all types), envelope/dispatcher/producer assertions schema-locked via parseWebhookEvent, 14 new after-hook tests plus call-site integration tests. Full backend suite green.

@codecov

codecov Bot commented Jun 11, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 94.27083% with 11 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
packages/backend/src/modules/alerts/service.ts 50.00% 11 Missing ⚠️

📢 Thoughts on this report? Let us know!

@Polliog Polliog merged commit 191bacb into develop Jun 11, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant