Building GigFlow: A Real-Time Freelance Marketplace with Secure Hiring Logic

Published: (January 16, 2026 at 01:35 AM EST)
3 min read
Source: Dev.to

Source: Dev.to

Introduction

Modern marketplaces aren’t just about CRUD APIs — they’re about correctness, trust, and real‑time feedback. In this post I walk through how I built GigFlow, a full‑stack freelance marketplace where clients can post jobs, freelancers can bid, and hiring happens atomically and in real time.

Project Focus

  • Secure authentication
  • Correct hiring logic
  • Preventing race conditions
  • Real‑time updates using Socket.io

GigFlow Overview

  • Any authenticated user can post a gig (client role)
  • Any user can bid on gigs (freelancer role)
  • A client can hire exactly one freelancer per gig; all other bids are automatically rejected
  • The hired freelancer receives a real‑time notification

Tech Stack

LayerTechnology
FrontendReact (Vite), Tailwind CSS, Context API, Socket.io client, Fetch API with credentials
BackendNode.js + Express, MongoDB + Mongoose, JWT authentication (HttpOnly cookies), Socket.io, MongoDB transactions
DeploymentFrontend on Vercel, Backend on Render, Database on MongoDB Atlas

Authentication

Authentication uses JWT stored in HttpOnly cookies, which:

  • Prevents access from JavaScript (XSS‑safe)
  • Works cleanly with credentials: "include"

Each request:

  1. Verifies the JWT
  2. Attaches the authenticated user to req.user

This enables a role‑less design: users can act as both client and freelancer without separate accounts.

Data Models

// User
{
  "name": "String",
  "email": "String",
  "password": "HashedString"
}
// Gig
{
  "title": "String",
  "description": "String",
  "budget": "Number",
  "ownerId": "ObjectId",
  "status": "open | assigned",
  "assignedTo": "ObjectId | null"
}
// Bid
{
  "gigId": "ObjectId",
  "freelancerId": "ObjectId",
  "message": "String",
  "price": "Number",
  "status": "pending | hired | rejected"
}

Hiring Logic (Core Challenge)

Rule: Only one freelancer can be hired for a gig — ever.

Edge Case

Two clients (or two browser tabs) click Hire at the same time. Without protection, both bids could be marked as hired.

Solution: MongoDB Transaction

  1. Start a session
  2. Check if the gig is still open
  3. Update gig → set status to assigned and assignedTo to the selected freelancer
  4. Mark selected bidhired
  5. Mark all other bidsrejected
  6. Commit transaction

If any step fails, the transaction rolls back, guaranteeing:

  • Exactly one hired freelancer
  • No partial or inconsistent state

Real‑Time Notification

When a freelancer is hired:

  1. The backend emits a hired event to that freelancer’s Socket.io room.
  2. The freelancer’s dashboard updates instantly—no polling, no page refresh.

User Flow

  1. Create gig → gig status open
  2. View bids → freelancers submit bids
  3. Click Hire → gig becomes assigned
  4. **Freelancer receives real‑time hire notification`

State is kept minimal and predictable using the Context API.

Deployment Considerations

  • Set all required environment variables explicitly.
  • Configure CORS to allow the deployed frontend domain; Socket.io shares the same CORS settings as Express.
  • API base URL must point to the deployed backend.
  • Fetch requests must include credentials.

Key pillars

  • Correct API design
  • Secure authentication
  • Transactional integrity
  • Real‑time communication
  • Production deployment awareness

Live Demo & Source Code

  • Live App:
  • GitHub Repository:

Final Thoughts

The hardest part of full‑stack development isn’t writing code — it’s ensuring the system behaves correctly when multiple actions occur simultaneously. GigFlow was built with that principle in mind.

Back to Blog

Related posts

Read more »

Rapg: TUI-based Secret Manager

We've all been there. You join a new project, and the first thing you hear is: > 'Check the pinned message in Slack for the .env file.' Or you have several .env...

Technology is an Enabler, not a Saviour

Why clarity of thinking matters more than the tools you use Technology is often treated as a magic switch—flip it on, and everything improves. New software, pl...