Files
Tasks/interview_quiz_user_story.md
2025-11-11 00:25:50 +02:00

51 KiB

Technical Interview Quiz Application - MySQL + Express + Angular + Node

Project Overview

A comprehensive technical interview preparation platform where users can practice interview questions across multiple categories with different question types (Multiple Choice, True/False, and Written Answer).


Technology Stack

Frontend

  • Angular (Latest version)
  • TypeScript
  • RxJS for state management
  • Angular Material or Bootstrap for UI components

Backend

  • Node.js with Express.js
  • MySQL (8.0+) with Sequelize ORM
  • JWT for authentication
  • Express Validator for input validation
  • bcrypt for password hashing

Additional Tools

  • Docker for containerization (optional)
  • Jest for testing
  • GitHub Actions for CI/CD

Core Features & User Stories

1. User Authentication & Authorization

User Story 1.0: Guest User Access (NEW)

As a visitor
I want to try the quiz without registering
So that I can explore the platform before committing to sign up

Acceptance Criteria:

  • Guest users can access limited quiz content without authentication
  • Guest users can take up to 3 quizzes per day (configurable by admin)
  • Guest users see only questions marked as "public/guest-accessible" by admin
  • Guest progress is NOT saved permanently (stored in session/local storage)
  • After quiz limit reached, prompt to register for unlimited access
  • Guest sessions expire after 24 hours
  • Guest users can see limited categories (admin-controlled)
  • Banner/prompt encouraging registration is visible for guests

API Endpoint:

POST /api/guest/start-session
Body: {
  deviceId: string (generated client-side)
}
Response: {
  sessionToken: string (temporary),
  guestId: string,
  remainingQuizzes: number,
  availableCategories: Category[],
  restrictions: {
    maxQuizzes: number,
    questionsPerQuiz: number,
    allowedFeatures: string[]
  }
}

GET /api/guest/quiz-limit
Headers: { X-Guest-Token: <session-token> }
Response: {
  remainingQuizzes: number,
  resetTime: Date,
  upgradePrompt: string
}

Database Schema:

-- guest_sessions table
CREATE TABLE guest_sessions (
  id CHAR(36) PRIMARY KEY DEFAULT (UUID()),
  guest_id VARCHAR(100) UNIQUE NOT NULL,
  device_id VARCHAR(255) NOT NULL,
  session_token VARCHAR(500) NOT NULL,
  quizzes_attempted INT DEFAULT 0,
  max_quizzes INT DEFAULT 3,
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  expires_at TIMESTAMP NOT NULL,
  ip_address VARCHAR(45),
  user_agent TEXT,
  INDEX idx_guest_id (guest_id),
  INDEX idx_session_token (session_token(255)),
  INDEX idx_expires_at (expires_at)
);

Sequelize Model:

// models/GuestSession.js
const { DataTypes } = require('sequelize');

module.exports = (sequelize) => {
  const GuestSession = sequelize.define('GuestSession', {
    id: {
      type: DataTypes.UUID,
      defaultValue: DataTypes.UUIDV4,
      primaryKey: true
    },
    guestId: {
      type: DataTypes.STRING(100),
      unique: true,
      allowNull: false,
      field: 'guest_id'
    },
    deviceId: {
      type: DataTypes.STRING(255),
      allowNull: false,
      field: 'device_id'
    },
    sessionToken: {
      type: DataTypes.STRING(500),
      allowNull: false,
      field: 'session_token'
    },
    quizzesAttempted: {
      type: DataTypes.INTEGER,
      defaultValue: 0,
      field: 'quizzes_attempted'
    },
    maxQuizzes: {
      type: DataTypes.INTEGER,
      defaultValue: 3,
      field: 'max_quizzes'
    },
    expiresAt: {
      type: DataTypes.DATE,
      allowNull: false,
      field: 'expires_at'
    },
    ipAddress: {
      type: DataTypes.STRING(45),
      field: 'ip_address'
    },
    userAgent: {
      type: DataTypes.TEXT,
      field: 'user_agent'
    }
  }, {
    tableName: 'guest_sessions',
    timestamps: true,
    createdAt: 'created_at',
    updatedAt: false,
    indexes: [
      { fields: ['guest_id'] },
      { fields: ['session_token'] },
      { fields: ['expires_at'] }
    ]
  });

  return GuestSession;
};

User Story 1.1: User Registration

As a new user
I want to create an account with email and password
So that I can save my progress and track my performance with unlimited access

Acceptance Criteria:

  • User can register with email, username, and password
  • Password must be at least 8 characters with 1 uppercase, 1 lowercase, 1 number
  • Email validation is performed
  • Duplicate emails are rejected
  • User receives a welcome email upon successful registration
  • User is automatically logged in after registration
  • Registration unlocks unlimited quizzes and all features
  • If converting from guest, show summary of guest performance

API Endpoint:

POST /api/auth/register
Body: {
  username: string,
  email: string,
  password: string,
  guestSessionId?: string (optional, to migrate guest data)
}
Response: {
  token: string,
  user: { id, username, email, role },
  upgradedFromGuest: boolean,
  migratedStats?: { quizzesTaken, score }
}

User Story 1.2: User Login

As a registered user
I want to log in with my credentials
So that I can access my personalized dashboard

Acceptance Criteria:

  • User can login with email and password
  • Invalid credentials show appropriate error message
  • Successful login redirects to dashboard
  • JWT token is generated and stored
  • Token expires after 24 hours

API Endpoint:

POST /api/auth/login
Body: {
  email: string,
  password: string
}
Response: {
  token: string,
  user: { id, username, email, stats }
}

User Story 1.3: User Logout

As a logged-in user
I want to log out securely
So that my account remains protected

Acceptance Criteria:

  • User can click logout button
  • JWT token is cleared from storage
  • User is redirected to login page
  • Session is terminated

2. Question Management

User Story 2.1: Browse Questions by Category

As a user
I want to browse questions by technology category
So that I can focus on specific topics

Acceptance Criteria:

  • Display list of categories (Angular, Node.js, MongoDB, etc.)
  • Show question count per category
  • User can select a category to view questions
  • Categories are filterable and searchable

API Endpoint:

GET /api/categories
Response: [{
  id: string,
  name: string,
  description: string,
  questionCount: number,
  icon: string
}]

User Story 2.2: View Question Details

As a user
I want to view question details with all options
So that I can attempt to answer it

Acceptance Criteria:

  • Question text is clearly displayed
  • Question type (Multiple Choice, True/False, Written) is shown
  • All answer options are visible (for MCQ and T/F)
  • Input field for written answers
  • Category and difficulty level are displayed

