Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/DerBasilisk/SEA-ServicioEvaluaconAsistida/llms.txt

Use this file to discover all available pages before exploring further.

Sealearn’s motivation layer is built on a set of interlocking systems — experience points, levels, limited lives, a daily streak, spendable currency, and unlockable achievements — all stored directly on the User model and updated in real time as students complete lessons, win duels, and hit daily goals. Every system is designed to reward consistency and mastery rather than mere participation.

XP and Leveling

Every action that earns experience points calls user.addXP(amount):
userSchema.methods.addXP = function (amount) {
  this.xp += amount;
  const xpForNext = Math.floor(100 * Math.pow(1.5, this.level - 1));
  const leveledUp = this.xp >= xpForNext;
  if (leveledUp) this.level += 1;
  return { newXP: this.xp, leveledUp, newLevel: this.level };
};
The threshold for the next level follows an exponential curve:
xpForNextLevel = floor(100 × 1.5^(level - 1))
So level 1 requires 100 XP, level 2 requires 150 XP, level 3 requires 225 XP, and so on. The pre('save') hook also enforces level-ups, catching any direct xp mutations that bypass addXP. The xpProgress virtual computes the student’s percentage progress toward the next level, clamped to [0, 100]:
userSchema.virtual("xpProgress").get(function () {
  const xpForCurrent = Math.floor(100 * Math.pow(1.5, this.level - 2)) || 0;
  const xpForNext    = this.xpForNextLevel;
  return Math.min(100, ((this.xp - xpForCurrent) / (xpForNext - xpForCurrent)) * 100);
});
Leveling up during a lesson completion is reported in the API response as { leveledUp: true, newLevel: N }, allowing the frontend to display a level-up animation without an additional request.

Hearts (Lives) System

Hearts are a scarce resource that gates access to lessons and keeps students focused. The hearts sub-document on the User model contains:
hearts: {
  current:    { type: Number, default: 5, min: 0, max: 5 },
  lastRefill: { type: Date,   default: Date.now },
}
  • Maximum: 5 hearts at any time.
  • Lose one: every wrong answer in a lesson (or a failed typing / Python exercise) calls user.loseHeart(), which decrements hearts.current and records the timestamp in hearts.lastRefill to start the refill timer.
  • Auto-refill: user.checkHeartRefill() runs on lesson start and calculates floor(elapsed / 30 minutes) hearts to restore. Hearts never exceed 5.
  • Manual refill: user.refillHearts() instantly restores all 5 hearts and resets the timestamp. This costs gems and is available through the in-app shop.
A student with 0 hearts cannot start a lesson. The startLesson controller returns HTTP 403 with the message "No tenés corazones para iniciar una lección" until at least one heart has been refilled.

Daily Streak

The streak system encourages students to return every single day. Calling user.updateStreak() at lesson completion handles all the logic:
userSchema.methods.updateStreak = function () {
  // ...
  if (diffDays === 0) return;          // already practiced today
  if (diffDays === 1) {
    this.streak.current += 1;          // consecutive day — extend streak
  } else {
    this.streak.current = 1;           // gap > 1 day — reset to 1
  }
  if (this.streak.current > this.streak.longest) {
    this.streak.longest = this.streak.current;
  }
  this.streak.lastActivityDate = now;
};
The streak sub-document tracks four values:
FieldTypeDescription
currentNumberActive streak length in days
longestNumberAll-time personal best
lastActivityDateDateTimestamp of the most recent lesson completion
freezeUsedBooleanWhether a streak freeze powerup has been used this period
The currentStreak virtual reads lastActivityDate and returns 0 if the gap to today is more than 1 day, even if streak.current has not been reset yet (lazy evaluation). The freeze flag (freezeUsed) mirrors Duolingo’s streak freeze mechanic, allowing one missed day to be pardoned.

Gems

Gems are Sealearn’s in-app currency, stored as a plain Number on the User model (gems, minimum 0). They are earned by:
  • Completing lessons (each lesson has a gemsReward field)
  • Earning a perfect lesson score (+5 bonus gems)
  • Unlocking achievements that specify a reward.gems value
Gems are spent in the shop to purchase:
  • Heart refills — instantly restore all 5 hearts
  • Frames (ShopItem documents referenced by activeFrame)
  • Backgrounds (ShopItem documents referenced by activeBackground)

Daily Goals

Students can set a personal daily XP target to help build a learning habit. The four available options are:
GoalXP per DayIntended audience
Casual10 XPOccasional learners
Regular20 XPDefault recommendation
Serious30 XPMotivated students
Intense50 XPPower learners
The dailyGoal field defaults to 10 and is constrained to the enum [10, 20, 30, 50]. Progress toward the daily goal is tracked against XP earned within the current calendar day and shown in the home screen dashboard.

Achievements

The Achievement model defines unlockable milestones. Each achievement has:
  • key — a unique string identifier (e.g. "streak_7", "perfect_lesson")
  • category — one of streak, xp, lessons, accuracy, social, special
  • condition.type — the event type: streak_days, total_xp, lessons_completed, perfect_lessons, subjects_started, or daily_goal_days
  • condition.threshold — the numeric target (e.g. 7 for a 7-day streak)
  • reward — an { xp, gems } object awarded on first unlock
  • raritycommon, rare, epic, or legendary
When a lesson is completed, checkAndGrantAchievements(user, streak, progress) is called. Any newly unlocked achievements are appended to the user’s achievements array (stored as ObjectId references to Achievement documents) and returned in the lesson completion response as newAchievements. A selection of built-in achievements seeded by Achievement.seedDefaults():
KeyNameConditionRewardRarity
first_lesson¡Primer paso!Complete 1 lesson10 XP + 5 gemsCommon
streak_3En racha3-day streak20 XP + 10 gemsCommon
streak_7Semana completa7-day streak50 XP + 20 gemsRare
streak_30Imparable30-day streak200 XP + 100 gemsLegendary
perfect_lessonPerfección1 perfect lesson25 XP + 15 gemsRare
xp_100Estudiante aplicadoAccumulate 100 XP10 gemsCommon
xp_1000ExpertoAccumulate 1000 XP50 gemsEpic
lessons_10ConstanteComplete 10 lessons30 XP + 20 gemsCommon

Leaderboard

Sealearn maintains two leaderboard views derived from the xp field on the User model:
  • Global leaderboard — all active users ranked by total XP
  • Friends leaderboard — the same ranking filtered to the user’s accepted friendships only
Both leaderboards are accessible from the social section and update in near-real time as lessons are completed.

Build docs developers (and LLMs) love