TheYard data flow
Pinch or Ctrl+scroll to zoom; the text is selectable.
Source
·
TheYard
TheYard data flow: a vehicle from a JSON file on disk to a card in the browser, and a bid back
TheYard data flow: a vehicle from a JSON file to a card in the browser, and a bid back
Every box is a file; the path under each title is where that step lives. Domain, Application, Infrastructure and Api are the projects under api/; render/ is the rendering service beside them.
The read path, top to bottom
The first four boxes run once at startup; the rest run for every request, and a page's first read runs on the rendering service.
The write path: a bid
A signed-in buyer, bids kept in the store; the domain decides.
The seed file
data/vehicles.json
The 200 records from the challenge, never modified. The Vehicle record they load into
lives with the other plain data shapes in api/TheYard.Data.
once, at startup
JsonFileVehicleSource
api/TheYard.Infrastructure/JsonFileSources.cs
Reads the seed once, at startup.
SyntheticVehicleSource
api/TheYard.Infrastructure/SyntheticVehicleSource.cs
Expands 200 to 100,000 deterministic variants. Each new id is hashed (FNV-1a,
api/TheYard.Domain/Fnv1a.cs) to vary the VIN, year, odometer, prices and bid state while
keeping the seed's make, model and trim mix.
InventoryService
api/TheYard.Application/InventoryService.cs
Applies each vehicle's photo gallery (api/TheYard.Domain/PhotoGallery.cs picks from the
pools in api/TheYard.Api/photo-manifest.json) and materializes the list plus an id index
once. The host awaits that load in api/TheYard.Api/Composition/Startup.cs before it
serves.
then, for every request
GET /api/vehicles
api/TheYard.Api/Endpoints/VehicleEndpoints.cs
api/TheYard.Api/VehicleQueryParams.cs binds and validates every parameter into a filter
and a sort. The clock is the server's (api/TheYard.Api/Clocks.cs): now, and the UTC
midnight that began the day, the same for every visitor.
Search, through Auction.Search
api/TheYard.Application/Auction.cs
1. Everybody's bids, then the room's, are laid over each vehicle (Auction.Overlay,
raising a price through api/TheYard.Domain/StandingRules.cs), so price bounds see the
figures the page shows.
2. Where: api/TheYard.Domain/VehicleFilter.cs
3. OrderBy: api/TheYard.Domain/VehicleOrdering.cs
4. Skip and Take for the page. Auction windows come from
api/TheYard.Domain/AuctionSchedule.cs, all in memory.
VehicleWire
api/TheYard.Api/VehicleWire.cs
Stamps the server-derived facts on each vehicle: auction_starts_at, auction_ends_at,
auction_status, min_next_bid. The endpoint answers { total, vehicles } in snake_case.
{ total, vehicles } as JSON
The rendering service, for a page
render/loaders.ts, render/render.ts
A page request (the bare path with its query) comes here from the edge, not to the API.
One loader per view reads what the address needs from the API above (for the inventory,
the listing with its facets), all at once under a 2.5 s deadline, then
src/app/entry-server.tsx draws the site with React's server renderer and the HTML leaves
with the first load, the JSON the reads answered, written beside #root. A read that
misses the deadline is left to the browser.
the page, drawn, with its first load
The fetch seam
src/lib/data.ts
In the browser, src/app/mount.tsx starts every hook from the first load the page
carries, so the first draw matches the server's and React takes the page over instead of
drawing it again. After that: debounces filter changes (500 ms), caches responses per
query string for five minutes (a hit skips the debounce) and aborts superseded requests.
The query string comes from src/lib/inventory.ts, the same serializer that feeds the
address bar.
App state and the address bar
src/app/hooks/useAddressBar.ts
Holds the page. Filters, sort, ?vehicle and ?view are mirrored into the URL, and Back
and Forward re-read it.
Cards, detail, bid panel
src/components/*
Format currency (src/lib/format.ts) and tick the countdowns from the server's window
(src/lib/auction.ts). No business math runs in the browser.
BidPanel
src/components/vehicle/BidPanel/BidPanel.tsx
Posts { amount } to POST /api/vehicles/{id}/bids through
src/lib/data.ts; buy now posts to /buy-now. Only a
signed-in buyer can.
POST
HandleBid
api/TheYard.Api/Endpoints/BidEndpoints.cs
Three questions in order: is this session on this store
(401 if not), does the vehicle exist (404 if not), does
the domain accept the action (400 with the reason if
not).
the Application ring
Auction.PlaceBidAsync
api/TheYard.Application/Auction.cs
Measures the bid against the room's standing price as
well as everybody's bids, so nobody retakes a lead below
the going rate.
the domain decides
BidRules
api/TheYard.Domain/BidRules.cs
The sole authority: the live window, the tiered minimum
increment, and the buy-now override (a bid at or above
buy_now_price wins outright at that price).
accepted, won, or rejected
BidService
api/TheYard.Application/BidService.cs
Under one gate: an accepted or won bid is written to the
store (Azure SQL Database or Cosmos DB, through the
IBidStore port) and then to memory, under the buyer's
account. The response carries the updated vehicle with a
fresh min_next_bid.
the updated vehicle
useBids
src/hooks/useBids.ts
Clears the query cache and refetches, so every list,
filter and total reflects the bid through the same read
path.
refetch, through the same read path
One rule shapes everything: derive, do not store. Windows, statuses, galleries and the 100,000 inventory are computed from stable ids, never persisted.
Source: docs/images/dataflow.svg in the repository, drawn by docs/images/dataflow.mjs and redrawn when a box moves.