Auctions Canonical Write Path
This document traces the real auction write paths that exist today.
It does not describe desired architecture. It describes current code reality.
Labels:
VERIFIEDINFERREDUNVERIFIEDREALMIXEDUI-FIRSTMISSING
1. Durable Internal Auction Declaration Path
Status:
- Truth:
VERIFIED - System state:
REAL
This is the strongest real auction write path in the repo.
Flow A — create draft
- UI authoring starts in the auction declaration wizard.
- Evidence: apps/web/src/ui/auctions/announcement/AuctionAnnouncementWizard.tsx
- Mutation client: apps/web/src/ui/auctions/announcement/client.ts
createAuctionDeclarationDraft
- Next.js server route forwards the request to
svc-tenders. svc-tendersvalidates and authorizes the request.- Evidence: services/svc-tenders/src/server.ts
POST /admin/auctions/declarations/drafts - Validation: services/svc-tenders/src/validation.ts
createAuctionDeclarationDraftSchema
- Evidence: services/svc-tenders/src/server.ts
- Repository writes the declaration draft in a DB transaction.
- Evidence: services/svc-tenders/src/repository.ts
createAuctionDeclarationDraft - Writes:
auction_declarations- registry projection row in
auctionsviaupsertAuctionRegistryStateFromDeclaration
- Evidence: services/svc-tenders/src/repository.ts
- Read path back to UI:
- Internal admin read routes in
svc-tenders - Public reads eventually surface the projected
auctionsrow if state becomes public
- Internal admin read routes in
Flow B — update draft
- UI calls
updateAuctionDeclarationDraft. - Next route forwards to
PUT /admin/auctions/declarations/:id/draft. svc-tendersupdates:auction_declarationsauctionsprojection row- all inside the repository transaction
- Evidence: services/svc-tenders/src/repository.ts
updateAuctionDeclarationDraft
Flow C — mark ready
- UI calls
markAuctionDeclarationReady. - Next route forwards to
POST /admin/auctions/declarations/:id/mark-ready. svc-tenders:- validates permissions and readiness guards
- updates
auction_declarations.state - updates
auctions.state - inserts
auction_declaration_eventsrow withAUCTION_READY_FOR_ANNOUNCEMENT - Evidence: services/svc-tenders/src/server.ts
POST /admin/auctions/declarations/:id/mark-ready - Evidence: services/svc-tenders/src/repository.ts
markAuctionDeclarationReady,insertAuctionDeclarationEvent
Flow D — declare / announce
- UI calls
declareAuctionAnnouncement. - Next route forwards to
POST /admin/auctions/declarations/:id/declare. svc-tenders:- validates transition guard
- updates
auction_declarations.state = 'ANNOUNCED' - updates the
auctionsregistry projection row toANNOUNCED - inserts
auction_declaration_eventsrow withAUCTION_DECLARED - Evidence: services/svc-tenders/src/server.ts
POST /admin/auctions/declarations/:id/declare - Evidence: services/svc-tenders/src/repository.ts
declareAuction,upsertAuctionRegistryStateFromDeclaration,insertAuctionDeclarationEvent
Transaction boundary
VERIFIED
Inside repository methods, declaration state updates and registry projection updates happen inside one SQL transaction:
BEGIN- write declaration row
- upsert
auctionsrow - insert declaration event row where applicable
COMMIT
Evidence:
- services/svc-tenders/src/repository.ts
createAuctionDeclarationDraft - services/svc-tenders/src/repository.ts
updateAuctionDeclarationDraft - services/svc-tenders/src/repository.ts
markAuctionDeclarationReady - services/svc-tenders/src/repository.ts
declareAuction
Event / outbox reality
VERIFIED
Auction declaration transitions write to:
auction_declaration_events
I did not verify:
- auction declaration rows being relayed into Kafka
- an auction-specific outbox equivalent to
kes_outbox_events - auction-specific projection consumers downstream of Kafka
So the write path is durable and transactional, but auction eventing is currently best described as:
- DB event log:
REAL - Kafka/outbox propagation:
UNVERIFIEDfor auctions specifically
2. Durable Service-Side Settlement Path
Status:
- Truth:
VERIFIED - System state:
REAL
This is the strongest real post-award auction mutation found.
Flow
- Some service-side caller invokes
repository.settleAuction(auctionId, winner).- Evidence: services/svc-tenders/src/repository.ts
settleAuction
- Evidence: services/svc-tenders/src/repository.ts
- Repository transaction:
- locks
auctionsrow withFOR UPDATE - validates already-settled winner consistency
- generates or reuses
entitlement_id - writes
winner_json - writes
state = 'SETTLED' - mirrors
entitlement_idto linkedtendersrow when present
- locks
Reality limit
VERIFIED
I did not verify a public portal mutation path that reaches this method directly.
That means:
- settlement durability exists in the backend
- public user-facing winner selection / Buy Now / fulfillment UX is not yet wired into that durable path
3. Public Read Path
Status:
- Truth:
VERIFIED - System state:
MIXED
Canonical branch
- Web calls:
- apps/web/src/portal/api.ts
fetchAuctions - apps/web/src/portal/api.ts
fetchAuctionPortalDetail
- apps/web/src/portal/api.ts
- Gateway handles:
- Gateway first attempts canonical upstream read:
- services/api/src/auctions/gateway.ts
proxyAuctionsJson - response headers now mark:
x-kvary-source: gateway-upstream-auctions-servicex-kvary-durability: service-read
- services/api/src/auctions/gateway.ts
- Upstream canonical service:
- services/svc-tenders/src/server.ts
GET /auctions,GET /auctions/:id
- services/svc-tenders/src/server.ts
- Read model source:
auctions- joined
auction_declarations
Compatibility branch
If upstream read fails or returns 404, the gateway falls back to the local engine:
Compatibility responses are now explicitly marked:
x-kvary-source: gateway-local-enginex-kvary-durability: compatibility-local-engine
The gateway list fallback now also returns:
projectionHealthy: false
UI offline branch
If the web cannot reach the API at all, it falls back to portal mocks:
- apps/web/src/portal/api.ts
getMockAuctionSummaries,getMockAuctionPortalDetail
This is not canonical.
4. Public Bid / Buy Now / Fulfillment Path
Status:
- Truth:
VERIFIED - System state:
UI-FIRST
Bid submit
- User clicks
Place Bidin apps/web/src/portal/components/AuctionDetailClient.tsx handleBid()creates aLOCAL-*bid idappendSessionAuctionBid()writes bid state to browsersessionStorage
No durable service write occurs on the normal portal path.
Buy Now
- User clicks
Buy Now handleBuyNow()callsrecordSessionAuctionBuyNow()- browser
sessionStoragebecomes the effective state source
No durable service write occurs on the normal portal path.
Fulfillment / transport selection
- Winner-side fulfillment choices use:
AuctionDetailClientandTransportWorkspaceClientsubscribe to those session overlays
Again, no durable backend orchestration write occurs on the normal portal path.
5. Public Compatibility Action Routes
Status:
- Truth:
VERIFIED - System state:
MIXED
These routes still exist under the public gateway surface:
POST /api/v1/auctions/createPOST /api/v1/auctions/:id/announcePOST /api/v1/auctions/:id/openPOST /api/v1/auctions/:id/bidsPOST /api/v1/auctions/:id/closePOST /api/v1/auctions/:id/awardPOST /api/v1/auctions/:id/settle
Evidence:
These are not the canonical durable auction action backend. They execute against:
That engine uses:
- fixtures
- generated mocks
- gateway in-memory ledger state
This is compatibility behavior, not durable source-of-truth behavior.
6. Read Path Back To UI
Canonical read-back after internal declaration writes
VERIFIED
After durable declaration writes, read-back can happen through:
- internal admin auction routes in
svc-tenders - public
GET /auctionsandGET /auctions/:idonce the projected auction row is in a public state
The key bridge is:
- services/svc-tenders/src/repository.ts
upsertAuctionRegistryStateFromDeclaration
That method materializes declaration snapshots into the auctions registry table used by public reads.
Public action read-back today
VERIFIED
After public bid / Buy Now / fulfillment interaction, read-back is mostly local:
- list views use
overlayAuctionPortalItem() - detail view subscribes to session bid / buy-now / fulfillment / transport state
That is coherent UX, but not durable backend truth.
7. Final Truth
- Canonical durable auction writes exist for:
- declaration draft lifecycle
- announcement state transition
- settlement entitlement recording
- Canonical durable public auction action writes do not exist yet for:
- bidder portal bid submit
- bidder portal Buy Now
- bidder portal fulfillment confirmation
- pre-commit transport selection
- Gateway compatibility auction actions still exist, but they should not be described as the durable platform backend.