Skip to content

Repository files navigation

Adaptive Quiz Platform

An intelligent quiz platform with adaptive difficulty, real-time leaderboards, and comprehensive performance tracking.

🚀 Features

Core Functionality

  • Adaptive Difficulty Algorithm: Questions dynamically adjust based on user performance
  • Real-time Score Updates: Instant feedback and score calculation after each answer
  • Streak System: Track consecutive correct answers with streak decay after 24 hours
  • Dual Leaderboards: Compete on both total score and maximum streak
  • Performance Analytics: Detailed metrics including accuracy, difficulty distribution, and recent performance

Technical Highlights

  • Idempotent Answer Submission: Prevents duplicate score updates
  • Redis Caching: Fast access to user state, question pools, and leaderboards
  • Rate Limiting: Protection against abuse
  • JWT Authentication: Secure user sessions
  • Responsive Design: Works seamlessly on desktop and mobile
  • Dark Mode: Full light/dark theme support
  • Design System: Reusable component library with design tokens

🛠️ Tech Stack

Backend

  • Node.js + Express.js: RESTful API server
  • MongoDB: Primary database for users, questions, and game state
  • Redis: Caching layer for performance optimization
  • JWT: Authentication and authorization
  • bcryptjs: Password hashing

Frontend

  • React 18: UI framework
  • Vite: Build tool and dev server
  • React Router: Client-side routing
  • Axios: HTTP client
  • Tailwind CSS: Utility-first styling
  • Lucide React: Icon library

DevOps

  • Docker + Docker Compose: Containerization
  • ESLint + Prettier: Code quality

📋 Prerequisites

  • Docker Desktop (includes Docker Compose)
  • Node.js 18+ (for local development)

🚀 Quick Start

Single Command Deployment

docker-compose up --build

This command will:

  1. Build and start MongoDB
  2. Build and start Redis
  3. Build and start the backend API (port 5000)
  4. Build and start the frontend app (port 3000)

Access the Application

Seed Database with Questions

docker-compose exec backend npm run seed

This will populate the database with 30 questions across difficulty levels 1-10.

📁 Project Structure

.
├── backend/
│   ├── config/           # Database and Redis configuration
│   ├── controllers/      # Request handlers
│   ├── middleware/       # Auth, rate limiting
│   ├── models/           # MongoDB schemas
│   ├── routes/           # API routes
│   ├── services/         # Business logic (adaptive, cache)
│   ├── scripts/          # Seed data script
│   └── server.js         # Entry point
├── frontend/
│   ├── src/
│   │   ├── components/   # Reusable UI components
│   │   │   ├── ui/       # Design system components
│   │   │   ├── layout/   # Layout components
│   │   │   └── auth/     # Auth components
│   │   ├── contexts/     # React contexts (Auth, Theme)
│   │   ├── pages/        # Route pages
│   │   ├── App.jsx       # App component
│   │   └── main.jsx      # Entry point
│   └── index.html
└── docker-compose.yml    # Container orchestration

🎮 How to Use

1. Register/Login

  • Create a new account or login with existing credentials
  • JWT token is stored in localStorage for session management

2. Dashboard

  • View your current stats: difficulty level, streak, score, accuracy
  • See performance trends and difficulty distribution
  • Quick access to start a quiz

3. Take Quiz

  • Answer questions that adapt to your skill level
  • Get instant feedback on correctness
  • See real-time updates to score, streak, and difficulty
  • Questions get harder as you answer correctly, easier if you struggle

4. Leaderboard

  • View top players by score or streak
  • See your current rank
  • Real-time updates after each answer

5. Profile

  • View detailed statistics
  • Track achievements and badges
  • Monitor accuracy and progress over time

🧠 Adaptive Algorithm

Difficulty Adjustment

  • Correct Answer:
    • Streak ≥ 3: +2 difficulty
    • Streak ≥ 1: +1 difficulty
  • Wrong Answer:
    • -1 to -2 difficulty based on recent performance
  • Range: 1-10 (clamped)

Score Calculation

baseScore = difficulty × 10
streakMultiplier = 1 + (streak × 0.1)
difficultyBonus = difficulty × 5
finalScore = (baseScore + difficultyBonus) × streakMultiplier

Streak System

  • Increments on correct answers
  • Resets to 0 on wrong answers
  • Decays after 24 hours of inactivity
  • Max streak tracked separately

🔌 API Endpoints

Authentication

  • POST /api/v1/auth/register - Register new user
  • POST /api/v1/auth/login - Login user
  • GET /api/v1/auth/profile - Get user profile (protected)

Quiz

  • GET /api/v1/quiz/next - Get next question (protected)
  • POST /api/v1/quiz/answer - Submit answer (protected, idempotent)
  • GET /api/v1/quiz/metrics - Get user metrics (protected)

Leaderboard

  • GET /api/v1/leaderboard/score - Get score leaderboard (protected)
  • GET /api/v1/leaderboard/streak - Get streak leaderboard (protected)

🎨 Design System

Color Tokens

  • Primary: Blue shades (main actions, links)
  • Secondary: Purple shades (accents)
  • Success: Green shades (correct answers, positive feedback)
  • Error: Red shades (wrong answers, errors)
  • Warning: Yellow/Orange shades (streaks, alerts)

