Auction Detail Controller Boundary
Purpose
This note documents the Sprint 05 boundary cleanup for the auction detail flow in apps/web.
The goal of this layer is not to make bidder mutations look durable. The goal is to make the current truth model explicit in code:
canonicalReadremains the visible source for auction detail/list reads- bidder mutations remain
UI-FIRSTand compatibility-backed - session overlays remain explicit
- the future durable mutation seam remains visible and intentionally separate
VERIFIED module structure
Top-level entry:
Controller / view-model layer:
apps/web/src/portal/components/auctionDetail/useAuctionDetailController.tsxapps/web/src/portal/components/auctionDetail/useAuctionSessionOverlays.tsapps/web/src/portal/components/auctionDetail/useAuctionBidderIdentity.tsapps/web/src/portal/components/auctionDetail/compatibilityActionAdapter.ts
Presentation modules from Sprint 04:
apps/web/src/portal/components/auctionDetail/AuctionReadPresentation.tsxapps/web/src/portal/components/auctionDetail/AuctionDeliveryOptionsPanel.tsxapps/web/src/portal/components/auctionDetail/AuctionBidActionCluster.tsxapps/web/src/portal/components/auctionDetail/AuctionBuyNowAction.tsxapps/web/src/portal/components/auctionDetail/AuctionFulfillmentPanel.tsxapps/web/src/portal/components/auctionDetail/AuctionCompatibilityNotice.tsx
Related cross-sprint boundaries:
apps/web/src/ui/auctions/canonicalRead/portalReadBoundary.tsapps/web/src/ui/auctions/compatibility/sessionAuctionMutationPort.tsapps/web/src/ui/auctions/futureDurable/auctionMutationPort.tsapps/web/src/ui/auctions/session/bidOverlay.tsapps/web/src/ui/auctions/session/fulfillmentOverlay.tsapps/web/src/ui/auctions/session/transportSelectionOverlay.ts
Responsibility ownership
AuctionDetailClient.tsx
Status: MIXED, but intentionally thin after Sprint 05.
Owns:
- assembly of the page-level cards
- wiring controller outputs into presentation components
- no direct session storage reads
- no direct bidder mutation persistence logic
It is now a shell/orchestrator entry point, not the place where eligibility, overlay merge, or compatibility write logic is implemented.
useAuctionDetailController.tsx
Status: UI-FIRST controller/view-model layer.
Owns:
- derived auction detail view-model construction
- action availability and gating decisions
- bid guidance / buy-now state shaping
- delivery option render-state shaping
- fulfillment state shaping
- degraded-state normalization for the action surface
- compatibility-backed action handler wiring
It is intentionally the place where current truth is concentrated:
- reads come in through
detail - session overlays are merged in
- compatibility mutation calls are issued explicitly
- future durable mutation is not silently implied
useAuctionSessionOverlays.ts
Status: UI-FIRST.
Owns:
- hydration guard for client-only overlay use
- subscription to session-backed bid overlays
- subscription to session-backed buy-now state
- subscription to session-backed transport pre-commit selection
- subscription to session-backed fulfillment intent
This is the explicit session/local merge layer for the detail controller.
useAuctionBidderIdentity.ts
Status: MIXED.
Owns:
- current-session user resolution via
useCurrentUser() - stakeholder-context fetch via
getMyStakeholderContext() - manual dev bidder override handling when enabled
- bidder identity normalization for the action surface
This hook keeps session/account/stakeholder identity shaping out of the visual detail component.
compatibilityActionAdapter.ts
Status: UI-FIRST.
Owns:
- explicit adapter from detail controller to the compatibility mutation port
It currently maps to:
This is intentionally named as compatibility, not service, gateway, or API mutation.
What moved out of AuctionDetailClient
Sprint 05 extracted these responsibilities from the top-level component:
- session overlay subscription and hydration handling
- bidder identity resolution and stakeholder-context usage
- compatibility-backed action wiring
- large derived state and view-model construction
- top-level action gating and participation normalization
This means new engineers and future AI agents no longer need to read a single giant client component to find:
- where bid overlays come from
- how bidder identity is chosen
- where Buy Now or bid submission is wired
- how delivery and fulfillment action states are computed
What still remains intentionally centralized
Inside useAuctionDetailController.tsx:
- top-level derived controller state
- action handlers that coordinate multiple view-model concerns
- cross-panel logic where bid/buy/delivery/fulfillment need the same derived state
Inside AuctionDetailClient.tsx:
- page-level composition
- card ordering and top-level render branches
This centralization is intentional for now. Splitting further before a real durable mutation path exists would risk scattering the same UI-first truth across too many modules.
Truth model after Sprint 05
Canonical read
Status: REAL / MIXED depending on upstream source, unchanged by this sprint.
- auction detail/list reads still come through the canonical read boundary
- this sprint did not invent a new read source
Compatibility mutation
Status: UI-FIRST.
- bid submit
- Buy Now
- transport pre-commit selection
- fulfillment advancement
These still flow through the compatibility adapter to the session-backed mutation port.
Session overlays
Status: UI-FIRST.
- bid overlays
- buy-now overlays
- transport selection overlays
- fulfillment intent overlays
These remain explicit and isolated under ui/auctions/session/*.
Future durable mutation seam
Status: SHELL.
The durable seam still exists under:
Sprint 05 did not implement it. The controller boundary now makes the eventual swap point much clearer.
What future durable mutation work should attach to
When a real bidder mutation backend is implemented later, the intended change point is:
- keep
AuctionDetailClient.tsxunchanged or nearly unchanged - keep presentation modules unchanged
- replace the compatibility adapter wiring inside:
- optionally update
useAuctionSessionOverlays.tsif durable optimistic/revalidation behavior replaces session overlays
That is the main value of this sprint: the swap point is now explicit instead of buried inside a very large UI component.