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.
- Agent, brokerage and city leaderboards — ranked on real closed-sale volume and count, not promises.
- Per-ZIP and per-city rankings with month-over-month movement, driven by monthly ranking snapshots.
- Rule-based market signals — momentum, market share, dependency, rookie and recruitability — with a public methodology page: no AI, no surveys, every number traceable to a formula.
- A ZIP heat table surfacing which markets are accelerating and which are cooling.
- Agent subscriptions (Basic / Pro) to claim a profile and showcase rankings, plus brokerage recruiting views.
- The original real-time auction engine — sealed-bid, SignalR-powered — preserved intact and switchable back on.
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
- Cross-MLS duplicate sales are collapsed before ranking, so a transaction listed in two systems can never double-count toward an agent's volume.
- The merge queue lets an admin pick which identity survives, then re-points ZIP / city / brokerage / user / Stripe rows onto it — audited, reversible, and reseeded in triage order on rescan.
- Ranking methodology is fully public and rule-based — momentum, share, dependency, rookie, recruitability — with no AI and no surveys.
- Subscriptions are Stripe Basic / Pro; the platform distinguishes registered-but-not-subscribed agents from paying members, and role state mirrors subscription state via webhooks.
- The live sealed-bid auction engine (SignalR + tokenized Authorize.Net) is intact but hidden — a deliberate pivot, preserved for the day it returns.
- Multi-step address normalisation gives per-ZIP attribution the precision a leaderboard needs — unit-level matching is what keeps two agents on the same street from blurring together.