Roadmap
v0.4.0 — Planned (mid-2026)
Phase 18 — Polly Resilience Hooks
Opt-in Polly policy integration per adapter. Every HTTP-based adapter will expose an IHttpClientBuilder hook so you can attach your own Polly policies — retry, timeout, circuit breaker, bulkhead — without any Polly dependency inside the library.
// Planned API — subject to change before release
builder.Services.AddRecurPixelNotify(options => { ... })
.ConfigureEmailHttpClient(http => http
.AddResiliencePipeline("email", pipeline => pipeline
.AddRetry(new RetryStrategyOptions { MaxRetryAttempts = 3 })
.AddCircuitBreaker(new CircuitBreakerStrategyOptions
{
FailureRatio = 0.5,
SamplingDuration = TimeSpan.FromSeconds(30),
BreakDuration = TimeSpan.FromSeconds(60),
})
.AddTimeout(TimeSpan.FromSeconds(10))));
What this means: you own the resilience policy entirely. The library owns the HttpClient lifetime and named client wiring. No Polly dependency in RecurPixel.Notify.Core — you bring Polly if you want it.
Circuit breaking today (no library needed): Wrap TriggerAsync in a Polly ResiliencePipeline in your own service layer. It’s roughly 10–15 lines and gives you full control over failure thresholds, sampling windows, and break duration.
Phase 19 — OpenTelemetry Integration
Full distributed tracing via System.Diagnostics.ActivitySource. Every TriggerAsync call, channel dispatch, and provider API call becomes a traceable span.
builder.Services.AddOpenTelemetry()
.WithTracing(tracing => tracing
.AddRecurPixelNotifyInstrumentation());
Activity tags per send attempt:
| Tag | Value |
|---|---|
notify.channel |
"email", "sms", "push", etc. |
notify.provider |
"sendgrid", "twilio", etc. |
notify.event_name |
Event name from TriggerAsync |
notify.success |
"true" or "false" |
notify.recipient_hash |
SHA-256 first 8 chars — never raw PII |
notify.used_fallback |
"true" when a fallback channel fired |
notify.bulk_batch_id |
Batch ID when part of a BulkTriggerAsync call |
Exportable to OTLP, Zipkin, Jaeger, or any OpenTelemetry collector. No Activity is emitted if no listener is registered — zero overhead when OpenTelemetry is not configured.
Privacy:
notify.recipient_hashis a one-way hash — raw email addresses, phone numbers, and device tokens are never written to traces.
Phase 20 — Additional Adapters
New provider adapters based on adoption:
| Package | Provider | Channel |
|---|---|---|
RecurPixel.Notify.Sms.Kaleyra |
Kaleyra | SMS |
RecurPixel.Notify.WhatsApp.Gupshup |
Gupshup | |
RecurPixel.Notify.WhatsApp.AiSensy |
AiSensy |
Community contributions welcome. Requirements: extend NotificationChannelBase, include a full unit test suite, provide a SkippableFact integration test that skips when credentials are absent. See Contributing.
Phase 21 — Dashboard v2
Read-only enhancements to the Dashboard introduced in v0.3.0:
- Batch detail page — dedicated view for a single bulk send with per-recipient status rows
- Provider health indicators — per-provider success rate over the last 24h in the summary row
- CSV export — download filtered log results from the UI
Retry actions are not in v0.4.0. Resending a failed notification from the dashboard requires storing the original payload (not currently persisted) and solving idempotency. This needs a design document before any implementation.
What Will Never Be Built
These are explicitly out of scope. Build them in your application layer if you need them.
| Feature | Why not |
|---|---|
| Template engine | You own subject, body, and HTML. We deliver the payload, we don’t build it. |
| Background queue / dispatcher | Call TriggerAsync from your own Hangfire, Quartz, or MassTransit job. |
| Scheduled send | Requires a persistent scheduler — wire your own, call TriggerAsync at fire time. |
| First-class circuit breaker | Phase 18 (Polly hooks) gives you a full circuit breaker in ~15 lines using Polly’s own CircuitBreakerStrategy. Building a duplicate inside the library adds stateful infrastructure and duplicates work Polly already does better. |
| Load balancing / round-robin across providers | Use Named Provider Routing for intent-based routing; random distribution across providers is not a notification library concern. |
| A/B testing across providers | Same reason. |
| Notification log storage (without Dashboard) | OnDelivery hook exists; you write to your own DB. The Dashboard package is opt-in for those who want a built-in store. |