Skip to main content

Overview

CUIDO’s gamification system encourages continuous participation through a comprehensive rewards structure embedded in the Employee model. The system includes points, levels, badges, and streaks to motivate healthcare professionals.

Gamification Data Structure

The gamification system is part of the Employee model:
// src/models/Employee.js
gamification: {
  totalPoints: { type: Number, default: 0 },
  currentStreak: { type: Number, default: 0 },
  maxStreak: { type: Number, default: 0 },
  level: { type: Number, default: 1 },
  badges: [{
    name: String,
    earnedAt: Date,
    description: String
  }]
}

Points System

Survey Completion

+5 pointsCompleting daily wellness surveys

Course Completion

+20 pointsFinishing a microlearning course

Badge Earned

+10 bonus pointsUnlocking new achievements

Level Up

+25 bonus pointsAdvancing to next level

Earning Points

Points are automatically awarded through the diagnostic service:
// src/services/diagnosticService.js
async updateEmployeeMetrics(employee, responses, riskAnalysis) {
  // Update wellness metrics
  employee.wellnessMetrics = {
    currentMoodScore: this.moodToScore(responses.moodToday) * 5,
    averageWorkload: responses.workloadLevel,
    teamSupportScore: responses.teamSupport,
    satisfactionScore: responses.jobSatisfaction,
    riskLevel: riskAnalysis.riskLevel
  };

  // Award points for participation
  employee.gamification.totalPoints += 5;
  
  // Update streak
  employee.updateStreak();
  
  // Recalculate level
  employee.gamification.level = employee.calculateLevel();
  
  // Check for badge eligibility
  await this.checkAndAwardBadges(employee);
  
  await employee.save();
}

Levels System

Levels are calculated based on total points accumulated:

Level Calculation Method

// Employee model method
employeeSchema.methods.calculateLevel = function() {
  return Math.floor(this.gamification.totalPoints / 100) + 1;
};

Level Progression Table

LevelPoints RequiredTypical Timeline
10-99Starting level
2100-199~3 weeks of daily surveys
3200-299~6 weeks + 1-2 courses
4300-399~2-3 months active participation
5400-499~3-4 months + multiple courses
10+900+6+ months of consistent engagement
Formula: Level = ⌊Total Points / 100⌋ + 1Every 100 points = 1 level

Streaks System

Streaks track consecutive days of survey participation:

Streak Update Method

// Employee model method
employeeSchema.methods.updateStreak = function() {
  this.gamification.currentStreak += 1;
  
  if (this.gamification.currentStreak > this.gamification.maxStreak) {
    this.gamification.maxStreak = this.gamification.currentStreak;
  }
};

Streak Milestones

Participación Semanal Badge
if (employee.gamification.currentStreak >= 7) {
  badges.push({
    name: 'Participación Semanal',
    description: '7 días consecutivos respondiendo encuestas',
    earnedAt: new Date()
  });
}
Reward: Badge + Recognition
Streaks reset if a day is missed. The maxStreak field preserves the longest streak achieved.

Badges System

Badges are achievements unlocked through specific actions or milestones:

Badge Award Logic

// src/services/diagnosticService.js
async checkAndAwardBadges(employee) {
  const badges = [];

  // Badge: Weekly Participation
  if (employee.gamification.currentStreak >= 7) {
    badges.push({
      name: 'Participación Semanal',
      description: '7 días consecutivos respondiendo encuestas',
      earnedAt: new Date()
    });
  }

  // Badge: Level Milestone
  if (employee.gamification.level === 5) {
    badges.push({
      name: 'Colaborador Comprometido',
      description: 'Alcanzó el nivel 5',
      earnedAt: new Date()
    });
  }

  // Badge: Positive Wellbeing
  if (employee.wellnessMetrics.currentMoodScore >= 4.5) {
    badges.push({
      name: 'Ánimo Positivo',
      description: 'Mantiene un excelente estado de ánimo',
      earnedAt: new Date()
    });
  }

  // Add only new badges (prevent duplicates)
  badges.forEach(badge => {
    const exists = employee.gamification.badges.some(b => b.name === badge.name);
    if (!exists) {
      employee.gamification.badges.push(badge);
      employee.gamification.totalPoints += 10; // Bonus points
    }
  });
}