API Endpoint:

GET /api/questions/:id
Response: {
  id: string,
  question: string,
  type: 'multiple' | 'trueFalse' | 'written',
  category: string,
  difficulty: 'easy' | 'medium' | 'hard',
  options: string[],
  correctAnswer: number | boolean | string,
  explanation: string,
  keywords: string[]
}

User Story 2.3: Submit Answer

As a user
I want to submit my answer and get immediate feedback
So that I can learn from my mistakes

Acceptance Criteria:

  • User can submit their selected/written answer
  • System validates the answer
  • Correct/incorrect feedback is shown immediately
  • Explanation is displayed after submission
  • Score is updated in real-time
  • Answer cannot be changed after submission

API Endpoint:

POST /api/quiz/submit
Body: {
  questionId: string,
  userAnswer: any,
  quizSessionId: string
}
Response: {
  isCorrect: boolean,
  correctAnswer: any,
  explanation: string,
  score: number
}

3. Quiz Session Management

User Story 3.1: Start Quiz Session

As a user
I want to start a quiz session for a specific category
So that I can practice multiple questions in one session

Acceptance Criteria:

  • User selects a category and number of questions
  • Quiz session is created with unique ID
  • Questions are randomly selected from category
  • Timer starts (optional)
  • Progress is tracked

API Endpoint:

POST /api/quiz/start
Body: {
  categoryId: string,
  questionCount: number,
  difficulty?: string
}
Response: {
  sessionId: string,
  questions: Question[],
  startTime: Date,
  totalQuestions: number
}

User Story 3.2: Navigate Between Questions

As a user
I want to move to next/previous questions
So that I can control my quiz pace

Acceptance Criteria:

  • Next button is enabled after answering
  • Previous button shows answered questions (review mode)
  • Progress bar shows current position
  • Question counter displays (e.g., "5 of 10")

User Story 3.3: Complete Quiz Session

As a user
I want to see my final score and performance summary
So that I can evaluate my knowledge

Acceptance Criteria:

  • Total score is displayed (X/Y correct)
  • Percentage score is calculated
  • Time taken is shown
  • Performance message (Excellent, Good, Keep Practicing)
  • Option to review incorrect answers
  • Option to retake quiz or return to dashboard

API Endpoint:

POST /api/quiz/complete
Body: {
  sessionId: string
}
Response: {
  score: number,
  totalQuestions: number,
  percentage: number,
  timeTaken: number,
  correctAnswers: number,
  incorrectAnswers: number,
  results: [{
    questionId: string,
    isCorrect: boolean,
    userAnswer: any
  }]
}

4. User Dashboard & Analytics

User Story 4.1: View Personal Dashboard

As a user
I want to see my overall statistics and progress
So that I can track my improvement

Acceptance Criteria:

  • Display total quizzes taken
  • Show overall accuracy percentage
  • List recent quiz sessions
  • Display category-wise performance
  • Show streak and achievements
  • Visualize progress with charts

API Endpoint:

GET /api/users/:userId/dashboard
Response: {
  totalQuizzes: number,
  overallAccuracy: number,
  totalQuestions: number,
  recentSessions: Session[],
  categoryStats: [{
    category: string,
    accuracy: number,
    questionsAttempted: number
  }],
  streak: number,
  achievements: Achievement[]
}

User Story 4.2: View Quiz History

As a user
I want to view my past quiz sessions
So that I can review my performance over time

Acceptance Criteria:

  • List all completed quiz sessions
  • Show date, category, score for each session
  • Filter by category and date range
  • Sort by score or date
  • Click to view detailed results

API Endpoint:

GET /api/users/:userId/history?page=1&limit=10&category=Angular
Response: {
  sessions: [{
    id: string,
    category: string,
    score: number,
    totalQuestions: number,
    date: Date,
    timeTaken: number
  }],
  totalCount: number,
  currentPage: number
}

5. Admin Features

User Story 5.0: Configure Guest Access Settings (NEW)

As an admin
I want to configure what content guest users can access
So that I can control the freemium experience and encourage registrations

Acceptance Criteria:

  • Admin can set maximum quizzes per day for guests (default: 3)
  • Admin can set maximum questions per quiz for guests (default: 5)
  • Admin can mark categories as "guest-accessible" or "registered-only"
  • Admin can mark individual questions as "public" or "premium"
  • Admin can set guest session expiry time (default: 24 hours)
  • Admin can enable/disable guest access entirely
  • Admin can view guest usage statistics
  • Admin can customize upgrade prompts and messaging
  • Settings are applied immediately without system restart

API Endpoint:

GET /api/admin/guest-settings
Headers: { Authorization: Bearer <admin-token> }
Response: {
  guestAccessEnabled: boolean,
  maxQuizzesPerDay: number,
  maxQuestionsPerQuiz: number,
  sessionExpiryHours: number,
  publicCategories: string[],
  upgradePromptMessage: string
}

PUT /api/admin/guest-settings
Headers: { Authorization: Bearer <admin-token> }
Body: {
  guestAccessEnabled: boolean,
  maxQuizzesPerDay: number,
  maxQuestionsPerQuiz: number,
  sessionExpiryHours: number,
  publicCategories: string[],
  upgradePromptMessage: string
}
Response: {
  message: string,
  updatedSettings: GuestSettings
}

PUT /api/admin/categories/:id/access
Headers: { Authorization: Bearer <admin-token> }
Body: {
  guestAccessible: boolean
}
Response: {
  message: string,
  category: Category
}

PUT /api/admin/questions/:id/visibility
Headers: { Authorization: Bearer <admin-token> }
Body: {
  isPublic: boolean,
  visibility: 'public' | 'registered' | 'premium'
}
Response: {
  message: string,
  question: Question
}

Admin Dashboard UI Components:

// Guest Access Settings Panel
{
  guestAccessEnabled: Toggle,
  maxQuizzesPerDay: NumberInput (1-10),
  maxQuestionsPerQuiz: NumberInput (3-15),
  sessionExpiryHours: NumberInput (1-72),
  publicCategories: MultiSelect,
  upgradePromptMessage: TextArea,
  guestStatistics: {
    totalGuestSessions: number,
    guestToUserConversion: percentage,
    averageQuizzesTaken: number
  }
}

User Story 5.1: Add New Question

As an admin
I want to add new questions to the database
So that users have more content to practice

