DEV Community

Cover image for πŸͺ™ CoinFlow β€” I Built a Full-Stack Micro-Tasking Platform with GitHub Copilot.
Redwan Shahriar Shubho
Redwan Shahriar Shubho

Posted on

πŸͺ™ CoinFlow β€” I Built a Full-Stack Micro-Tasking Platform with GitHub Copilot.

GitHub β€œFinish-Up-A-Thon” Challenge Submission

πŸ’‘ What I Built

CoinFlow is a full-stack MERN micro-tasking platform with a real coin economy, Stripe payments, Firebase authentication, and a three-role system for Workers, Buyers, and Admins.

Live Demo: coin-flow-peach.vercel.app
GitHub Repo: github.com/redwanshahriarshubho/CoinFlow


πŸ“Έ Before & After

❌ Before β€” No Backend At All

Empty server folder - no index.js

The entire server/ folder had no index.js. Every API call failed with network errors. The frontend looked beautiful but nothing worked.

Firebase error - app completely broken

βœ… After β€” Fully Working Live App

Worker Dashboard fully working with 10 coins

Complete project - server/index.js and .env configured


πŸ› οΈ Tech Stack

Frontend: React 19, Vite 8, React Router 7, TanStack Query v5, Firebase v12, Stripe.js, Swiper, React Hook Form

Backend: Node.js, Express 5, MongoDB (native driver), JWT, Stripe SDK

Infrastructure: Vercel (frontend), Render (backend), MongoDB Atlas, imgBB


🧩 How It Works β€” The Three Roles

πŸ‘· Worker

Workers join the platform and get 10 free coins on signup. They browse available tasks, submit completed work, and get paid instantly when approved. Once they hit 200 coins ($10), they can withdraw via bKash, Nagad, Rocket, or Bank Transfer.

🏒 Buyer

Buyers post tasks with a coin reward per worker β€” the total cost is deducted when the task goes live. They review submissions through a dashboard and approve or reject each one. Unused coins are refunded automatically if a task is deleted.

πŸ” Admin

Admins see platform-wide stats, manage all users, moderate any task, and approve worker withdrawal requests.


πŸ’° The Coin Economy

Action Coins
Register as Worker +10 free
Register as Buyer +50 free
Post a task -(workers Γ— coins_per_worker)
Submission approved +payable_amount to worker
Delete task (unused slots) +refund to buyer
Withdrawal minimum 200 coins ($10)
Exchange rate 20 coins = $1 USD

One design decision I'm proud of: when a submission is rejected, the task's required_workers count is incremented back by 1 so another worker can claim that slot. Without this, a single rejection would permanently block an open position.

app.patch("/submissions/:id/reject", verifyToken, verifyBuyer, async (req, res) => {
  await submissions.updateOne(
    { _id: new ObjectId(req.params.id) },
    { $set: { status: "rejected" } }
  );
  await tasks.updateOne(
    { _id: new ObjectId(sub.task_id) },
    { $inc: { required_workers: 1 } }
  );
  await notifications.insertOne({
    recipient_email: sub.worker_email,
    message: `Your submission for "${sub.task_title}" was rejected. Keep going!`,
    actionRoute: "/dashboard/task-list",
    time: new Date(), read: false,
  });
});
Enter fullscreen mode Exit fullscreen mode

πŸ€– How GitHub Copilot Helped

Architectural Review

I used Copilot as a sounding board throughout. Describing the coin economy rules in plain English and asking "what could go wrong here?" surfaced edge cases before they became bugs.

Security Hardening

Copilot flagged an IDOR vulnerability β€” I wasn't verifying that the buyer making a request actually owned the task. It suggested adding buyer_email: req.user.email to every MongoDB mutation query:

await tasks.updateOne(
  { _id: new ObjectId(req.params.id), buyer_email: req.user.email },
  { $set: { task_title, task_detail, submission_info } }
);
Enter fullscreen mode Exit fullscreen mode

MongoDB Index Design

Copilot reviewed my schema and recommended the full index set:

await users.createIndex({ email: 1 }, { unique: true });
await tasks.createIndex({ buyer_email: 1 });
await submissions.createIndex({ worker_email: 1 });
await notifications.createIndex({ recipient_email: 1, time: -1 });
Enter fullscreen mode Exit fullscreen mode

Duplicate Submission Guard

const dup = await submissions.findOne({ task_id, worker_email });
if (dup) return res.status(400).json({ message: "You already submitted this task" });
Enter fullscreen mode Exit fullscreen mode

✨ Features Shipped

Worker: Browse tasks, full detail page, submit work, paginated history, real-time notifications, withdrawal form

Buyer: Post tasks with live cost preview, review submissions via modal, approve/reject with instant worker payout, edit/delete with refund, purchase coins via Stripe, payment history

Admin: Platform stats, user management, task moderation, withdrawal approval queue

System: JWT + Firebase auth (Email + Google OAuth), role-based route guards, imgBB image upload, fully responsive UI


πŸš€ Try It Live

coin-flow-peach.vercel.app

Register as a Worker to browse and complete tasks, or as a Buyer to post tasks and review submissions.
Test Stripe with card 4242 4242 4242 4242 / any future date / any CVC.


Built with React, Node.js, MongoDB, Stripe, and Firebase. GitHub Copilot helped me think through security, edge cases, and performance throughout the build.

Top comments (0)