Available Badges

Participación Semanal

7 consecutive daily surveysBonus: +10 points

Colaborador Comprometido

Reach Level 5Bonus: +10 points

Ánimo Positivo

Maintain mood score ≥ 4.5/5Bonus: +10 points

Participativo

Complete surveys regularlyType: Recognition badge

Aprendiz

Complete learning coursesBonus: +10 points

Estrella

Employee of the MonthBonus: +100 points

Badge Schema

Each badge has:
  • name: Unique identifier
  • description: What was accomplished
  • earnedAt: Timestamp of achievement

Gamification Statistics

Get comprehensive stats for an employee:
// src/services/diagnosticService.js
async getGamificationStats(employeeId) {
  const employee = await Employee.findById(employeeId);
  
  // Get hospital ranking
  const hospitalEmployees = await Employee.find({
    hospitalId: employee.hospitalId,
    isActive: true
  }).sort({ 'gamification.totalPoints': -1 });
  
  const rank = hospitalEmployees.findIndex(emp => 
    emp._id.toString() === employeeId
  ) + 1;
  
  // Calculate progress to next level
  const currentLevelPoints = (employee.gamification.level - 1) * 100;
  const nextLevelPoints = employee.gamification.level * 100;
  const progressToNextLevel = 
    ((employee.gamification.totalPoints - currentLevelPoints) / 100) * 100;
  
  return {
    employee: {
      name: employee.personalInfo.name,
      department: employee.jobInfo.department,
      position: employee.jobInfo.position
    },
    gamification: {
      totalPoints: employee.gamification.totalPoints,
      currentLevel: employee.gamification.level,
      currentStreak: employee.gamification.currentStreak,
      maxStreak: employee.gamification.maxStreak,
      badges: employee.gamification.badges.length,
      badgesList: employee.gamification.badges
    },
    ranking: {
      position: rank,
      totalEmployees: hospitalEmployees.length,
      percentile: Math.round((1 - (rank / hospitalEmployees.length)) * 100)
    },
    progress: {
      currentLevelPoints,
      nextLevelPoints,
      progressPercentage: Math.round(progressToNextLevel),
      pointsToNextLevel: nextLevelPoints - employee.gamification.totalPoints
    },
    achievements: {
      recentBadges: employee.gamification.badges
        .sort((a, b) => new Date(b.earnedAt) - new Date(a.earnedAt))
        .slice(0, 3),
      upcomingMilestones: this.getUpcomingMilestones(employee)
    }
  };
}

Response Example

{
  "employee": {
    "name": "Dr. María González",
    "department": "urgencias",
    "position": "medico"
  },
  "gamification": {
    "totalPoints": 275,
    "currentLevel": 3,
    "currentStreak": 12,
    "maxStreak": 15,
    "badges": 4,
    "badgesList": [
      {
        "name": "Participación Semanal",
        "description": "7 días consecutivos",
        "earnedAt": "2024-03-01T10:00:00Z"
      }
    ]
  },
  "ranking": {
    "position": 5,
    "totalEmployees": 120,
    "percentile": 96
  },
  "progress": {
    "currentLevelPoints": 200,
    "nextLevelPoints": 300,
    "progressPercentage": 75,
    "pointsToNextLevel": 25
  }
}

Upcoming Milestones

Show employees their next achievements:
getUpcomingMilestones(employee) {
  const milestones = [];
  
  // Next streak milestone
  const nextStreakMilestone = [10, 15, 30].find(ms => 
    ms > employee.gamification.currentStreak
  );
  
  if (nextStreakMilestone) {
    milestones.push({
      name: `Racha de ${nextStreakMilestone} días`,
      progress: Math.round(
        (employee.gamification.currentStreak / nextStreakMilestone) * 100
      ),
      reward: `${nextStreakMilestone * 2} puntos bonus`
    });
  }
  
  // Next level
  if (employee.gamification.level < 10) {
    milestones.push({
      name: `Nivel ${employee.gamification.level + 1}`,
      progress: Math.round(
        ((employee.gamification.totalPoints % 100) / 100) * 100
      ),
      reward: 'Nueva insignia'
    });
  }
  
  return milestones.slice(0, 2); // Max 2 upcoming
}

