A full-stack React + Vite + Express + MongoDB app with gamified learning:
- Learning Hub for starting challenges and uploading task files
- Admin Panel for verifying submissions and awarding water drops
- Leaderboard powered by database stats (drops, lessons, streak)
- Dashboard and Garden showing user progress (DB-backed)
- Frontend: React 18, Vite, TypeScript, TailwindCSS
- Backend: Node.js, Express, Mongoose, Socket.io
- Auth: Signed HTTP-only cookies (JWT)
- File uploads: multer to local
uploads/ - DB: MongoDB (Atlas or local)
- Node.js 18+
- MongoDB connection string
- Install dependencies
npm install- Configure environment
- The server uses
process.env.JWT_SECRET(falls back to a dev default). - Mongo URI is currently configured directly in
server/server.js. Replace with your own if needed.
- Run dev servers (concurrently runs client and API)
npm run dev- Frontend: http://localhost:5173
- API: http://localhost:4000
Vite proxy forwards /api/* to the API.
- Register:
POST /api/auth/register - Login:
POST /api/auth/login - Logout:
POST /api/auth/logout - Session:
GET /api/auth/me
- Model:
LeaderboardStat(per user)- fields:
userId,name,drops,lessonsCompleted,streak
- fields:
- API:
GET /api/leaderboard?by=drops|lessons|streak&limit=50 - User stats:
GET /api/me/leaderboard,POST /api/me/leaderboard(increment user’s stats) - Frontend page:
src/pages/Leaderboard.tsx(fetches from API)
- Start sets UI state to “Started”
- Upload uses multipart to send files:
POST /api/challenges/:id/upload(field:file, body:challengeTitle)- Files are stored in
uploads/and served at/uploads/<filename>
- Flash message “Task uploaded” shown on success
- Existing submissions are loaded on mount via
GET /api/me/submissionsto persist UI state
- List submissions by status:
GET /api/admin/submissions?status=submitted|approved|rejected - Verify:
POST /api/admin/submissions/:id/verifywith{ approve: boolean, dropsAward: number }- On approval, increments
LeaderboardStat.dropsfor that user - “Open file” link available if a file was uploaded
- On approval, increments
- Admin endpoints require auth + role
admin
UserContextloads user’s stats from/api/me/leaderboardand refreshes on window focus + every 15s- Dashboard and Garden read from
useUser().stats - Garden classic UI adapter:
src/pages/GardenClassic.tsx(renders old UI using DB-backed stats)
server/server.js– Express server, schemas, routessrc/context/AuthContext.tsx– auth statesrc/context/UserContext.tsx– DB-backed user stats and helperssrc/pages/Leaderboard.tsx– leaderboard pagesrc/components/LearningHub.tsx– challenges and upload flowsrc/pages/AdminPanel.tsx– submission moderation and awardingsrc/pages/GardenClassic.tsx– adapter for classic Garden UIuploads/– uploaded files (served at/uploads)
- Seed demo leaderboard data (automatic on first run): Included in server start.
- Make a user admin: Register user with email starting
admin@or update role in DB. - Change Mongo URI: Edit
mongoUriinserver/server.js.
- File storage is local for development; switch to cloud storage for production.
- JWT secret should be provided via environment in production.
- If drops don’t appear immediately after admin approval, wait up to 15s or refocus window; or wire a manual refresh using
useUser().refreshStats().
npm run dev # client + server concurrently
npm run build # build frontend
npm run preview # preview built frontendMIT