Acceptance Criteria:

  • Admin can access question management panel
  • Form to input question details (text, type, category, options, answer, explanation)
  • NEW: Admin can mark question visibility (public/registered/premium)
  • NEW: Admin can set if question is available for guest users
  • Validate all required fields
  • Preview question before submission
  • Success/error message after submission

API Endpoint:

POST /api/admin/questions
Headers: { Authorization: Bearer <admin-token> }
Body: {
  question: string,
  type: string,
  category: string,
  difficulty: string,
  options: string[],
  correctAnswer: any,
  explanation: string,
  keywords: string[],
  visibility: 'public' | 'registered' | 'premium', // NEW
  isGuestAccessible: boolean // NEW
}
Response: {
  message: string,
  questionId: string
}

User Story 5.2: Edit Existing Question

As an admin
I want to edit existing questions
So that I can correct mistakes or update content

Acceptance Criteria:

  • Admin can search for questions
  • Edit form is pre-filled with existing data
  • Changes are validated
  • Update confirmation is shown
  • Version history is maintained

API Endpoint:

PUT /api/admin/questions/:id
Headers: { Authorization: Bearer <admin-token> }
Body: { ...updated fields }
Response: { message: string }

User Story 5.3: Delete Question

As an admin
I want to delete inappropriate or outdated questions
So that the question bank remains high quality

Acceptance Criteria:

  • Admin can soft delete questions
  • Confirmation dialog before deletion
  • Deleted questions don't appear in quizzes
  • Deletion is logged
  • Can restore deleted questions

API Endpoint:

DELETE /api/admin/questions/:id
Headers: { Authorization: Bearer <admin-token> }
Response: { message: string }

User Story 5.4: View User Statistics

As an admin
I want to view system-wide user statistics
So that I can understand platform usage

Acceptance Criteria:

  • Total registered users
  • Active users (last 7 days)
  • Total quiz sessions
  • Most popular categories
  • Average quiz scores
  • User growth chart

API Endpoint:

GET /api/admin/statistics
Headers: { Authorization: Bearer <admin-token> }
Response: {
  totalUsers: number,
  activeUsers: number,
  totalQuizzes: number,
  popularCategories: Category[],
  averageScore: number,
  userGrowth: [{date: Date, count: number}]
}

6. Additional Features

User Story 6.1: Search Questions

As a user
I want to search for specific questions
So that I can practice targeted topics

Acceptance Criteria:

  • Search bar in navigation
  • Search by keyword in question text
  • Filter by category and difficulty
  • Display matching results with highlighting
  • Empty state when no results found

API Endpoint:

GET /api/questions/search?q=angular&category=Angular&difficulty=medium
Response: {
  results: Question[],
  totalCount: number
}

User Story 6.2: Bookmark Questions

As a user
I want to bookmark difficult questions
So that I can review them later

Acceptance Criteria:

  • Bookmark icon on each question
  • Toggle bookmark on/off
  • View all bookmarked questions
  • Remove bookmarks
  • Sync across devices

API Endpoint:

POST /api/users/:userId/bookmarks
Body: { questionId: string }
Response: { message: string }

GET /api/users/:userId/bookmarks
Response: { bookmarks: Question[] }

User Story 6.3: Share Quiz Results

As a user
I want to share my quiz results on social media
So that I can celebrate my achievements

Acceptance Criteria:

  • Share button after quiz completion
  • Generate shareable image/card with score
  • Links to Twitter, LinkedIn, Facebook
  • Copy link functionality
  • Privacy option (public/private)

User Story 6.4: Dark Mode

As a user
I want to toggle between light and dark themes
So that I can use the app comfortably in different lighting

Acceptance Criteria:

  • Theme toggle in settings
  • Preference is saved in local storage
  • Smooth transition between themes
  • All UI elements support both themes

User Story 6.5: Mobile Responsive Design

As a user
I want to use the app on my mobile device
So that I can practice anywhere

Acceptance Criteria:

  • Fully responsive layout (320px to 4K)
  • Touch-friendly buttons and controls
  • Readable text on small screens
  • Optimized images and assets
  • Works offline with service worker (PWA)

Database Schema

1. Users Table

