Domain research platform
Multi-tenant SaaS with subscription-tier entitlements down to the field level, event-driven auction auto-bidding, third-party data pipelines and Stripe billing. The hard part was SQL: a 13 GB index scan over 130M+ row tables, cut about 10× with covering and filtered indexes.
The problem
Domain investors want to know which newly registered names are worth buying. The platform cross-references millions of domain candidates against real business data — company keywords, LinkedIn company data, Crunchbase and funding records — and then bids on auctions automatically.
What I built
- React 19 + Vite on Azure Static Web Apps, an ASP.NET Core 8 API and SQL Server.
- Multi-tenant entitlements that gate API responses down to individual fields, by subscription tier, with Stripe billing.
- Event-driven auto-bidding on Hangfire instead of polling loops.
- Third-party data pipelines that refresh the signals behind each candidate.
Making SQL fast
The expensive query was a 13 GB index scan over tables of 130M+ rows. It came down about 10× with:
- Denormalisation — frequently filtered metrics copied onto the candidate row in batch updates, removing the joins.
- Covering and filtered indexes, with standard indexes kept alongside so the optimiser still has options.
- Capped result counts, so changing a filter never triggers a full count over the table.
What broke, and the fix
- Stale auction data. End times cached from providers drifted as auctions were extended or rescheduled. Freshness is now layered: a live re-check when a bid is scheduled, background refreshes for pending bids, and explicit auction status tracking.
- Lost encryption keys. ASP.NET Core DataProtection keys regenerated inside containers, making stored credentials unreadable, until the keys were persisted to the database.
- Static Web Apps deploy failures that needed manual workarounds.
Lessons
Retrofitting multi-tenant entitlements touched nearly every endpoint and took eight work phases. Design the entitlement model first. All times are stored in UTC and converted at the edge.