Employee Ranking

View top performers by hospital:
// src/controllers/recognitionController.js
export const getEmployeeRanking = asyncHandler(async (req, res) => {
  const { hospitalId } = req.params;
  const { limit = 10 } = req.query;

  const ranking = await Recognition.aggregate([
    {
      $lookup: {
        from: 'employees',
        localField: 'employeeId',
        foreignField: '_id',
        as: 'employee'
      }
    },
    {
      $match: {
        'employee.hospitalId': hospitalId
      }
    },
    {
      $group: {
        _id: '$employeeId',
        totalPoints: { $sum: '$pointsAwarded' },
        totalRecognitions: { $sum: 1 },
        employee: { $first: '$employee' }
      }
    },
    {
      $sort: { totalPoints: -1 }
    },
    {
      $limit: parseInt(limit)
    }
  ]);

  sendSuccess(res, 'Ranking obtenido', { ranking });
});

Gamified Survey Experience

Advanced gamification for interactive surveys:
async processGamifiedSurvey(employeeId, surveyType, interactions) {
  let totalPoints = 0;
  const newBadges = [];
  
  // Award points per interaction type
  for (const interaction of interactions) {
    switch (interaction.type) {
      case 'emoji_slider':
        totalPoints += 3;
        break;
      case 'card_swipe':
        totalPoints += 4;
        break;
      case 'quick_tap':
        totalPoints += 2;
        break;
      case 'voice_note':
        totalPoints += 8;
        break;
    }
  }
  
  // Bonus for completion
  if (interactions.length >= 5) {
    totalPoints += 10;
    newBadges.push({
      name: 'Participación Completa',
      description: 'Completó toda la encuesta interactiva',
      earnedAt: new Date()
    });
  }
  
  // Bonus for speed (< 3 minutes)
  if (interactions.completionTime < 180) {
    totalPoints += 5;
    newBadges.push({
      name: 'Respuesta Rápida',
      description: 'Completó en menos de 3 minutos',
      earnedAt: new Date()
    });
  }
  
  // Update employee
  const oldLevel = employee.gamification.level;
  employee.gamification.totalPoints += totalPoints;
  employee.gamification.level = employee.calculateLevel();
  
  // Check for level up
  const levelUp = employee.gamification.level > oldLevel;
  if (levelUp) {
    totalPoints += 25;
    employee.gamification.totalPoints += 25;
  }
  
  return {
    pointsEarned: totalPoints,
    newBadges,
    levelUp,
    currentLevel: employee.gamification.level,
    currentStreak: employee.gamification.currentStreak
  };
}

Integration with Recognition Module

The recognition service awards points for various achievements:
// src/services/recognitionService.js
getRecognitionConfig(type) {
  const configs = {
    'encuesta_completada': {
      rewardType: 'puntos',
      title: '¡Encuesta Completada!',
      description: 'Gracias por compartir tu feedback',
      points: 5,
      badge: 'participativo'
    },
    'curso_terminado': {
      rewardType: 'diploma',
      title: '¡Curso Completado!',
      description: 'Has terminado exitosamente',
      points: 20,
      badge: 'aprendiz'
    },
    'empleado_mes': {
      rewardType: 'mencion',
      title: '¡Empleado del Mes!',
      description: 'Reconocimiento por excelencia',
      points: 100,
      badge: 'estrella'
    }
  };
  
  return configs[type];
}

Gamification Best Practices

Immediate Feedback

Points and badges are awarded instantly upon completing actions

Progressive Rewards

Larger rewards for more significant achievements

Visible Progress

Always show progress to next milestone

Social Recognition

Public recognition wall for achievements

API Endpoints

Get complete gamification statistics for an employee.Response includes:
  • Total points and current level
  • Current and max streaks
  • All earned badges
  • Hospital ranking position
  • Progress to next level
  • Upcoming milestones
Get top performers leaderboard.Query Parameters:
  • limit: Number of top employees (default: 10)
Returns:
  • Ranked list by total points
  • Total recognitions per employee
  • Employee details

Next Steps

Recognition Module

Full documentation on the recognition system

Diagnostic Module

How surveys integrate with gamification

Build docs developers (and LLMs) love