Last Updated: 2026-08-10
Status: Active — Phase 2 (Traction & Feedback)
Latest release: v0.4.1 (2026-08-10) — dependency-refresh maintenance patch. v0.4.0 (2026-07-29) was the reliability and security release (delivery-correctness audit fixes, authenticated SignalR hub, connect-time IP allowlist, login rate limiting, operator backlog metrics). v0.3.0 (2026-06-08) closed the SDK coverage and portal-client drift gaps; v0.3.1 (2026-06-29) was a container CVE refresh. The embeddable customer portal landed in v0.2.0 (B1 Steps 1-5: /api/v1/portal/* surface, HS256 JWT middleware, per-app dynamic CORS, operator dashboard controls, <PortalAccessModal />); v0.2.1 hardened it (portal CORS deny-cache, PUT→PATCH, validator consolidation); and the @webhookengine/endpoint-manager npm package shipped in the portal-v0.1.0 tag (2026-05-11).
Note: Phase 1 is complete (launch posts and the engineering blog post remain deferred). Phase 2 core tasks (2.2, 2.3, 2.4, 2.5 payload transformation across all three rollout phases, 2.7 application layer cleanup) are done. v0.1.6 added eight follow-on features (endpoint test webhook, validate-time URL guard, per-resource overrides, IP allowlist, audit log, SignalR endpoint health, TanStack Query data layer). v0.2.0 adds the embeddable customer portal (engine + dashboard half). The
@webhookengine/endpoint-managernpm package (B1 Step 7 / Step 11) shipped in theportal-v0.1.0tag (2026-05-11). Remaining Phase 2 items (TypeScript SDK gated on demand signal, comparison / best-practice blog posts) are planned.
WebhookEngine is the first product in a PostgreSQL-native, MIT-licensed SaaS infrastructure toolkit. Starting as a focused webhook delivery platform, it evolves into a multi-channel notification infrastructure — all running from a single Docker Compose.
Phase 1 Phase 2 Phase 3 Phase 4
(Month 1-2) (Month 2-4) (Month 4-8) (Month 8-12)
━━━━━━━━━━━ ━━━━━━━━━━━ ━━━━━━━━━━━━━ ━━━━━━━━━━━━━
Launch & Traction & Notification Multi-Tenant
First Users Feedback Infrastructure Identity Library
Goal: Public GitHub repo, Docker Hub image, first external users.
Principle: Ship what we have. No new features — only polish, docs, and launch.
| # | Task | Priority | Est. | Status |
|---|---|---|---|---|
| 1.1 | Sample app: ASP.NET Core sender + webhook receiver | P0 | 2d | done |
| 1.2 | Complete SDK (WebhookEngineClient real methods) | P0 | 2d | done |
| 1.3 | Signature verification helpers (C#, TypeScript, Python) | P0 | 1d | done |
| 1.4 | Getting Started guide (zero to first webhook in 5 min) | P0 | 1d | done |
| 1.5 | Self-hosting guide (config reference, production tips) | P1 | 1d | done |
| 1.6 | CONTRIBUTING.md + issue/PR templates | P1 | 0.5d | done |
| 1.7 | GitHub repo setup (labels, milestones, release) | P1 | 0.5d | prepared |
| 1.8 | Docker Hub publish (voyvodka/webhook-engine:latest) | P0 | 0.5d | done |
| 1.9 | NuGet publish (WebhookEngine.Sdk) | P0 | 0.5d | done |
| 1.10 | Launch posts (HN Show HN, r/dotnet, r/selfhosted) | P0 | 1d | deferred |
| 1.11 | Blog: "How We Built Reliable Webhook Delivery with PostgreSQL" | P1 | 1d | deferred |
-
docker compose up→ working system in < 2 minutes - GitHub repo public with README, docs, LICENSE, CONTRIBUTING
- Docker Hub image available
- NuGet SDK published
- At least 1 launch post published
- Sample app works end-to-end
- No new features
- No TypeScript SDK yet (wait for demand signal)
- No Kubernetes support
- No UI redesign
Patch release focused on project discoverability and packaging hygiene. No new engine features.
| # | Task | Status |
|---|---|---|
| P.1 | Landing page at webhook.sametozkan.com.tr — features, quick start, links | done |
| P.2 | GitHub Pages setup with custom domain + SSL | done |
| P.3 | SEO: JSON-LD structured data, OG/Twitter tags, canonical, sitemap, robots.txt | done |
| P.4 | SDK version aligned with main project (0.1.3), PackageProjectUrl updated |
done |
| P.5 | GitHub repo homepage set to landing page | done |
| P.6 | README header updated with website, Docker Hub, NuGet links | done |
| P.7 | Internal planning docs removed from public repo | done |
| # | Task | Status |
|---|---|---|
| 2.5 P1 | JMESPath payload transformation: schema + API (transformExpression, transformEnabled, transformValidatedAt on endpoints) |
done |
| 2.5 P2 | JMESPath payload transformation: delivery integration with 100 ms timeout, 256 KB output cap, fail-open fallback | done |
| 2.5 P3 | JMESPath payload transformation: dashboard CodeMirror 6 editor + /dashboard/transform/validate endpoint |
done |
| — | Multi-arch Docker (linux/amd64 + linux/arm64) | done |
| — | NuGet brand icon (WebhookEngine.Sdk + Docker Hub README sync) |
done |
| — | OpenAPI 3 + Scalar interactive UI (/openapi/v1.json, /scalar) — Dev / Staging only |
done |
| — | Security automations: CodeQL, Dependency Review, Dependabot (NuGet / npm / GitHub Actions / Docker) | done |
| — | Replay + Batch integration tests | done |
| — | Frontend toolchain: Yarn → Bun 1.2 | done |
| — | WebhookEngine.Application empty scaffold removed (ADR-002 update) |
done |
A multi-agent deep audit covering security, memory, concurrency, code quality, frontend, ops, timezone correctness, and SDK compliance produced ten F-fixes plus an idempotency race fix and an SDK target-framework simplification. No breaking API changes.
| # | Task | Status |
|---|---|---|
| F1 | SSRF guard with DNS-rebinding defense (SocketsHttpHandler.ConnectCallback IP-pinning, WebhookEngine:SsrfGuard options) |
done |
| F2 | Compare-and-set guards on MessageRepository.Mark*Async (concurrency C2 — duplicate-attempt regression on lock loss closed) |
done |
| F3 | Advisory-lock serialized EndpointHealthTracker.WithEndpointLockAsync (concurrency C1 — Open/HalfOpen/Closed corruption closed) |
done |
| F5 | Migration startup race serialized via pg_advisory_lock |
done |
| F6 | Security headers (HSTS, CSP, X-Frame-Options, Permissions-Policy), /metrics auth gate, cookie SecureAlways |
done |
| F7 | Idempotency race condition closed — partial unique index idx_messages_app_endpoint_idempotency + Stripe-style 23505 catch + retention NULL-out |
done |
| F8 | Frontend session-expiry redirect + chunk-load error boundary | done |
| F9 | HttpResponseMessage disposal + EndpointRateLimiter idle-eviction |
done |
| F10 | CustomHeaderPolicy allow-list + reserved-header rejection |
done |
| Ops | Liveness / readiness probes, OpenTelemetry tracing, graceful shutdown drain window | done |
| SDK | WebhookVerifier shipped in WebhookEngine.Sdk + target framework simplified to net10.0 only |
done |
Eight new features, three rounds of dashboard polish, three reviewer-finding fixes, and a backend correctness pass. Test count moved from 211 to 215.
| # | Task | Status |
|---|---|---|
| F1 | Endpoint test webhook (POST /api/v1/dashboard/endpoints/{id}/test) + dashboard preview drawer |
done |
| F2 | Endpoint URL DNS resolution / private-IP rejection at validator chain | done |
| F3 | Per-app retention overrides (Application.RetentionDeliveredDays, RetentionDeadLetterDays) |
done |
| F4 | Per-event-type idempotency window override (EventType.IdempotencyWindowMinutes) |
done |
| F6 | Per-application rate-limit override (Application.RateLimitPerSecond) |
done |
| F7 | SignalR EndpointHealthChanged event for circuit-state and visible status transitions |
done |
| F8 | Per-endpoint IP allowlist (Endpoint.AllowedIpsJson, CIDR positive-list gate at delivery) |
done |
| F9 | Append-only audit log (audit_logs table, GET /api/v1/dashboard/audit) |
done |
| F12 | TanStack Query dashboard data layer across six pages — manual setInterval polling and the smart-debounce shim removed |
done |
| R1 | Transient DNS retry within budget (no early dead-letter on resolver flakes) | done |
| R3 | Cascade message-delete on application / endpoint removal | done |
| R6 | Smart-debounced dashboard polling (later folded into F12) | done |
| R2 + R4 + R5 | IP matcher contract guard, application rate-limiter sweep thread-safety, endpoint health tracker double-fetch removed | done |
| DPR-1 | Modal a11y (role="dialog" + ARIA + focus trap), reconnect-safe SignalR cache, awaited refetches, skeleton loaders |
done |
| DPR-2 | Shared StatusBadge / inputClasses / editor theme, lazy-loaded CodeMirror, parseError field-error routing |
done |
| DPR-3 | Modal dvh sizing, mobile filter grid, payload field error, SignalR Live / Offline header badge, URL field error wiring |
done |
First minor release. The engine half and operator dashboard half of the embeddable customer portal land here. The @webhookengine/endpoint-manager React package shipped in the follow-up portal-v0.1.0 tag (2026-05-11).
| # | Task | Status |
|---|---|---|
| B1 Step 1 | Bun workspaces — root package.json + single bun.lock + Dockerfile/CI plumbing |
done |
| B1 Step 2 | Application.PortalSigningKey + AllowedPortalOriginsJson migration |
done |
| B1 Step 3 | PortalTokenAuthMiddleware (HS256 algorithm-pinned, 15-min cap, capability-scoped) + PortalCorsMiddleware (RFC 6454 ordinal-case-insensitive) + PortalLookupCache + PortalCapability enum |
done |
| B1 Step 4 | PortalEndpointsController — 9 narrowed /api/v1/portal/* routes; MessageRepository.ListAttemptsByEndpointAsync / CountAttemptsByEndpointAsync |
done |
| B1 Step 5 | DashboardPortalController (5 routes) + <PortalAccessModal /> + Application.PortalRotatedAt migration; audit log redacts signing key to boolean |
done |
| — | AuditLogRepository extract — AuditLogsController no longer bypasses repository pattern |
done |
| — | Tailwind 4.2.4 → 4.3.0 | done |
| — | Dependabot npm bun.lock auto-sync workflow |
done |
| — | Documentation drift sync (ADR-003 Accepted, stack version lines) | done |
| B1 Step 7 | @webhookengine/endpoint-manager npm package |
done (portal-v0.1.0, 2026-05-11) |
Goal: Learn from real users. Fix what's broken. Add what's missing.
Principle: Listen first, build second. Every feature must come from user feedback or clear demand signal.
| # | Task | Priority | Trigger | Status |
|---|---|---|---|---|
| 2.1 | Bug fixes and edge cases | P0 | GitHub issues | in_progress |
| 2.2 | Event replay (re-deliver events in a time range) | P1 | Almost certain user request | done |
| 2.3 | Batch message sending (multiple events in one API call) | P1 | API power users | done |
| 2.4 | Rate limiting per endpoint | P1 | Large-scale users | done |
| 2.5 | Webhook payload transformation (JMESPath, ADR-003 — schema, delivery integration, dashboard editor) | P2 | Integration use cases | done |
| 2.6 | TypeScript SDK (npm) | P1 | If demand signal exists | planned |
| 2.7 | Application layer cleanup (implement CQRS or remove scaffold) | P1 | Tech debt | done |
| 2.8 | Blog: "Webhook Delivery Best Practices" | P1 | SEO + authority | planned |
| 2.9 | Blog: "WebhookEngine vs Svix vs Convoy" | P1 | SEO + positioning | planned |
| 2.10 | Integration guide: ABP Framework + WebhookEngine | P2 | .NET ecosystem reach | planned |
Evaluate based on data:
- Docker pulls > 500? → Market exists, proceed to Phase 3
- GitHub issues active? → Users are engaged
- Zero traction? → Reassess positioning or pivot
- 500+ Docker Hub pulls
- 200+ GitHub stars
- At least 5 GitHub issues from external users
- 2+ blog posts published
Goal: Evolve WebhookEngine from webhook-only to multi-channel notification platform.
Principle: Webhook remains the core. New channels are additive. Existing users are not disrupted.
- Same codebase, same community, same Docker image
- Webhook is just one notification channel — email, SMS, push are others
- Novu (38.6K stars) proves the market; their weakness (MongoDB + Redis) is our strength
- "PostgreSQL-native Novu alternative" is a stronger story than "Svix alternative in .NET"
WebhookEngine v1 (current) WebhookEngine v2 (Phase 3)
━━━━━━━━━━━━━━━━━━━━━━━━━ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
INotificationChannel interface
Webhook delivery (HTTP POST) → ├── WebhookChannel (existing)
├── EmailChannel (SMTP, SendGrid, Resend)
├── InAppChannel (SignalR real-time)
└── (future: SMS, Push)
Subscriber management
├── Subscriber profiles
├── Channel preferences
└── Topic subscriptions
Notification workflows
├── Send → Delay → Send
├── Channel fallback
└── Digest/batching
| # | Task | Priority | Est. |
|---|---|---|---|
| 3.1 | INotificationChannel interface + refactor webhook as first channel |
P0 | 3d |
| 3.2 | Email channel: SMTP provider | P0 | 3d |
| 3.3 | Email channel: SendGrid provider | P1 | 2d |
| 3.4 | Email channel: Resend provider | P2 | 1d |
| 3.5 | Subscriber entity + management API | P0 | 3d |
| 3.6 | Subscriber channel preferences | P0 | 2d |
| 3.7 | In-App notification channel (SignalR) | P0 | 4d |
| 3.8 | <NotificationInbox /> React component (embeddable) |
P1 | 5d |
| 3.9 | Notification workflow engine (send → delay → send) | P1 | 5d |
| 3.10 | Channel fallback (try push, fallback to email) | P2 | 3d |
| 3.11 | Digest/batching ("group last N events into one email") | P2 | 3d |
| 3.12 | Template system (Handlebars-style variables, per-channel) | P1 | 3d |
| 3.13 | Dashboard: subscriber management page | P0 | 3d |
| 3.14 | Dashboard: notification log (all channels) | P0 | 2d |
| 3.15 | Dashboard: workflow editor (visual) | P2 | 5d |
| 3.16 | npm package: @webhookengine/inbox |
P1 | 2d |
| 3.17 | Documentation: notification channels guide | P0 | 2d |
| 3.18 | Blog: "PostgreSQL-Native Notification Infrastructure" | P1 | 1d |
- Email + In-App + Webhook channels working
- Subscriber preferences functional
-
<NotificationInbox />npm package published - Positioning shift: "webhook + notification infrastructure"
- 1000+ GitHub stars
Goal: Separate NuGet package for ASP.NET Core multi-tenant Identity.
Principle: Independent project, same brand ecosystem. WebhookEngine dogfoods it for its own multi-tenant support.
| # | Task | Priority |
|---|---|---|
| 4.1 | TenantIdentityDbContext (extends IdentityDbContext) | P0 |
| 4.2 | TenantUserManager (tenant-scoped queries) | P0 |
| 4.3 | TenantSignInManager (tenant resolution during login) | P0 |
| 4.4 | User-Tenant many-to-many mapping | P0 |
| 4.5 | Multi-DB migration engine (ITenantMigrator) | P0 |
| 4.6 | Tenant resolution strategies (subdomain, path, header) | P0 |
| 4.7 | Finbuckle compatibility layer | P1 |
| 4.8 | Sample project + documentation | P0 |
| 4.9 | NuGet publish | P0 |
- NuGet package published
- Works with PostgreSQL + SQL Server
- Sample project with WebhookEngine integration
- 2000+ NuGet downloads in first 3 months
WebhookEngine Ecosystem
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
WebhookEngine → Webhook + Notification delivery
+ Email, SMS, Push, In-App channels
+ Workflow orchestration
+ Embeddable <NotificationInbox />
TenantIdentity → Multi-tenant ASP.NET Core Identity
+ Shared Identity DB + per-tenant data DB
+ NuGet package
(possible) EventBus → PostgreSQL-native event bus
+ Pub/sub between microservices
+ Outbox pattern built-in
All: PostgreSQL-only, Docker Compose, MIT licensed, .NET native.
- SMS channel (Twilio, Vonage)
- Push channel (FCM, APNs)
- WhatsApp Business API
- Managed cloud offering (SaaS)
- Kubernetes Helm chart
- Embeddable endpoint management portal
- A/B testing for notification content