Node.js / Express backend API for a vocabulary flashcards app with JWT-based authentication, MongoDB persistence, lesson progress tracking, and text-to-speech support.
-
User authentication
- Email/password registration and login
- Passwords hashed with bcrypt
- Access tokens (JWT, 15 minutes) in Authorization header
- Refresh tokens (JWT, 14 days) stored as secure HttpOnly cookies
- Token rotation and logout with refresh token blacklist per user
-
Vocabulary & courses
- Per-user words with
courseNameandlessonName - Loading default word sets for new users from a separate collection
- Queries by user, course, and lesson
- Admin endpoint to upload default words
- Per-user words with
-
Lesson progress
- Track number of repeats per lesson
- Create, set, and increment repeat counters
- Fetch all progress entries for a given user & course
-
Text-to-speech
- Simple TTS endpoint using Google Translate TTS HTTP API
- Streams MP3 audio for any given word
-
Frontend integration
- CORS configured for deployment on Netlify
(https://memorygamepuzzlegame.netlify.appby default)
- CORS configured for deployment on Netlify
- Runtime: Node.js
- Framework: Express
- Database: MongoDB Atlas (via Mongoose)
- Auth: JSON Web Tokens (JWT), bcrypt
- Other: uuid, axios, cookie-parser, cors, dotenv
Models (Mongoose):
User– users, roles, refresh tokensDefaultWord– default course/lesson wordsWord– user-specific words with repeats counterLessonProgress– per-lesson repeat tracking
| Method | Path | Description |
|---|---|---|
| POST | /auth/register |
Register user (email + password) |
| POST | /auth/login |
Login, returns access token + cookie |
| POST | /auth/refresh |
Rotate refresh token, new access JWT |
| POST | /auth/logout |
Logout, invalidate refresh token |
| Method | Path | Description |
|---|---|---|
| POST | /words |
Add a user word |
| GET | /words/:userId |
Get all words for user |
| GET | /words/:userId/:courseName/:lessonName |
Get words by user + course + lesson |
| POST | /load-defaults |
Load default words for a user (one-time) |
| POST | /admin/words |
Upload default words (admin use) |
| GET | /courses/:userId |
Get distinct course names for a user |
| GET | /lessons/:userId/:courseName |
Get distinct lesson names for a course |
| Method | Path | Description |
|---|---|---|
| POST | /lesson-progress |
Create progress record for a lesson |
| PUT | /lesson-progress |
Set repeats value explicitly |
| PATCH | /lesson-progress/increment |
Increment repeats by 1 (or create record) |
| GET | /lesson-progress/:userId/:courseName |
Get all lesson progress for user & course |
| Method | Path | Description |
|---|---|---|
| GET | /speak/:word |
Stream MP3 pronunciation for a word |
| Method | Path | Description |
|---|---|---|
| GET | /protected |
Example protected route (requires JWT) |
Protected routes use
Authorization: Bearer <accessToken>header and theauthMiddleware.
- Node.js (LTS)
- npm or yarn
- MongoDB Atlas cluster (or local MongoDB)
Create a .env file in the project root:
MONGO_URL=mongodb+srv://...
ACCESS_SECRET=your_access_jwt_secret
REFRESH_SECRET=your_refresh_jwt_secret
PORT=5000npm install
npm start
# or
node server.jsThe server will start on:
http://localhost:5000
Update the CORS config if you use a different frontend origin:
app.use(
cors({
origin: "https://memorygamepuzzlegame.netlify.app",
methods: "GET,HEAD,PUT,PATCH,POST,DELETE",
credentials: true,
})
);- Refresh tokens are stored in HttpOnly cookies with
secureandsameSite: "Strict"flags. - Access tokens are short-lived (15 minutes) and must be sent in the
Authorizationheader. - Passwords are hashed with
bcryptbefore storing in MongoDB.
- Move routes and models into separate modules
- Add request validation (e.g. Joi/Zod)
- Add automated tests (unit/integration)
- Add role-based authorization for admin endpoints
Built as the backend for a vocabulary flashcards / memory game application.