About
Assessments that respect everyone's time
DevBench is a developer assessment platform that keeps writing, taking and reviewing tests in one place.
Our mission
Make technical hiring simple and fair
Hiring teams often stitch together spreadsheets, email threads and separate testing tools. Candidates juggle links and deadlines. DevBench puts the whole flow in one workspace: build a problem, assemble an assessment, invite a candidate and review the result.
Every invitation costs one credit and you only pay for what you use, so small teams can start with a single candidate.
- Company portalOwners, assessment creators and evaluators build problems and assessments, send invitations and review results.
- Candidate portalCandidates accept invitations, take timed assessments and keep a record of their attempts.
- Admin portalPlatform admins manage companies and candidates and keep an audit trail of important actions.
Architecture
How a request moves through DevBench
A Next.js front end in front of an Express API, with each outside service doing one job.
Browser
React 19 + TanStack Query · httpOnly auth cookies
Next.js 16
Pages + role guard (proxy.ts) · /api/v1 → backend rewrite
Express 5 API
Zod validation, JWT auth · Rate limits, audit log
PostgreSQL
Prisma 7
Upstash Redis
Sessions, OTPs, cache
Stripe
Checkout + webhook
SMTP
Codes and emails
Cloudinary
File uploads
Engineering decisions
The details that keep it correct
Small choices that stop real bugs: race conditions, replayed webhooks and stale sessions. Each links to the code.
- Credits can't go negativeSending an invitation takes a credit with one conditional update (only when the balance is above zero) inside a transaction, so two invitations racing for the last credit can't both succeed.invitation.service.ts
- One live refresh token per userRefresh tokens are hashed and stored in Redis. Every refresh replaces the stored hash, so an older token stops working at once.session.ts
- Expiry without a background jobEvery attempt request checks the deadline first. If it has passed, the attempt is graded and submitted on the spot, so nothing depends on a cron job.attempt.util.ts
- Company scoping in one placeTwo small helpers decide which company's data a caller may touch. Services build their queries from them, and only admins can read across companies.scoping.ts
- Stripe retries can't double-creditA payment is marked as succeeded with a conditional update, so when Stripe delivers the same webhook twice, the credits are only added once.payment.util.ts
- Silent session refreshThe frontend API client retries once after a 401, and requests that fail at the same moment share a single refresh call instead of stampeding.apiClient.ts
Built with
A modern full stack
Frontend
- Next.js 16 (App Router)
- React 19 + React Compiler
- Tailwind CSS 4
- shadcn/ui on Base UI
- TanStack Query and Form
- Zustand
- Motion
- three.js (React Three Fiber)
- Recharts
- Monaco Editor
Backend
- Express 5
- TypeScript
- Prisma 7
- Zod
- JWT in httpOnly cookies
- Nodemailer + EJS
- Multer
Infrastructure
- PostgreSQL
- Upstash Redis
- Stripe
- Cloudinary
- Vercel
Run your first assessment in five minutes
Create a free account, buy credits when you need them and invite your first candidate today.