Mailglass.Webhook.WebhookEvent (Mailglass v1.0.0)

Copy Markdown View Source

Ecto schema for the mailglass_webhook_events table (V02 migration, Plan 04-01). Mutable + prunable — UNLIKE mailglass_events which is append-only via the SQLSTATE 45A01 trigger (CONTEXT D-15 split).

Stores raw webhook payloads from Postmark + SendGrid for:

  • Idempotency: UNIQUE (provider, provider_event_id) defends against replay (D-15 + PITFALLS MAIL-03). Plan 04-06's Mailglass.Webhook.Ingest.ingest_multi/3 inserts with on_conflict: :nothing, conflict_target: [:provider, :provider_event_id] — a replay is a no-op SELECT-by-index, not an INSERT.
  • Audit: full raw payload available for support / debugging.
  • GDPR erasure: targeted DELETE FROM mailglass_webhook_events WHERE raw_payload->>'to' = ? without touching the append-only ledger (D-15).

The :raw_payload field is marked redact: true so Inspect output (test failures, IEx) does NOT leak PII bytes. Mirrors accrue's webhook_event.ex:48 convention.

Status state machine

:received → :processing → :succeeded | :failed → :dead. Plan 04-06 inserts at :processing and flips to :succeeded at the end of the Multi; failures (outside Plan 04-06 scope) will surface the Plan 08 DLQ.

Summary

Functions

Closed set of valid :status atoms. Cross-checked in api_stability.md.

Builds a changeset for inserting a webhook_event row at ingest time.

Functions

__statuses__()

(since 0.1.0)

Closed set of valid :status atoms. Cross-checked in api_stability.md.

changeset(attrs)

(since 0.1.0)
@spec changeset(map()) :: Ecto.Changeset.t()

Builds a changeset for inserting a webhook_event row at ingest time.

Caller passes :provider, :provider_event_id, :event_type_raw, :tenant_id, :raw_payload. Other fields default sensibly:

  • :status defaults to :processing (Plan 04-06 flips to :succeeded after the Multi commits)
  • :received_at defaults to Mailglass.Clock.utc_now/0