BidPulse is a full-stack, real-time auction platform for verified buying and selling. Sellers submit listings, admins review them, bidders register before the session opens, and winners complete payment while BidPulse manages the post-auction flow.
- Frontend: React 19, Vite, Redux Toolkit, React Router, Socket.IO client
- Backend: Express 5, MongoDB with Mongoose, Socket.IO
- Payments: Stripe
- Media: Cloudinary
- Email: Brevo, Resend, or SMTP fallback
- Bot protection: Cloudflare Turnstile
- A user signs up with name, email, password, and Turnstile verification.
- The new account is created but is not logged in automatically.
- The user signs in through the regular login page.
- After login, regular users are taken to the profile page.
- The user completes profile verification with identity details and a profile picture.
- Verification is finalized through either OTP or an email link sent to the user's primary email.
- Only verified users can register for auctions, place bids, or create listings.
- Sellers submit listings, admins approve or reject them, and approved listings move into the future auction pipeline.
- Bidders register before the registration window closes, then live bidding begins.
- The winner pays, BidPulse manages shipping, and the winner confirms product receipt to close the lifecycle.
- User-specific notification system with bell popover and full notifications page
- Separate admin login page removed; admin credentials work through the regular login page
- Turnstile protection on sign up, login, and create-auction flows
- Profile verification moved out of sign-up and into the profile page after login
- Profile verification supports:
- Date of birth with 18+ enforcement
- Country
- Primary contact
- Optional emergency contact
- NID or passport number
- Profile picture upload
- OTP or verification-link completion
- Dynamic social profile links in account editing
- Payment reconciliation helpers to reduce Stripe/webhook race issues
- Automated promotional and birthday email system
flowchart LR
UI[React + Vite] --> API[Express API]
UI <--> WS[Socket.IO]
API <--> WS
API --> DB[(MongoDB)]
API --> STRIPE[Stripe]
API --> CLOUD[Cloudinary]
API --> MAIL[Brevo / Resend / SMTP]
API --> TURNSTILE[Cloudflare Turnstile]
- Seller creates a listing request.
- Admin reviews the request.
- If approved, the listing becomes a future auction.
- Bidders register during the registration window.
- If no one registers, the seller can withdraw or relist lower.
- If one bidder registers, that bidder can win at the configured starting logic.
- If multiple bidders register, live turn-based bidding begins.
- The winner completes Stripe checkout.
- BidPulse moves the order into shipping.
- The winner confirms receipt and the auction closes.
POST /api/auth/register- Creates a new account
- Requires Turnstile
- Does not auto-login
POST /api/auth/login- Handles both normal users and admin credentials
- Requires Turnstile
POST /api/auth/profile-verification/start- Starts profile verification
- Accepts OTP or link method
- Uploads the profile picture as part of the flow
POST /api/auth/profile-verification/verify-otp- Completes verification with OTP
GET /api/auth/profile-verification/verify-link/:token- Completes verification with email link
Legacy email-verification-at-signup endpoints still exist in the router, but they now return 410 and are no longer part of the intended flow.
- Bell icon opens a popover instead of redirecting immediately
- Popover shows up to 10 notifications
- Unread notifications are shown first in the bell popover
- The full notifications page shows all notifications strictly by time and date
- Notifications are scoped to the signed-in user and no longer leak across accounts on the same device
Realtime delivery uses Socket.IO rooms such as:
user:<id>role:admin
BidPulse uses a shared email service and template layer:
backend/utils/emailService.jsbackend/utils/emailTemplates.js
Delivery priority:
- Brevo
- Resend
- SMTP via Nodemailer
- Profile verification OTP
- Profile verification link
- Profile verified confirmation
- Password reset
- Support ticket creation and status updates
- Listing submitted, approved, disapproved
- Auction winner and participant outcome updates
- Payment receipt
- Shipping started
- Seller payout updates
- Funds released
- Payment failed
- Product received confirmation
- Sent on the
5thand25thof every month - The same month's campaign is used for both sends
- Sent to all users with an email address
- verified
- unverified
- banned
- active
- Tracked by
PromotionalEmailLog - Manual trigger endpoint:
POST /api/admin/promotional/trigger- accepts
month,year,dayOfMonth,dryRun, andforceSend
- Sent daily to verified users whose date of birth matches the current day
- Tracked by
BirthdayEmailLog - Sent once per user per year
UserAuctionSupportTicketPromotionalEmailLogBirthdayEmailLog
POST /api/auth/registerPOST /api/auth/loginGET /api/auth/meGET /api/auth/activityPUT /api/auth/updatedetailsDELETE /api/auth/deleteaccountPOST /api/auth/avatar/uploadPOST /api/auth/profile-verification/startPOST /api/auth/profile-verification/verify-otpGET /api/auth/profile-verification/verify-link/:tokenGET /api/auth/export-dataPOST /api/auth/forgotpasswordPUT /api/auth/resetpassword/:resetToken
GET /api/auctionsGET /api/auctions/summary/statsGET /api/auctions/:idPOST /api/auctionsPUT /api/auctions/:idDELETE /api/auctions/:idPOST /api/auctions/:id/registerPOST /api/auctions/:id/bidPOST /api/auctions/:id/give-upPOST /api/auctions/:id/no-registration-decision
POST /api/payment/checkout/:auctionIdPOST /api/payment/create-checkout-session/:auctionIdPOST /api/payment/confirm-successPOST /api/payment/reconcile/:auctionIdPOST /api/payment/confirm-received/:auctionIdPOST /api/payment/release/:auctionIdPOST /api/webhook
GET /api/admin/statsGET /api/admin/usersGET /api/admin/users/:id/historyPUT /api/admin/users/ban/:idDELETE /api/admin/users/:idGET /api/admin/auctionsDELETE /api/admin/auctions/:idPUT /api/admin/auctions/:id/approvePUT /api/admin/auctions/:id/disapprovePOST /api/admin/test-emailPOST /api/admin/promotional/trigger
POST /api/support/ticketsGET /api/support/ticketsPUT /api/support/tickets/:id
NODE_ENV=development
PORT=5000
MONGO_URI=...
MONGO_MAX_POOL_SIZE=20
MONGO_SERVER_SELECTION_TIMEOUT_MS=10000
MONGO_SOCKET_TIMEOUT_MS=45000
JWT_SECRET=...
JWT_EXPIRE=30d
CLIENT_URL=http://localhost:5173
CLIENT_APP_URL=http://localhost:5173
CORS_ORIGIN=http://localhost:5173
CORS_ORIGINS=http://localhost:5173
ADMIN_EMAIL=...
ADMIN_PASS=...
SUPPORT_EMAIL=...
TURNSTILE_SECRET_KEY=...
STRIPE_SECRET_KEY=...
STRIPE_WEBHOOK_SECRET=...
CLOUDINARY_CLOUD_NAME=...
CLOUDINARY_API_KEY=...
CLOUDINARY_API_SECRET=...
CLOUDINARY_FOLDER=BidPulse
PROMOTIONAL_EMAIL_TIMEZONE=UTC
BREVO_API_KEY=...
BREVO_SENDER_EMAIL=...
BREVO_SENDER_NAME=BidPulse Support
BREVO_API_URL=https://api.brevo.com/v3/smtp/email
BREVO_TIMEOUT_MS=15000
RESEND_API_KEY=...
RESEND_FROM_EMAIL=...
RESEND_API_URL=https://api.resend.com/emails
RESEND_TIMEOUT_MS=15000
SMTP_HOST=...
SMTP_PORT=587
SMTP_SECURE=false
SMTP_FAMILY=4
SMTP_CONNECTION_TIMEOUT_MS=10000
SMTP_GREETING_TIMEOUT_MS=10000
SMTP_SOCKET_TIMEOUT_MS=15000
EMAIL_SERVICE=gmail
EMAIL_USERNAME=...
EMAIL_PASSWORD=...
EMAIL_USER=...
EMAIL_PASS=...VITE_API_URL=http://localhost:5000/api
VITE_SOCKET_URL=http://localhost:5000
VITE_TURNSTILE_SITE_KEY=...cd backend
npm install
npm run devcd frontend
npm install
npm run devcd frontend
npm run build- If your MongoDB already has the older unique index for promotional emails on
(user, year, month), it should be replaced with the new(user, year, month, dayOfMonth)index so the 5th and 25th sends can coexist correctly. - Socket connections are used for realtime auction and notification updates.
- The project currently has no dedicated automated test suite configured in
package.json.
MIT