Play is a monorepo that powers the Play Dodon quiz experience, pairing a Vite/React frontend with an Express/Prisma backend that is backed by PostgreSQL and curated quiz data.
The frontend is a modern React+Vite SPA that calls the backend API to render featured challenges, roll up leaderboard data, and keep the experience responsive with Tailwind/TanStack utilities. The backend exposes a set of quiz and leaderboard endpoints, seeds data via Prisma, and ships Swagger docs for quick exploration.
- Frontend: Vite + React + TailwindCSS handles routing, theming, and responsive layout.
- Backend: Express server with CORS protection,
swagger-jsdoc+swagger-ui-express, and Prisma for data and schema migrations. - Persistence: PostgreSQL (connection string lives in
.env) with Prisma migrations (npx prisma migrate) and seed helpers.
- Install dependencies from the monorepo root:
npm install
- Copy the root
.env(already tracked) and adjust any secrets/hostnames for your environment. - Make sure your PostgreSQL instance is reachable and
DATABASE_URLpoints to a writable database. - If you need fresh data, run Prisma commands from
apps/backend(e.g.,npm --workspace apps/backend run migrate:deploy).
- Start the backend server and watch files:
The server listens on
npm run dev:backend
http://localhost:6008/apiby default. - Start the frontend dev server at the same time:
Vite will serve the UI on
npm run dev:frontend
http://localhost:6009and proxy API requests to the backend.
docker compose up -d also starts:
gateway(nginx,infrastructure/gateway/nginx.conf): one entry point, with/api/going to the backend and everything else to the frontend. On the LAN it ishttp://<host>:6010(GATEWAY_PORT).tunnel(cloudflared): publishes the gateway athttps://play.dodon.in, using the tunnel token in.envasCLOUDFLARE_TUNNEL_TOKEN. If the token is empty, the tunnel exits and the rest of the stack keeps running.
The tunnel is play (created with cloudflared tunnel create play, DNS routed with cloudflared tunnel route dns play play.dodon.in). To set up a new machine, get its token with cloudflared tunnel token play and put it in .env. Run only one machine per tunnel, because two machines on the same tunnel would split its traffic.
GET /api/health– health check.GET /api/quizzes– paginated quiz catalog with optionalfeatured,category, andlimitfilters.GET /api/quizzes/:slug/leaderboard– top 10 leaderboard for a quiz.POST /api/quizzes/:slug/leaderboard– submit a leaderboard entry (requires username, score, completion time).GET /api/leaderboard– aggregate leaderboard across users with pagination, category, challenge, and period filters.POST /api/admin/quizzes/upload– upload the Excel workbook (see admin tooling) and seed quiz/question data.- Swagger docs live at
http://localhost:6008/api/docsfor complete schema/response details.
The backend ships with Excel-driven import helpers:
- Download the template via
GET /api/admin/quiz-template(protected byADMIN_PASSWORD). - Fill out the Quiz and Questions sheets (required headers are enforced).
- POST the workbook to
/api/admin/quizzes/uploadwith thex-admin-passwordheader orpasswordbody field. Useforceto overwrite existing slugs.
A standalone script (apps/backend/scripts/importQuizFromExcel.js) also reuses the same import logic if you prefer CLI-driven seeds.
This project is released under the MIT License.
