# OpenSpec Change: enterprise-delivery-tracking - **Change ID**: enterprise-delivery-tracking - **Package**: `@suaveplan/delivery-tracking` - **Category**: universal - **Target path**: `universal/email/delivery-tracking` - **Status**: IN PROGRESS - **Date**: 2026-04-24 - **Reference spec**: `/mnt/s/web/suaveplan/enterprise/delivery-tracking.md` --- ## Summary Deliver `@suaveplan/delivery-tracking` on the genesis branch from scratch at enterprise quality. The package provides channel-agnostic delivery event tracking: a typed `DeliveryEvent` model covering all SMTP/webhook status transitions (`queued`, `sent`, `delivered`, `bounced`, `complained`, `unsubscribed`, `opened`, `clicked`), a `DeliveryTracker` facade with pluggable store adapters, webhook payload normalization for major ESP providers (generic interface — no provider SDK deps), bounce classification (hard/soft/transient), unsubscribe propagation to `@suaveplan/suppression`, and per-campaign/per-recipient analytics aggregation. Genesis adds structured errors, Zod schemas, OTel instrumentation, and property-based tests. --- ## Current-state audit (genesis) The package does not exist on genesis yet — this is a fresh build. --- ## Available workspace deps on genesis | Package | Role | |---|---| | `@suaveplan/error` (`workspace:^`) | `DeliveryTrackingError`; `DLVR.*` error codes | | `@suaveplan/types` (`workspace:^`) | `LoggerLike`, `Clock`, `EventBusLike`, `StorageLike` | | `@suaveplan/events` (`workspace:^`) | Delivery event propagation | | `@suaveplan/suppression` (`workspace:^`) | Unsubscribe/bounce → suppression list write | | `@suaveplan/crypto` (`workspace:^`) | HMAC-SHA256 webhook signature verification | | `zod` (`catalog:forms`) | Schema validation | | `@opentelemetry/api` (`catalog:observability`) | Spans + counters | Dev deps: `vitest`, `@vitest/coverage-istanbul`, `fast-check` (all `catalog:testing`). --- ## Public API surface ### Core types ```ts type DeliveryEventType = | 'queued' | 'sent' | 'delivered' | 'deferred' | 'bounced' | 'complained' | 'unsubscribed' | 'opened' | 'clicked' type BounceType = 'hard' | 'soft' | 'transient' interface DeliveryEvent { id: string messageId: string campaignId?: string recipientEmail: string type: DeliveryEventType timestamp: Date bounceType?: BounceType bounceCode?: string clickUrl?: string userAgent?: string ipAddress?: string metadata: Record } interface DeliveryAnalytics { campaignId: string total: number sent: number delivered: number bounced: number complained: number unsubscribed: number opened: number clicked: number deliveryRate: number openRate: number clickRate: number bounceRate: number } ``` ### `DeliveryTracker` ```ts interface DeliveryTracker { record(event: DeliveryEventInput): Promise get(eventId: string): Promise listByMessage(messageId: string): Promise listByRecipient(email: string, options?: ListOptions): Promise> analytics(campaignId: string): Promise } function createMemoryDeliveryTracker(options?: MemoryTrackerOptions): DeliveryTracker ``` ### Webhook normalizer ```ts interface WebhookNormalizeOptions { secret?: string // HMAC secret for signature verification providerHint?: string // 'sendgrid' | 'mailgun' | 'ses' | 'postmark' | 'generic' } function normalizeWebhookPayload( body: unknown, headers: Record, options?: WebhookNormalizeOptions ): DeliveryEventInput[] ``` ### Error codes ```ts type DeliveryTrackingErrorCode = | 'DLVR_EVENT_NOT_FOUND' | 'DLVR_INVALID_PAYLOAD' | 'DLVR_SIGNATURE_FAILED' | 'DLVR_STORE_FAILED' | 'DLVR_ANALYTICS_FAILED' ``` --- ## Genesis additions 1. **`DeliveryTrackingError`** extends `SuaveplanError` with five stable codes. 2. **Zod schemas** for `DeliveryEvent`, `DeliveryAnalytics`, `WebhookNormalizeOptions`, all provider payload shapes. 3. **Suppression auto-propagation** — `bounced` (hard) and `complained` events automatically call `@suaveplan/suppression` to add the recipient. 4. **Webhook signature verification** — constant-time HMAC via `@suaveplan/crypto`; configurable clock-skew window. 5. **OTel instrumentation** — counter `delivery.event_total` with attribute `delivery.event_type`; histogram `delivery.analytics_duration_ms`. 6. **Property-based tests** — analytics rate calculations for arbitrary event sets. --- ## File layout ```text universal/email/delivery-tracking/ package.json tsconfig.json vitest.config.ts src/ index.ts error-codes.ts constants/ index.ts types/ common.ts common.md core/ delivery-tracker/ delivery-tracker.ts delivery-tracker.md delivery-tracker.types.ts delivery-tracker.test.ts index.ts memory-tracker/ memory-tracker.ts memory-tracker.md memory-tracker.test.ts index.ts analytics/ analytics-aggregator/ analytics-aggregator.ts analytics-aggregator.md analytics-aggregator.test.ts index.ts webhook/ webhook-normalizer/ webhook-normalizer.ts webhook-normalizer.md webhook-normalizer.test.ts index.ts signature-verifier/ signature-verifier.ts signature-verifier.md signature-verifier.test.ts index.ts __benchmarks__/ delivery-tracking.bench.ts tests/ integration.test.ts property.test.ts ``` --- ## Impact **Downstream consumers**: `@suaveplan/campaigns`, any server-side email dispatch service. **Workspace dep prerequisites**: `@suaveplan/error`, `@suaveplan/types`, `@suaveplan/events`, `@suaveplan/suppression`, `@suaveplan/crypto`, `@suaveplan/pagination`.