Project · Sulfur

Agent Arena

Every agent ranked on real sales — the competitive truth of a market.

Essence

For the people who use it

Agent Arena began as a sealed-bid auction house. Homeowners listed a property, qualified agents bid in real time for exclusive representation, and the market — not the warmest handshake — set the agent's value. That engine works, and it still lives in the codebase. But it kept pointing at a harder, more valuable question underneath: which agent is actually the best in this market, by the only measure that can't be spun — closed sales.

So Agent Arena pivoted to the answer: a market-intelligence leaderboard that ranks every Florida real-estate agent by their actual transaction history — drawn from cleaned MLS data, never self-reported — at two grains, per ZIP code and per city. It answers three questions a brokerage actually pays for: which ZIPs are heating up, which agents are rising or already dominant, and which agents look recruitable right now. Agents subscribe to claim and showcase their standing; brokerages use it to scout talent before a competitor does.

The leaderboard is the easy half. The hard half — where most of the engineering went — is making the numbers true. Real-estate data is filthy: the same agent appears under a dozen name spellings, phone numbers and identifiers across overlapping MLS feeds, and a single sale can show up two or three times. Before a single rank is computed, a cleanup pipeline resolves agent identity and collapses duplicate sales — so a leaderboard position means exactly what it claims.

Visit Agent Arena

Construction

For the engineers

Stack

Runtime
.NET 10 · C# latest
API
ASP.NET Core 10 · MediatR 14 (CQRS) · FluentValidation 12 · JWT Bearer
Web
Blazor WebAssembly 10 — public Site (custom CSS) + Admin console (Bootstrap)
Data
EF Core 10 database-first (idempotent SQL, no migrations) · SQL Server / Azure SQL
Ranking store
Cleaned MLS transaction table + per-(agent, ZIP) ranking tables + monthly history snapshots
Subscriptions
Stripe — Basic / Pro tiers, webhook-driven role sync
Messaging
SendGrid (email) · Twilio (SMS)
Real-time
SignalR 10 — the sealed-bid auction hub, in its own process (preserved, currently hidden)
Storage & observability
Azure Blob Storage · Application Insights · OpenTelemetry
Testing
NUnit 4 · Moq · Playwright · NBomber load tests
Hosting
Azure App Services (Linux) · Cloudflare DNS · Azure DevOps pipelines

Architecture

The cleanup pipeline is the product. MLS sales arrive from overlapping feeds and land in a cleaned transaction table: agent names, phones (normalised to E.164) and emails are canonicalised, addresses are parsed to a canonical form, and every transaction is de-duplicated via a deterministic CleaningKey — so a sale that appears in two MLS systems collapses to one before it can inflate anyone's numbers. Only the last 24 complete months of Sold records are retained, and future-dated rows are rejected at ingest.

Agent-identity resolution is the deep work. One human shows up as many agent identities — phone|name variants scattered across feeds. An admin merge queue surfaces candidate pairs (including re-key collisions), lets an operator choose which identity survives, and then re-points every dependent row — ZIP rankings, city rankings, brokerage history, user links, even Stripe-linked accounts — onto the survivor. An alias table and a naming-fault queue catch the long tail, and bulk identifier re-key sweeps clean systematic faults in one pass. The whole thing is built to be audited and reversed, and a rescan reseeds the backlog in triage order.

Rankings, then enrichment. A pipeline writes one row per (agent, ZIP) into a unified rankings table plus per-city rollups, snapshots them monthly so month-over-month deltas are real, and then an enrichment pass computes rule-based signals — momentum, market share, dependency, rookie and poachability — at both ZIP and agent-within-ZIP grain. There is no model and no guesswork: every figure on the dashboard maps back to a documented formula, and a public methodology page spells each one out in plain English first, then in arithmetic.

The auction engine is preserved, not deleted. The original sealed-bid auction still lives in its own AgentArena.Auction SignalR service — auction state as a static ConcurrentDictionary behind per-room semaphores, group-based messaging per auction, JWT passed through the WebSocket upgrade — alongside tokenized Authorize.Net commission capture. The pivot hid it from the live product rather than removing it: the hub, the code and the schema remain, so real-time auctions can be switched back on without a rebuild.

The rest holds. A twelve-project clean-architecture solution; database-first idempotent SQL scripts for zero-downtime deploys; three-layer caching with a coordination layer that invalidates on mutation; and the sibling lead-generation funnel — a Redfin scraper plus targeted mailers, with multi-step address normalisation (uppercase, strip punctuation, standardise suffixes, directionals and units, append city/state/ZIP) — that drives sellers and agents into the platform. Everything runs on Azure App Services behind Cloudflare, deployed through Azure DevOps.

Notable details