Component Library

  • Button: Multiple variants (primary, secondary, outline, ghost)
  • Card: Composable with Header, Body, Footer
  • Input: Form inputs with labels and error states
  • Badge: Status indicators
  • Progress: Progress bars with labels

Responsive Breakpoints

  • sm: 640px
  • md: 768px
  • lg: 1024px
  • xl: 1280px

🔒 Security Features

  • Password hashing with bcrypt
  • JWT token authentication
  • Rate limiting on all API endpoints
  • Stricter limits on auth endpoints
  • CORS enabled
  • Environment variable configuration

📊 Database Schema

Users

{
  username: String (unique),
  email: String (unique),
  password: String (hashed),
  createdAt: Date
}

Questions

{
  difficulty: Number (1-10),
  prompt: String,
  choices: [String],
  correctAnswerHash: String (SHA-256),
  tags: [String]
}

UserState

{
  userId: ObjectId,
  currentDifficulty: Number (1-10),
  streak: Number,
  maxStreak: Number,
  totalScore: Number,
  lastQuestionId: ObjectId,
  lastAnswerAt: Date,
  stateVersion: Number,
  totalAnswered: Number,
  correctAnswers: Number
}

AnswerLog

{
  userId: ObjectId,
  questionId: ObjectId,
  difficulty: Number,
  answer: String,
  correct: Boolean,
  scoreDelta: Number,
  streakAtAnswer: Number,
  answeredAt: Date,
  answerIdempotencyKey: String (unique)
}

🚦 Edge Cases Handled

  1. Idempotency: Duplicate answer submissions return cached results
  2. Streak Decay: Automatic reset after 24 hours of inactivity
  3. State Version Mismatch: Prevents race conditions in concurrent requests
  4. Question Pool Exhaustion: Falls back to any available question
  5. Difficulty Boundaries: Clamped between 1-10
  6. Negative Scores: Prevented (minimum 0)
  7. Cache Invalidation: Automatic on state changes

🧪 Testing

Manual Testing

  1. Register multiple users
  2. Answer questions correctly/incorrectly
  3. Verify difficulty adjustments
  4. Check leaderboard updates
  5. Test streak decay (modify lastAnswerAt)
  6. Verify idempotency with duplicate requests

🔧 Development

Local Development (without Docker)

Backend

cd backend
npm install
npm run dev

Frontend

cd frontend
npm install
npm run dev

Environment Variables

Backend .env:

PORT=5000
MONGODB_URI=mongodb://localhost:27017/adaptive-quiz
REDIS_HOST=localhost
REDIS_PORT=6379
JWT_SECRET=your-secret-key
JWT_EXPIRES_IN=7d
NODE_ENV=development

📝 Low-Level Design (LLD)

Class Responsibilities

AdaptiveService

  • Calculate score deltas based on difficulty and streak
  • Adjust difficulty based on performance
  • Handle streak decay logic
  • Provide performance metrics

CacheService

  • Manage Redis operations
  • Cache user state, question pools, leaderboards
  • Handle cache invalidation strategies
  • Define TTL policies

Controllers

  • Handle HTTP requests/responses
  • Validate input
  • Call services
  • Format responses

Cache Strategy

Keys:

  • user_state:{userId} - TTL: 300s
  • question_pool:{difficulty} - TTL: 3600s
  • leaderboard:{type} - TTL: 60s

Invalidation:

  • User state: On answer submission
  • Leaderboards: On score/streak changes
  • Question pools: Manual/time-based

Indexes

  • UserState: userId, totalScore (desc), maxStreak (desc)
  • Question: difficulty
  • AnswerLog: userId + answeredAt (desc), answerIdempotencyKey

🎯 Evaluation Criteria Met

Frontend (25%)

  • Modern React SPA with Vite
  • Reusable component library
  • Design system with tokens
  • Responsive + dark mode
  • Lazy loading ready
  • Clean architecture

LLD Rigour (25%)

  • Clear module responsibilities
  • API schemas documented
  • DB schema with indexes
  • Cache strategy defined
  • Pseudocode in services

Functional Requirements (25%)

  • Adaptive difficulty ✓
  • Real-time updates ✓
  • Leaderboards ✓
  • Score/streak tracking ✓
  • Metrics dashboard ✓

Edge Cases (15%)

  • Idempotency ✓
  • Streak decay ✓
  • State versioning ✓
  • Boundary conditions ✓

Operational Concerns (10%)

  • Strong consistency ✓
  • Rate limiting ✓
  • Caching ✓
  • Stateless servers ✓
  • Docker deployment ✓

📦 Deployment

The application is fully containerized and can be deployed to:

  • Docker Swarm
  • Kubernetes
  • AWS ECS
  • Any Docker-compatible platform

🤝 Contributing

  1. Fork the repository
  2. Create a feature branch
  3. Commit your changes
  4. Push to the branch
  5. Open a Pull Request

📄 License

MIT License

👥 Authors

Built as part of the Scalar assignment.

🙏 Acknowledgments

  • React team for the amazing framework
  • Tailwind CSS for the utility-first approach
  • MongoDB and Redis teams for robust databases

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages