What is Hapnd?
Hapnd is a managed event sourcing platform that eliminates the infrastructure complexity traditionally required to build event-sourced systems. Engineers upload C# domain logic, append events through an SDK, and receive computed state back immediately — with zero infrastructure to provision, no message brokers to manage, and no projection engines to build.
The core promise: upload C# code, it just works. Zero configuration. Zero manual deployment steps. Zero compromises on security.
The Problem
Section titled “The Problem”Building an event-sourced system from scratch typically requires:
- Message infrastructure — Kafka, RabbitMQ, or EventStoreDB clusters to provision and maintain
- Projection engines — Custom code to subscribe to event streams, apply events to read models, handle failures, and manage checkpoints
- Snapshot management — Logic to periodically snapshot aggregate state so replaying from the beginning of time doesn’t become a performance problem
- Replay mechanisms — The ability to rebuild projections from historical events when logic changes
- Concurrency control — Optimistic concurrency to prevent lost updates across distributed writes
- Multi-tenancy — Isolation guarantees if serving multiple customers from the same infrastructure
- Security hardening — Ensuring customer code can’t escape its sandbox in a shared environment
Each of these is a significant engineering effort. Together, they represent months of work before any domain logic gets written. Hapnd collapses all of this into a single platform where the only thing an engineer writes is their domain logic.
How It Works
Section titled “How It Works”Hapnd follows a progressive capability model. Start simple and add capabilities as you need them.
1. Events
Section titled “1. Events”Append immutable facts about things that happened. Events are stored in per-aggregate streams with monotonically increasing version numbers. This is your source of truth — everything else is derived.
var result = await hapnd.Aggregate("order_123") .Append(new OrderPlaced { CustomerId = "cust_456" });2. Reducers
Section titled “2. Reducers”Write a C# class that computes state from events. Bind it to an aggregate type, and every event append returns the computed state synchronously in the response. Think of it as a fold: (State, Event) → New State.
public class OrderReducer : IReducer<OrderState>{ public OrderState Apply(OrderState? state, Event @event) { state ??= new OrderState(); return @event.Type switch { "OrderPlaced" => state with { CustomerId = @event.GetData<OrderPlacedData>().CustomerId }, "ItemAdded" => state with { Total = state.Total + @event.GetData<ItemAddedData>().Price }, _ => state }; }}3. Projections
Section titled “3. Projections”Build asynchronous read models across all aggregates. Same interface as reducers, but executed via a queue after events are appended. Hapnd automatically replays historical events and then processes new events as they arrive.
4. Notifications
Section titled “4. Notifications”Get notified when projection state changes. Three delivery mechanisms: webhooks (HTTP push with HMAC-SHA256 signatures), WebSocket streaming (real-time), or REST polling (cursor-based).
Technology
Section titled “Technology”| Component | Choice | Why |
|---|---|---|
| Cloud platform | Cloudflare Workers | Edge-native, no cold starts, global distribution |
| Event storage | Durable Objects + SQLite | Strong consistency per aggregate, co-located storage and compute |
| Code execution | .NET 10 + Roslyn | Enterprise C# ecosystem, compile-time security via semantic analysis |
| SDK resilience | Polly | Industry-standard .NET resilience library |
| Region | London (WEUR) | All infrastructure co-located for minimal latency |
Security
Section titled “Security”Hapnd runs your code through four security layers:
- Semantic allowlist at compile-time — Roslyn analyses your code and only permits explicitly allowed APIs. This is an inverted model: everything is blocked unless specifically permitted.
- DLL signature verification at load-time — Compiled assemblies are signed with ECDSA P-256. The container verifies signatures before loading any assembly.
- Environment variable stripping at runtime — Your code cannot access platform secrets.
- Container isolation — Non-root user, Alpine-based, CPU/memory limits, 5-second execution timeout.
Performance
Section titled “Performance”| Operation | Typical Latency |
|---|---|
| Event append (no reducer) | ~15–30ms |
| Event append (with reducer) | ~200–500ms |
| State query | ~15–30ms |
Reducer latency includes container invocation. For high-throughput scenarios where immediate state isn’t needed, append without a reducer bound and query state separately.