CREATE TABLE users (
  id CHAR(36) PRIMARY KEY DEFAULT (UUID()),
  username VARCHAR(50) UNIQUE NOT NULL,
  email VARCHAR(255) UNIQUE NOT NULL,
  password VARCHAR(255) NOT NULL,
  role ENUM('user', 'admin') DEFAULT 'user',
  profile_image VARCHAR(500),
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  last_login TIMESTAMP NULL,
  total_quizzes INT DEFAULT 0,
  total_questions INT DEFAULT 0,
  correct_answers INT DEFAULT 0,
  streak INT DEFAULT 0,
  INDEX idx_email (email),
  INDEX idx_username (username),
  INDEX idx_role (role)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

Sequelize Model:

const { DataTypes } = require('sequelize');

module.exports = (sequelize) => {
  const User = sequelize.define('User', {
    id: {
      type: DataTypes.UUID,
      defaultValue: DataTypes.UUIDV4,
      primaryKey: true
    },
    username: {
      type: DataTypes.STRING(50),
      unique: true,
      allowNull: false
    },
    email: {
      type: DataTypes.STRING(255),
      unique: true,
      allowNull: false,
      validate: { isEmail: true }
    },
    password: {
      type: DataTypes.STRING(255),
      allowNull: false
    },
    role: {
      type: DataTypes.ENUM('user', 'admin'),
      defaultValue: 'user'
    },
    profileImage: {
      type: DataTypes.STRING(500),
      field: 'profile_image'
    },
    lastLogin: {
      type: DataTypes.DATE,
      field: 'last_login'
    },
    totalQuizzes: {
      type: DataTypes.INTEGER,
      defaultValue: 0,
      field: 'total_quizzes'
    },
    totalQuestions: {
      type: DataTypes.INTEGER,
      defaultValue: 0,
      field: 'total_questions'
    },
    correctAnswers: {
      type: DataTypes.INTEGER,
      defaultValue: 0,
      field: 'correct_answers'
    },
    streak: {
      type: DataTypes.INTEGER,
      defaultValue: 0
    }
  }, {
    tableName: 'users',
    timestamps: true,
    createdAt: 'created_at',
    updatedAt: 'updated_at'
  });

  User.associate = (models) => {
    User.belongsToMany(models.Question, { 
      through: 'user_bookmarks', 
      as: 'bookmarks',
      foreignKey: 'user_id'
    });
    User.hasMany(models.QuizSession, { foreignKey: 'user_id' });
  };

  return User;
};

2. Categories Table

CREATE TABLE categories (
  id CHAR(36) PRIMARY KEY DEFAULT (UUID()),
  name VARCHAR(100) UNIQUE NOT NULL,
  description TEXT,
  icon VARCHAR(255),
  slug VARCHAR(100) UNIQUE NOT NULL,
  question_count INT DEFAULT 0,
  is_active BOOLEAN DEFAULT TRUE,
  guest_accessible BOOLEAN DEFAULT FALSE,
  public_question_count INT DEFAULT 0,
  registered_question_count INT DEFAULT 0,
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  INDEX idx_slug (slug),
  INDEX idx_is_active (is_active),
  INDEX idx_guest_accessible (guest_accessible)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

Sequelize Model:

const { DataTypes } = require('sequelize');

module.exports = (sequelize) => {
  const Category = sequelize.define('Category', {
    id: {
      type: DataTypes.UUID,
      defaultValue: DataTypes.UUIDV4,
      primaryKey: true
    },
    name: {
      type: DataTypes.STRING(100),
      unique: true,
      allowNull: false
    },
    description: {
      type: DataTypes.TEXT
    },
    icon: {
      type: DataTypes.STRING(255)
    },
    slug: {
      type: DataTypes.STRING(100),
      unique: true,
      allowNull: false
    },
    questionCount: {
      type: DataTypes.INTEGER,
      defaultValue: 0,
      field: 'question_count'
    },
    isActive: {
      type: DataTypes.BOOLEAN,
      defaultValue: true,
      field: 'is_active'
    },
    guestAccessible: {
      type: DataTypes.BOOLEAN,
      defaultValue: false,
      field: 'guest_accessible'
    },
    publicQuestionCount: {
      type: DataTypes.INTEGER,
      defaultValue: 0,
      field: 'public_question_count'
    },
    registeredQuestionCount: {
      type: DataTypes.INTEGER,
      defaultValue: 0,
      field: 'registered_question_count'
    }
  }, {
    tableName: 'categories',
    timestamps: true,
    createdAt: 'created_at',
    updatedAt: 'updated_at'
  });

  Category.associate = (models) => {
    Category.hasMany(models.Question, { foreignKey: 'category_id' });
  };

  return Category;
};

3. Questions Table

CREATE TABLE questions (
  id CHAR(36) PRIMARY KEY DEFAULT (UUID()),
  question TEXT NOT NULL,
  type ENUM('multiple', 'trueFalse', 'written') NOT NULL,
  category_id CHAR(36) NOT NULL,
  difficulty ENUM('easy', 'medium', 'hard') NOT NULL,
  options JSON,
  correct_answer VARCHAR(500),
  explanation TEXT NOT NULL,
  keywords JSON,
  tags JSON,
  visibility ENUM('public', 'registered', 'premium') DEFAULT 'registered',
  is_guest_accessible BOOLEAN DEFAULT FALSE,
  created_by CHAR(36),
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  is_active BOOLEAN DEFAULT TRUE,
  times_attempted INT DEFAULT 0,
  correct_rate DECIMAL(5,2) DEFAULT 0.00,
  FOREIGN KEY (category_id) REFERENCES categories(id) ON DELETE RESTRICT,
  FOREIGN KEY (created_by) REFERENCES users(id) ON DELETE SET NULL,
  INDEX idx_category (category_id),
  INDEX idx_difficulty (difficulty),
  INDEX idx_type (type),
  INDEX idx_visibility (visibility),
  INDEX idx_is_active (is_active),
  INDEX idx_is_guest_accessible (is_guest_accessible),
  FULLTEXT idx_question_text (question, explanation)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

Sequelize Model:

const { DataTypes } = require('sequelize');

module.exports = (sequelize) => {
  const Question = sequelize.define('Question', {
    id: {
      type: DataTypes.UUID,
      defaultValue: DataTypes.UUIDV4,
      primaryKey: true
    },
    question: {
      type: DataTypes.TEXT,
      allowNull: false
    },
    type: {
      type: DataTypes.ENUM('multiple', 'trueFalse', 'written'),
      allowNull: false
    },
    categoryId: {
      type: DataTypes.UUID,
      allowNull: false,
      field: 'category_id'
    },
    difficulty: {
      type: DataTypes.ENUM('easy', 'medium', 'hard'),
      allowNull: false
    },
    options: {
      type: DataTypes.JSON,
      comment: 'Array of answer options for multiple choice questions'
    },
    correctAnswer: {
      type: DataTypes.STRING(500),
      field: 'correct_answer'
    },
    explanation: {
      type: DataTypes.TEXT,
      allowNull: false
    },
    keywords: {
      type: DataTypes.JSON,
      comment: 'Array of keywords for search'
    },
    tags: {
      type: DataTypes.JSON,
      comment: 'Array of tags'
    },
    visibility: {
      type: DataTypes.ENUM('public', 'registered', 'premium'),
      defaultValue: 'registered'
    },
    isGuestAccessible: {
      type: DataTypes.BOOLEAN,
      defaultValue: false,
      field: 'is_guest_accessible'
    },
    createdBy: {
      type: DataTypes.UUID,
      field: 'created_by'
    },
    isActive: {
      type: DataTypes.BOOLEAN,
      defaultValue: true,
      field: 'is_active'
    },
    timesAttempted: {
      type: DataTypes.INTEGER,
      defaultValue: 0,
      field: 'times_attempted'
    },
    correctRate: {
      type: DataTypes.DECIMAL(5, 2),
      defaultValue: 0.00,
      field: 'correct_rate'
    }
  }, {
    tableName: 'questions',
    timestamps: true,
    createdAt: 'created_at',
    updatedAt: 'updated_at'
  });

  Question.associate = (models) => {
    Question.belongsTo(models.Category, { foreignKey: 'category_id' });
    Question.belongsTo(models.User, { foreignKey: 'created_by', as: 'creator' });
    Question.belongsToMany(models.User, { 
      through: 'user_bookmarks', 
      as: 'bookmarkedBy',
      foreignKey: 'question_id'
    });
  };

  return Question;
};

4. Quiz Sessions Table

CREATE TABLE quiz_sessions (
  id CHAR(36) PRIMARY KEY DEFAULT (UUID()),
  user_id CHAR(36),
  guest_session_id CHAR(36),
  is_guest_session BOOLEAN DEFAULT FALSE,
  category_id CHAR(36),
  start_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  end_time TIMESTAMP NULL,
  score INT DEFAULT 0,
  total_questions INT NOT NULL,
  status ENUM('in-progress', 'completed', 'abandoned') DEFAULT 'in-progress',
  completed_at TIMESTAMP NULL,
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
  FOREIGN KEY (guest_session_id) REFERENCES guest_sessions(id) ON DELETE CASCADE,
  FOREIGN KEY (category_id) REFERENCES categories(id) ON DELETE SET NULL,
  INDEX idx_user_id (user_id),
  INDEX idx_guest_session_id (guest_session_id),
  INDEX idx_status (status),
  INDEX idx_completed_at (completed_at)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

Sequelize Model:

const { DataTypes } = require('sequelize');

module.exports = (sequelize) => {
  const QuizSession = sequelize.define('QuizSession', {
    id: {
      type: DataTypes.UUID,
      defaultValue: DataTypes.UUIDV4,
      primaryKey: true
    },
    userId: {
      type: DataTypes.UUID,
      field: 'user_id'
    },
    guestSessionId: {
      type: DataTypes.UUID,
      field: 'guest_session_id'
    },
    isGuestSession: {
      type: DataTypes.BOOLEAN,
      defaultValue: false,
      field: 'is_guest_session'
    },
    categoryId: {
      type: DataTypes.UUID,
      field: 'category_id'
    },
    startTime: {
      type: DataTypes.DATE,
      defaultValue: DataTypes.NOW,
      field: 'start_time'
    },
    endTime: {
      type: DataTypes.DATE,
      field: 'end_time'
    },
    score: {
      type: DataTypes.INTEGER,
      defaultValue: 0
    },
    totalQuestions: {
      type: DataTypes.INTEGER,
      allowNull: false,
      field: 'total_questions'
    },
    status: {
      type: DataTypes.ENUM('in-progress', 'completed', 'abandoned'),
      defaultValue: 'in-progress'
    },
    completedAt: {
      type: DataTypes.DATE,
      field: 'completed_at'
    }
  }, {
    tableName: 'quiz_sessions',
    timestamps: true,
    createdAt: 'created_at',
    updatedAt: 'updated_at'
  });

  QuizSession.associate = (models) => {
    QuizSession.belongsTo(models.User, { foreignKey: 'user_id' });
    QuizSession.belongsTo(models.GuestSession, { foreignKey: 'guest_session_id' });
    QuizSession.belongsTo(models.Category, { foreignKey: 'category_id' });
    QuizSession.belongsToMany(models.Question, { 
      through: 'quiz_session_questions', 
      foreignKey: 'quiz_session_id'
    });
    QuizSession.hasMany(models.QuizAnswer, { foreignKey: 'quiz_session_id' });
  };

  return QuizSession;
};

5. Quiz Session Questions (Junction Table)

CREATE TABLE quiz_session_questions (
  id CHAR(36) PRIMARY KEY DEFAULT (UUID()),
  quiz_session_id CHAR(36) NOT NULL,
  question_id CHAR(36) NOT NULL,
  question_order INT NOT NULL,
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  FOREIGN KEY (quiz_session_id) REFERENCES quiz_sessions(id) ON DELETE CASCADE,
  FOREIGN KEY (question_id) REFERENCES questions(id) ON DELETE CASCADE,
  INDEX idx_quiz_session (quiz_session_id),
  INDEX idx_question (question_id),
  UNIQUE KEY unique_session_question (quiz_session_id, question_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

6. Quiz Answers Table

CREATE TABLE quiz_answers (
  id CHAR(36) PRIMARY KEY DEFAULT (UUID()),
  quiz_session_id CHAR(36) NOT NULL,
  question_id CHAR(36) NOT NULL,
  user_answer TEXT,
  is_correct BOOLEAN,
  time_spent INT COMMENT 'Time in seconds',
  answered_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  FOREIGN KEY (quiz_session_id) REFERENCES quiz_sessions(id) ON DELETE CASCADE,
  FOREIGN KEY (question_id) REFERENCES questions(id) ON DELETE CASCADE,
  INDEX idx_quiz_session (quiz_session_id),
  INDEX idx_question (question_id),
  INDEX idx_is_correct (is_correct)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

Sequelize Model:

const { DataTypes } = require('sequelize');

module.exports = (sequelize) => {
  const QuizAnswer = sequelize.define('QuizAnswer', {
    id: {
      type: DataTypes.UUID,
      defaultValue: DataTypes.UUIDV4,
      primaryKey: true
    },
    quizSessionId: {
      type: DataTypes.UUID,
      allowNull: false,
      field: 'quiz_session_id'
    },
    questionId: {
      type: DataTypes.UUID,
      allowNull: false,
      field: 'question_id'
    },
    userAnswer: {
      type: DataTypes.TEXT,
      field: 'user_answer'
    },
    isCorrect: {
      type: DataTypes.BOOLEAN,
      field: 'is_correct'
    },
    timeSpent: {
      type: DataTypes.INTEGER,
      comment: 'Time in seconds',
      field: 'time_spent'
    },
    answeredAt: {
      type: DataTypes.DATE,
      defaultValue: DataTypes.NOW,
      field: 'answered_at'
    }
  }, {
    tableName: 'quiz_answers',
    timestamps: false
  });

  QuizAnswer.associate = (models) => {
    QuizAnswer.belongsTo(models.QuizSession, { foreignKey: 'quiz_session_id' });
    QuizAnswer.belongsTo(models.Question, { foreignKey: 'question_id' });
  };

  return QuizAnswer;
};

7. Guest Settings Table

CREATE TABLE guest_settings (
  id CHAR(36) PRIMARY KEY DEFAULT (UUID()),
  guest_access_enabled BOOLEAN DEFAULT TRUE,
  max_quizzes_per_day INT DEFAULT 3,
  max_questions_per_quiz INT DEFAULT 5,
  session_expiry_hours INT DEFAULT 24,
  upgrade_prompt_message TEXT,
  feature_restrictions JSON COMMENT 'JSON object with feature flags',
  updated_by CHAR(36),
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  FOREIGN KEY (updated_by) REFERENCES users(id) ON DELETE SET NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

Sequelize Model:

const { DataTypes } = require('sequelize');

module.exports = (sequelize) => {
  const GuestSettings = sequelize.define('GuestSettings', {
    id: {
      type: DataTypes.UUID,
      defaultValue: DataTypes.UUIDV4,
      primaryKey: true
    },
    guestAccessEnabled: {
      type: DataTypes.BOOLEAN,
      defaultValue: true,
      field: 'guest_access_enabled'
    },
    maxQuizzesPerDay: {
      type: DataTypes.INTEGER,
      defaultValue: 3,
      field: 'max_quizzes_per_day'
    },
    maxQuestionsPerQuiz: {
      type: DataTypes.INTEGER,
      defaultValue: 5,
      field: 'max_questions_per_quiz'
    },
    sessionExpiryHours: {
      type: DataTypes.INTEGER,
      defaultValue: 24,
      field: 'session_expiry_hours'
    },
    upgradePromptMessage: {
      type: DataTypes.TEXT,
      field: 'upgrade_prompt_message'
    },
    featureRestrictions: {
      type: DataTypes.JSON,
      defaultValue: {
        canBookmark: false,
        canViewHistory: false,
        canViewExplanations: true,
        canShareResults: false
      },
      field: 'feature_restrictions'
    },
    updatedBy: {
      type: DataTypes.UUID,
      field: 'updated_by'
    }
  }, {
    tableName: 'guest_settings',
    timestamps: true,
    createdAt: 'created_at',
    updatedAt: 'updated_at'
  });

  GuestSettings.associate = (models) => {
    GuestSettings.belongsTo(models.User, { foreignKey: 'updated_by', as: 'updater' });
  };

  return GuestSettings;
};

8. Guest Settings Categories (Junction Table)

CREATE TABLE guest_settings_categories (
  id CHAR(36) PRIMARY KEY DEFAULT (UUID()),
  guest_settings_id CHAR(36) NOT NULL,
  category_id CHAR(36) NOT NULL,
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  FOREIGN KEY (guest_settings_id) REFERENCES guest_settings(id) ON DELETE CASCADE,
  FOREIGN KEY (category_id) REFERENCES categories(id) ON DELETE CASCADE,
  INDEX idx_guest_settings (guest_settings_id),
  INDEX idx_category (category_id),
  UNIQUE KEY unique_settings_category (guest_settings_id, category_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

9. Achievements Table

CREATE TABLE achievements (
  id CHAR(36) PRIMARY KEY DEFAULT (UUID()),
  name VARCHAR(100) NOT NULL,
  description TEXT,
  icon VARCHAR(255),
  condition_type VARCHAR(50) NOT NULL COMMENT 'e.g., streak, score, category',
  condition_value INT NOT NULL,
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  INDEX idx_condition_type (condition_type)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

Sequelize Model:

const { DataTypes } = require('sequelize');

module.exports = (sequelize) => {
  const Achievement = sequelize.define('Achievement', {
    id: {
      type: DataTypes.UUID,
      defaultValue: DataTypes.UUIDV4,
      primaryKey: true
    },
    name: {
      type: DataTypes.STRING(100),
      allowNull: false
    },
    description: {
      type: DataTypes.TEXT
    },
    icon: {
      type: DataTypes.STRING(255)
    },
    conditionType: {
      type: DataTypes.STRING(50),
      allowNull: false,
      field: 'condition_type'
    },
    conditionValue: {
      type: DataTypes.INTEGER,
      allowNull: false,
      field: 'condition_value'
    }
  }, {
    tableName: 'achievements',
    timestamps: true,
    createdAt: 'created_at',
    updatedAt: 'updated_at'
  });

  Achievement.associate = (models) => {
    Achievement.belongsToMany(models.User, { 
      through: 'user_achievements', 
      foreignKey: 'achievement_id',
      as: 'earnedBy'
    });
  };

  return Achievement;
};

10. User Achievements (Junction Table)

CREATE TABLE user_achievements (
  id CHAR(36) PRIMARY KEY DEFAULT (UUID()),
  user_id CHAR(36) NOT NULL,
  achievement_id CHAR(36) NOT NULL,
  earned_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
  FOREIGN KEY (achievement_id) REFERENCES achievements(id) ON DELETE CASCADE,
  INDEX idx_user (user_id),
  INDEX idx_achievement (achievement_id),
  UNIQUE KEY unique_user_achievement (user_id, achievement_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

11. User Bookmarks (Junction Table)

CREATE TABLE user_bookmarks (
  id CHAR(36) PRIMARY KEY DEFAULT (UUID()),
  user_id CHAR(36) NOT NULL,
  question_id CHAR(36) NOT NULL,
  bookmarked_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
  FOREIGN KEY (question_id) REFERENCES questions(id) ON DELETE CASCADE,
  INDEX idx_user (user_id),
  INDEX idx_question (question_id),
  UNIQUE KEY unique_user_bookmark (user_id, question_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

API Endpoints Summary

Authentication

  • POST /api/auth/register - Register new user (with optional guest migration)
  • POST /api/auth/login - Login user
  • POST /api/auth/logout - Logout user
  • GET /api/auth/verify - Verify JWT token
  • POST /api/auth/forgot-password - Request password reset
  • POST /api/auth/reset-password - Reset password with token

Guest Access (NEW)

  • POST /api/guest/start-session - Create guest session
  • GET /api/guest/quiz-limit - Check remaining quizzes
  • GET /api/guest/available-categories - Get guest-accessible categories
  • POST /api/guest/quiz/start - Start guest quiz session
  • GET /api/guest/session/:sessionId - Get guest session details
  • POST /api/guest/convert - Convert guest to registered user

Users

  • GET /api/users/:userId - Get user profile
  • PUT /api/users/:userId - Update user profile
  • GET /api/users/:userId/dashboard - Get dashboard data
  • GET /api/users/:userId/history - Get quiz history
  • POST /api/users/:userId/bookmarks - Add bookmark
  • DELETE /api/users/:userId/bookmarks/:questionId - Remove bookmark
  • GET /api/users/:userId/bookmarks - Get all bookmarks

Categories

  • GET /api/categories - Get all categories
  • GET /api/categories/:id - Get category details
  • POST /api/categories - Create category (admin)
  • PUT /api/categories/:id - Update category (admin)
  • DELETE /api/categories/:id - Delete category (admin)

Questions

  • GET /api/questions - Get all questions (paginated)
  • GET /api/questions/:id - Get question by ID
  • GET /api/questions/search - Search questions
  • GET /api/questions/category/:categoryId - Get questions by category
  • POST /api/questions - Create question (admin)
  • PUT /api/questions/:id - Update question (admin)
  • DELETE /api/questions/:id - Delete question (admin)

Quiz

  • POST /api/quiz/start - Start new quiz session
  • POST /api/quiz/submit - Submit answer
  • GET /api/quiz/session/:sessionId - Get session details
  • POST /api/quiz/complete - Complete quiz session
  • GET /api/quiz/review/:sessionId - Review completed quiz

Admin

  • GET /api/admin/statistics - Get system statistics
  • GET /api/admin/users - Get all users
  • PUT /api/admin/users/:userId/role - Update user role
  • GET /api/admin/reports - Get usage reports
  • GET /api/admin/guest-settings - Get guest access settings (NEW)
  • PUT /api/admin/guest-settings - Update guest access settings (NEW)
  • PUT /api/admin/categories/:id/access - Set category guest accessibility (NEW)
  • PUT /api/admin/questions/:id/visibility - Set question visibility level (NEW)
  • GET /api/admin/guest-analytics - Get guest user analytics (NEW)
  • GET /api/admin/conversion-rate - Get guest-to-user conversion metrics (NEW)

Non-Functional Requirements

Performance

  • API response time < 200ms for 95% of requests
  • Support 1000+ concurrent users
  • Database query optimization with proper indexing
  • Implement caching for frequently accessed data (Redis)
  • Use MySQL query cache and InnoDB buffer pool optimization
  • Connection pooling with Sequelize

Security

  • HTTPS only
  • JWT token authentication
  • Password hashing with bcrypt (10 rounds)
  • Input validation and sanitization
  • Rate limiting on API endpoints
  • CORS configuration
  • SQL injection prevention (Sequelize parameterized queries)
  • XSS protection
  • Prepared statements for all database queries

Scalability

  • Horizontal scaling support
  • Load balancing
  • Database sharding (future)
  • CDN for static assets
  • Microservices architecture (future)

Accessibility

  • WCAG 2.1 Level AA compliance
  • Keyboard navigation
  • Screen reader support
  • Color contrast ratios
  • Alt text for images

Testing

  • Unit tests (80%+ coverage)
  • Integration tests for APIs
  • E2E tests for critical user flows
  • Performance testing

Development Phases

Phase 1: MVP (Weeks 1-4)

  • Guest access with limited quiz functionality (NEW)
  • Admin guest settings configuration panel (NEW)
  • User authentication (register, login, logout)
  • Basic question display with visibility controls
  • Quiz session management (guest + registered)
  • Simple dashboard with statistics
  • Admin panel for question CRUD with visibility settings

Phase 2: Enhanced Features (Weeks 5-8)

  • Category management
  • Advanced filtering and search
  • Bookmarking system
  • Quiz history with detailed analytics
  • Performance charts and visualizations

Phase 3: Social & Gamification (Weeks 9-12)

  • Achievements and badges
  • Leaderboards
  • Share results on social media
  • User profiles with avatars
  • Daily challenges

Phase 4: Advanced Features (Weeks 13-16)

  • AI-powered question recommendations
  • Timed quizzes
  • Code editor for programming questions
  • Discussion forum
  • Email notifications

Deployment Strategy

Development Environment

  • Local MySQL 8.0+ instance
  • Node.js v18+
  • Sequelize CLI for migrations
  • Angular CLI
  • VS Code / WebStorm
  • MySQL Workbench (optional GUI)

Staging Environment

  • Managed MySQL (AWS RDS, Azure Database, or PlanetScale)
  • Heroku / Railway / Render
  • CI/CD with GitHub Actions
  • Automated database migrations

Production Environment

  • Managed MySQL with read replicas (AWS RDS, Azure Database for MySQL)
  • AWS / DigitalOcean / Azure
  • Load balancer
  • SSL certificate
  • Connection pooling (ProxySQL or built-in)
  • Monitoring (New Relic / DataDog)
  • Automated backup strategy (daily snapshots)
  • Point-in-time recovery enabled
  • Disaster recovery plan

Success Metrics

User Engagement

  • Daily Active Users (DAU) - including guest users
  • Monthly Active Users (MAU) - including guest users
  • Guest-to-Registered User Conversion Rate (NEW)
  • Average quizzes taken before registration (NEW)
  • Guest user bounce rate (NEW)
  • Average session duration
  • Questions answered per session
  • Return rate
  • Registration trigger points analysis (NEW)

Performance

  • API response time
  • Error rate
  • Uptime percentage
  • Page load time

Business

  • User registration rate
  • Quiz completion rate
  • User retention rate
  • NPS score

Future Enhancements

  1. AI Integration: Personalized learning paths based on user performance
  2. Video Explanations: Video tutorials for complex topics
  3. Live Quizzes: Compete with other users in real-time
  4. Certifications: Issue certificates on completion
  5. Company-Specific Prep: Custom question sets for specific companies
  6. Interview Scheduler: Book mock interviews with mentors
  7. Multi-language Support: i18n for global reach
  8. Offline Mode: Progressive Web App capabilities
  9. Voice Commands: Practice with voice-based interaction
  10. Collaborative Learning: Study groups and peer review

Getting Started (For Developers)

Prerequisites

# Install Node.js v18+
node --version

# Install MySQL 8.0+
# Windows: Download from https://dev.mysql.com/downloads/mysql/
# Mac: brew install mysql
# Linux: sudo apt-get install mysql-server

# Install Angular CLI
npm install -g @angular/cli

# Install Sequelize CLI
npm install -g sequelize-cli

Backend Setup

cd backend
npm install

# Install MySQL dependencies
npm install sequelize mysql2

# Create .env file
cp .env.example .env

# Configure MySQL connection in .env
# DB_HOST=localhost
# DB_PORT=3306
# DB_NAME=interview_quiz_db
# DB_USER=your_username
# DB_PASSWORD=your_password
# DB_DIALECT=mysql

# Create database
mysql -u root -p
CREATE DATABASE interview_quiz_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
EXIT;

# Run migrations
npx sequelize-cli db:migrate

# Seed database (optional)
npx sequelize-cli db:seed:all

# Start development server
npm run dev

Frontend Setup

cd frontend
npm install
ng serve

Database Migrations

# Create a new migration
npx sequelize-cli migration:generate --name migration-name

# Run migrations
npx sequelize-cli db:migrate

# Undo last migration
npx sequelize-cli db:migrate:undo

# Undo all migrations
npx sequelize-cli db:migrate:undo:all

# Create seeder
npx sequelize-cli seed:generate --name demo-data

Running Tests

# Backend tests
cd backend && npm test

# Frontend tests
cd frontend && ng test

# Integration tests with test database
DB_NAME=interview_quiz_test npm test

Contributing Guidelines

  1. Fork the repository
  2. Create feature branch (git checkout -b feature/amazing-feature)
  3. Commit changes (git commit -m 'Add amazing feature')
  4. Push to branch (git push origin feature/amazing-feature)
  5. Open Pull Request

License

MIT License


Contact & Support


MySQL Configuration Best Practices

Connection Pool Configuration

// config/database.js
const { Sequelize } = require('sequelize');

const sequelize = new Sequelize(
  process.env.DB_NAME,
  process.env.DB_USER,
  process.env.DB_PASSWORD,
  {
    host: process.env.DB_HOST,
    port: process.env.DB_PORT || 3306,
    dialect: 'mysql',
    logging: process.env.NODE_ENV === 'development' ? console.log : false,
    
    pool: {
      max: 10,
      min: 0,
      acquire: 30000,
      idle: 10000
    },
    
    dialectOptions: {
      charset: 'utf8mb4',
      collate: 'utf8mb4_unicode_ci',
      connectTimeout: 10000
    },
    
    define: {
      timestamps: true,
      underscored: true,
      freezeTableName: true
    }
  }
);

module.exports = sequelize;

MySQL Optimization Settings

-- my.cnf or my.ini configuration

[mysqld]
# InnoDB settings
innodb_buffer_pool_size = 2G
innodb_log_file_size = 512M
innodb_flush_log_at_trx_commit = 2
innodb_flush_method = O_DIRECT

# Connection settings
max_connections = 200
max_connect_errors = 100
connect_timeout = 10
wait_timeout = 600
interactive_timeout = 600

# Query cache (MySQL 5.7)
query_cache_type = 1
query_cache_size = 256M

# Character set
character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci

# Binary logging (for replication)
log_bin = mysql-bin
binlog_format = ROW
expire_logs_days = 7

# Slow query log
slow_query_log = 1
long_query_time = 2

Sequelize Migrations Structure

backend/
├── config/
│   └── database.js
├── migrations/
│   ├── 20250101000001-create-users.js
│   ├── 20250101000002-create-categories.js
│   ├── 20250101000003-create-questions.js
│   ├── 20250101000004-create-guest-sessions.js
│   ├── 20250101000005-create-quiz-sessions.js
│   ├── 20250101000006-create-quiz-answers.js
│   ├── 20250101000007-create-achievements.js
│   ├── 20250101000008-create-guest-settings.js
│   └── 20250101000009-create-junction-tables.js
├── models/
│   ├── index.js
│   ├── User.js
│   ├── Category.js
│   ├── Question.js
│   ├── GuestSession.js
│   ├── QuizSession.js
│   ├── QuizAnswer.js
│   ├── Achievement.js
│   └── GuestSettings.js
├── seeders/
│   ├── 20250101000001-demo-users.js
│   ├── 20250101000002-demo-categories.js
│   └── 20250101000003-demo-questions.js
└── .sequelizerc

Sample .sequelizerc Configuration

const path = require('path');

module.exports = {
  'config': path.resolve('config', 'database.js'),
  'models-path': path.resolve('models'),
  'seeders-path': path.resolve('seeders'),
  'migrations-path': path.resolve('migrations')
};

Database Indexing Strategy

-- Performance Indexes for Common Queries

-- User searches
CREATE INDEX idx_users_email ON users(email);
CREATE INDEX idx_users_username ON users(username);

-- Question searches with full-text
CREATE FULLTEXT INDEX idx_questions_fulltext ON questions(question, explanation);

-- Quiz session queries
CREATE INDEX idx_quiz_sessions_user_status ON quiz_sessions(user_id, status, completed_at);
CREATE INDEX idx_quiz_sessions_guest ON quiz_sessions(guest_session_id, status);

-- Performance tracking
CREATE INDEX idx_quiz_answers_correct ON quiz_answers(is_correct, answered_at);
CREATE INDEX idx_quiz_answers_session_question ON quiz_answers(quiz_session_id, question_id);

-- Category filtering
CREATE INDEX idx_questions_category_active ON questions(category_id, is_active, visibility);

-- Guest session cleanup
CREATE INDEX idx_guest_sessions_expires ON guest_sessions(expires_at);

-- Composite indexes for dashboard queries
CREATE INDEX idx_users_stats ON users(total_quizzes, correct_answers, streak);

Query Optimization Examples

// Efficient category listing with question counts
const categories = await Category.findAll({
  where: { isActive: true },
  attributes: {
    include: [
      [
        sequelize.literal(`(
          SELECT COUNT(*) 
          FROM questions 
          WHERE questions.category_id = categories.id 
          AND questions.is_active = true
        )`),
        'questionCount'
      ]
    ]
  }
});

// Dashboard stats with single query
const userDashboard = await User.findByPk(userId, {
  include: [
    {
      model: QuizSession,
      where: { status: 'completed' },
      required: false,
      limit: 10,
      order: [['completed_at', 'DESC']],
      include: [{ model: Category }]
    }
  ]
});

// Efficient bookmark management
const bookmarkedQuestions = await Question.findAll({
  include: [{
    model: User,
    as: 'bookmarkedBy',
    where: { id: userId },
    through: { attributes: [] }
  }],
  where: { isActive: true }
});

Backup Strategy

# Daily backup script
#!/bin/bash
BACKUP_DIR="/var/backups/mysql"
DATE=$(date +%Y%m%d_%H%M%S)
DB_NAME="interview_quiz_db"

# Create backup directory
mkdir -p $BACKUP_DIR

# Backup database
mysqldump -u root -p$MYSQL_PASSWORD \
  --single-transaction \
  --routines \
  --triggers \
  --events \
  $DB_NAME | gzip > $BACKUP_DIR/${DB_NAME}_${DATE}.sql.gz

# Delete backups older than 30 days
find $BACKUP_DIR -name "*.sql.gz" -mtime +30 -delete

echo "Backup completed: ${DB_NAME}_${DATE}.sql.gz"

Environment Variables (.env.example)

# Application
NODE_ENV=development
PORT=3000
API_PREFIX=/api

# Database
DB_HOST=localhost
DB_PORT=3306
DB_NAME=interview_quiz_db
DB_USER=root
DB_PASSWORD=your_secure_password
DB_DIALECT=mysql

# JWT
JWT_SECRET=your_jwt_secret_key_here
JWT_EXPIRE=24h

# Redis (for caching)
REDIS_HOST=localhost
REDIS_PORT=6379

# Email (for notifications)
SMTP_HOST=smtp.gmail.com
SMTP_PORT=587
SMTP_USER=your_email@gmail.com
SMTP_PASSWORD=your_email_password

# Frontend URL
FRONTEND_URL=http://localhost:4200

# Rate Limiting
RATE_LIMIT_WINDOW_MS=900000
RATE_LIMIT_MAX_REQUESTS=100

End of User Stories Document

Version 2.0 - MySQL Edition - Last Updated: November 2025