An open-source auction platform built on the Critter Stack — a reference architecture and live conference demo vehicle for event-driven .NET systems.
CritterBids is a working, demonstrable auction platform built on Wolverine (messaging and command handling), Marten (event sourcing + document storage over PostgreSQL), and Polecat (event sourcing + document storage over SQL Server) — JasperFx's suite of .NET libraries collectively known as the Critter Stack.
CritterBids is one of several open-source reference architectures showcasing the Critter Stack across different domains. The auction domain was chosen because competitive real-time bidding surfaces patterns — contention, time pressure, multi-audience projections — that simpler domains don't.
CritterBids is intended to be run, demonstrated, and learned from and not for actual live auctions.
Auctions are a natural fit for event-driven architecture. The core mechanic — competitive bidding under time pressure — is inherently event-driven, and the domain surfaces patterns that simpler examples don't:
| Pattern | How CritterBids demonstrates it |
|---|---|
| Dynamic Consistency Boundaries (DCB) | Concurrent bidders contending over the same lot — the canonical DCB scenario, not a contrived one |
| Sagas and process managers | Auction closing, proxy bid manager, post-sale obligations, and anti-snipe extended bidding are four distinct saga shapes |
| Projections by audience | Sellers, participants, ops staff, and finance all need radically different views of the same event streams |
| Real-time transport | SignalR is load-bearing — the live bid feed is the participant experience, not a demo flourish |
| Mixed storage engines | PostgreSQL via Marten for auction-core BCs; SQL Server via Polecat for operations and finance |
| Transport agnosticism | RabbitMQ for MVP, then a live swap to Azure Service Bus — one config change, no BC-level refactor |
Any audience can follow a live bidding session, whether or not they know what an event store is. That makes it an unusually effective teaching vehicle.
CritterBids is a modular monolith — a single deployable unit organized into well-enforced, loosely-coupled bounded context modules.
- Each bounded context (BC) is a separate .NET class library project
- BCs communicate exclusively through types in
CritterBids.Contracts— no BC references another BC's internals - The
CritterBids.Apihost wires all modules together at startup viaAddXyzModule()extension methods - All cross-BC messaging is via Wolverine — no direct handler-to-handler calls
This gives the boundary enforcement of microservices without the distributed systems overhead. The full stack runs on a single VPS.
| BC | Storage | Key Patterns |
|---|---|---|
| Auctions | PostgreSQL / Marten | DCB, Auction Closing saga, Proxy Bid saga |
| Selling | PostgreSQL / Marten | Event-sourced aggregate, listing state machine |
| Listings | PostgreSQL / Marten | Multi-stream projections, full-text search, watchlist |
| Obligations | PostgreSQL / Marten | Saga, cancellable scheduled messages, escalation chain |
| Relay | PostgreSQL / Marten | Wolverine handlers, SignalR push to participants |
| Participants | SQL Server / Polecat | Event-sourced aggregate, anonymous session management |
| Settlement | SQL Server / Polecat | Saga, financial event stream, reserve evaluation |
| Operations | SQL Server / Polecat | Cross-BC projections, SignalR ops dashboard |
The SQL Server BCs reflect a real organizational pattern: finance and ops data belongs where BI tooling and compliance teams can query it directly, without an ETL layer.
| Concern | Tool |
|---|---|
| Language | C# 14 / .NET 10 |
| Message handling | Wolverine 5+ |
| Event sourcing (PostgreSQL) | Marten 8+ |
| Event sourcing (SQL Server) | Polecat 2+ |
| Async messaging | RabbitMQ (AMQP) |
| Real-time push | SignalR |
| Testing | xUnit + Shouldly + Testcontainers + Alba |
| Frontend | React + TypeScript |
| Local orchestration | .NET Aspire 13.2+ |
| Deployment | Hetzner VPS |
The standard eBay-style format. A seller creates a listing, configures a duration (1, 3, 5, 7, or 10 days), and publishes it. The listing runs independently. The highest bidder at the scheduled close wins, subject to reserve.
An Operations staff member creates a Session, attaches listings, and starts it. All listings open simultaneously and close together — typically 5 to 10 minutes later. Extended bidding can fire on individual lots.
Flash Sessions exist for live conference and meetup demonstrations. They use the same Auctions BC mechanics as timed listings — the same saga, the same DCB enforcement, the same anti-snipe logic. The Session is an optional coordination container, not a separate system.
The ideal live demonstration:
- Presenter shows a QR code or URL
- Audience scans — receives an anonymous session with a generated display name and a hidden credit ceiling
- A Flash Session starts — three to five lots, five to ten minutes, everything live on the projector
- Audience bids. Extended bidding fires. The ops dashboard shows saga state, bid feed, and settlement activity in real time.
- Lots close. Winners are declared. The audience watched it happen.
This scenario directly shapes architectural decisions. Anonymous frictionless onboarding, SignalR reliability under load, a projector-legible ops dashboard, and a single docker compose up deployment are all first-class constraints — not afterthoughts.
Note: CritterBids is in active early development. The
src/projects are being built out milestone by milestone. The instructions below reflect the intended local development workflow.
- .NET 10 SDK
- Docker Desktop (or compatible Docker runtime)
- Node.js 22+ (for React frontends)
CritterBids uses .NET Aspire for local orchestration. A single command starts PostgreSQL, SQL Server, RabbitMQ, and the API host — no separate docker compose up needed.
dotnet run --project src/CritterBids.AppHost --launch-profile httpThe Aspire dashboard opens at http://localhost:15237. It shows live service health, structured logs, and distributed traces for all running resources. In Docker Desktop, the three infrastructure containers (PostgreSQL, SQL Server, RabbitMQ) appear grouped under critterbids in the Containers view.
To use the HTTPS profile instead, first trust the .NET development certificate if you haven't already:
dotnet dev-certs https --trustThen run with the https profile:
dotnet run --project src/CritterBids.AppHost --launch-profile httpsThe dashboard will be at https://localhost:17019.
The participant frontend (critterbids-web) and ops dashboard (critterbids-ops) are separate React apps in src/frontend/.
CritterBids/
├── src/
│ ├── CritterBids.AppHost/ # .NET Aspire orchestration — local dev entry point
│ ├── CritterBids.Api/ # Host — wires all BC modules together
│ ├── CritterBids.Contracts/ # Shared integration event types (the BC public API)
│ ├── CritterBids.Auctions/ # Auctions BC
│ ├── CritterBids.Selling/ # Selling BC
│ ├── CritterBids.Listings/ # Listings BC
│ ├── CritterBids.Obligations/ # Obligations BC
│ ├── CritterBids.Relay/ # Relay BC (SignalR push)
│ ├── CritterBids.Participants/ # Participants BC
│ ├── CritterBids.Settlement/ # Settlement BC
│ ├── CritterBids.Operations/ # Operations BC
│ └── frontend/
│ ├── critterbids-web/ # Participant-facing SPA
│ └── critterbids-ops/ # Staff ops dashboard
├── tests/
│ └── [BC integration and unit test projects]
└── docs/
├── vision/ # Overview, BC map, domain event vocabulary
├── skills/ # Implementation pattern guides (load before implementing)
├── decisions/ # Architecture Decision Records (ADRs)
├── milestones/ # Scoped milestone definitions
└── personas/ # Agent personas for Event Modeling workshops
| Document | Purpose |
|---|---|
docs/vision/overview.md |
Full project vision, eBay model, architecture summary |
docs/skills/README.md |
Skills index — load before implementing any feature |
docs/decisions/ |
Architecture Decision Records |
docs/milestones/MVP.md |
MVP definition of done and demo scenario |
CLAUDE.md |
AI development entry point and coding conventions |
If you are contributing or exploring the codebase with an AI assistant, start with CLAUDE.md.
MVP — A working, demonstrable auction platform suitable for a live conference demo with audience participation. All 8 BCs, both listing formats, both React frontends, full docker compose up deployment.
Post-MVP milestones (planned):
M-transport-swap— Live swap from RabbitMQ to Azure Service Bus (configuration-only change, demonstrable during a conference talk)M-polecat-marten-swap— Swap a Polecat BC to Marten, demonstrating JasperFx's storage-agnostic programming model- Real payment processor integration (same saga shape, real Stripe wiring)
- Demo reset command cascade
- Feedback and reputation system
Contributions welcome. Before submitting a PR:
- Read
CLAUDE.mdfor coding conventions and the non-negotiable modular monolith rules - Load the relevant skill file from
docs/skills/before implementing - Run
dotnet buildanddotnet testbefore committing - Do not commit directly to
main— branch and PR
- Blog: event-sourcing.dev
- Wolverine: wolverine.netlify.app
- Marten: martendb.io
- Polecat: polecat.netlify.app
- JasperFx: jasperfx.github.io
- Tools: JetBrains Rider, DataGrip
Erik "Faelor" Shafer