Product architecture
How BidBosna works
A transparent look at our auction engine, bidding rules, notification fan-out, and commission logic.
End-to-end auction flow
Seller lists item
→
Browse & watch
→
Place bid
→
Bid validated
→
Outbid fan-out
→
Auction closes
→
Winner + payout
Authentication
- Email + password
- Role-based access (Bidder, Seller, Admin)
- Session via signed JWT (15m) + refresh
Bidding engine
- Validates increment ≥ admin-set minimum
- Rejects seller self-bid
- Atomic update + bid history append
- WebSocket fan-out to viewers
Notifications
- Outbid, won, lost, ending soon, new bid
- In-app + email channels
- Queue-backed with retries
Data layer
- PostgreSQL primary
- Redis for live bid state
- S3-compatible image storage
Admin controls
- Suspend/delete users
- Remove listings
- Tune commission, increments, durations
Performance
- Edge cache for browse pages
- Realtime bid updates < 250ms
- CDN-delivered images
Bidding rules engine
Bid validation pipeline
- 1Authenticate user and load auction by ID
- 2Reject if auction.status ≠ active OR auction.endsAt ≤ now
- 3Reject if bidder.id == seller.id
- 4Reject if amount < currentBid + minIncrement
- 5Begin transaction → append bid → update currentBid
- 6Publish outbid event for previous leader
- 7Publish new_bid event to seller + viewers
- 8Commit + return updated auction snapshot
Auction closure
when (auction.endsAt reached):
IF bids.length == 0:
auction.status = "ended_no_sale"
ELSE:
winner = bids[0].user // highest
auction.status = "ended"
commission = winner.amount
* settings.commissionPct
/ 100
payouts.create({
seller: auction.seller,
gross: winner.amount,
fee: commission,
net: winner.amount - commission
})
notify(winner, "won")
notify(seller, "sold")
notify(losers, "lost")Commission model
Default fee
7%
Adjustable by admin
Range
5–10%
Recommended band
Applied
On close
Calculated atomically