Bidazk
Co-founder & Full-Stack Engineer
Marketplace · Since 2025 · In development
Bidazk inverts the usual marketplace flow. Instead of browsing listings, a buyer describes the job and vendors compete for it. I co-founded it and own the full stack. The interesting engineering problem is not the bidding; it's that a request moves through six states with different people acting at each one, and every transition has to be both enforced and reversible.
The problem
Buyers do not know what a job should cost, and vendors waste time quoting for work they were never going to win. Both sides need structured competition with a clear record of what was agreed.
Architecture
- Client
- Next.js App Router. Separate buyer and vendor surfaces built from one shared component library, so a change to the bid card ships to both at once.
- State
- Server-rendered request and bid state; optimistic updates on the bid submission path so a vendor sees their bid land immediately.
- API
- REST endpoints for the request lifecycle, with server actions handling bid placement, acceptance, and withdrawal.
- Data
- PostgreSQL via Prisma. Requests, bids, and awards are separate tables with the state transition recorded as its own row, so the history of a job is queryable rather than overwritten.
- Auth
- Session auth with distinct buyer and vendor roles; vendor accounts gated behind a verification step before they can bid.
- Infra
- Deployed on Vercel with a managed Postgres instance.
Decisions
A request is a state machine, not a status column
Draft, open, bidding, awarded, in progress, closed. Each transition is triggered by a different actor and some can be reversed. Encoding this as an explicit set of allowed transitions, rather than a status string anyone can set, made illegal states unrepresentable and gave the audit trail for free.
Vendors should not see each other's numbers
Exposing competing bid amounts turns the marketplace into a race to the bottom and punishes the vendor who quotes honestly first. Bids are sealed until the buyer awards, which meant the read path had to be scoped per-actor at the query layer rather than hidden in the interface.
Two products, one codebase
Buyer and vendor experiences diverge enough to feel like separate apps, but splitting them would have doubled the surface to maintain for a two-person team. One component library with role-scoped routes kept the shipping velocity that a co-founded product actually needs.
Outcomes
- Request lifecycle enforced as an explicit state machine with a queryable transition history
- Sealed-bid model implemented with per-actor scoping at the data layer
- Buyer and vendor surfaces maintained from a single shared component library
Built with
- Next.js
- TypeScript
- Node.js
- Prisma
- PostgreSQL
- Tailwind CSS
- Radix UI