Value Bets
Model price against the market's, on three boards that run at once — and the URL-to-query mapping that has to exist on both sides of the network.
| Route | Composed |
|---|---|
/value-bets | src/composed/value-bets |
/value-bets-v2/[view] | src/composed/value-bets-v2 |
/value-bets-v3/[view] | src/composed/value-bets-v3 |
Three generations, on purpose
All three are live. A change to the model is judged against the board it replaces rather than against memory, which is the only way to tell an improvement from a difference.
v2 and v3 take a [view] segment — raw-model-outputs, teams-model,
tracked, watchlist, maccas-settings — rather than a ?view= flag, so a
saved link keeps working when the default changes. The redirects in
next.config.js map the old query form onto it.
The URL is not the API's query
The two vocabularies differ, and there are eighteen of them: the address says
q, market, leagues, minOdds; the endpoint wants search, marketType,
uniqueTournamentId, minOdd.
That mapping used to be a useMemo over eighteen useQueryState values inside
the client component, which was fine until the server had to build the same
request. It now lives in its own module, deliberately free of nuqs — nuqs is
client-only, and importing a module that touches it from a Server Component
fails the build. It takes plain values in and returns the API's query out, so
both sides can call it.
This is the general shape of the fix
Any board whose data is read on the server and filtered in the browser needs its
URL-to-query mapping in a module neither side owns. super-sub-heroes/state.ts
carries a comment about the same build failure, from the other direction.
V2 is the biggest surface in the product
4,900 lines, fifty-nine data calls, and a hundred and forty-six values the markup reads. The seam between state and view is a hook, not a prop list: a hand-written list of a hundred and forty-six props would be longer than most components and would need editing twice for every change.
useValueBetsV2 owns every request, every parser and every derivation; the view
takes its return value whole and cannot reach the network. That is the boundary
the convention is about, whether it arrives as ten props or a hundred and
forty-six.