One bid through the rings
Pinch or Ctrl+scroll to zoom; the text is selectable.
Source
·
TheYard
One bid through TheYard's rings: the endpoint asks Application, Application asks Domain, Domain decides, Application saves through the IBidStore port, an adapter writes the store, and the endpoint answers
One bid through the rings
Left to right is outside to inside. Solid arrows are calls the code makes in order; the dashed arrow is the one call that crosses outward, at runtime, through the port.
Outside: the host and the adapters
api/TheYard.Api and the two adapter projects
Application: the use cases and the port
api/TheYard.Application
Domain: the rules
api/TheYard.Domain
BidEndpoints.HandleBid
Endpoints/BidEndpoints.cs
POST /api/vehicles/{id}/bids, signed in.
Is this session on this store? If not, 401.
Does the vehicle exist (Auction.Find)? If not, 404.
Reads the server clock once: Clocks.Now().
Hands the vehicle, the amount and that clock in.
Writes the answer: 400 with the reason, or 200
with the bid and the vehicle as it now stands.
EfBidStore or CosmosBidStore
EfSources.cs and CosmosSources.cs
Each implements IBidStore against one store.
EF Core: one row per buyer per vehicle, in
Azure SQL Database or SQLite.
Cosmos DB SDK: one document in the buyer's partition.
Composition/StoreRegistration.cs picks which.
Auction.PlaceBidAsync
Auction.cs
The one class endpoints ask about the auction.
Passes the bid to the service that keeps bids.
BidService.PlaceBidAsync
BidService.Bidding.cs
Takes the gate: one bid at a time.
Folds everybody's bids into the vehicle, so the
rules see the price as it stands.
Asks Domain, then on yes writes the store first
and memory second.
IBidStore, the port
Ports.cs
Declared here, in the inner ring: the shape of
what Application needs, and nothing about SQL
or Cosmos DB.
LoadAsync, SaveAsync(userId, vehicleId, state),
ClearAsync(userId).
BidRules.ResolveBid
BidRules.cs
Sold to anybody already? Refused.
Live and at or above buy-now? Won,
at the buy-now price.
Not started, or ended? Refused.
Below the minimum next bid? Refused.
Otherwise accepted, as a BidOutcome.
No store, no web, no clock of its own.
Held by OnionTests:
Domain_never_reaches_the_disk_
the_network_or_the_clock
Endpoints_reach_the_auction_only_
through_the_Application_ring
1
2
3
4
5
6
runs it
implements
7
1
The endpoint asks Application, with the server clock as a value.
2
Auction hands the bid to BidService, which keeps everybody's bids.
3
BidService asks Domain whether the bid stands.
4
Domain answers with a BidOutcome and touches nothing else.
5
On yes, BidService saves through IBidStore, the port it owns.
6
The call reaches whichever adapter Composition wired in at startup.
7
The outcome travels back out and the endpoint writes the answer.
Source: docs/images/bid-walk.svg in the repository, drawn by docs/images/bid-walk.mjs and redrawn when the bid's path changes.