Skip to main content
A streak measures how many consecutive days a user has completed at least one task. Streaks are one of the core motivational mechanics in Mais Hábito.
Missing a day resets current_streak to 0. The max_streak field is never reduced — it permanently records the user’s all-time highest streak.

User model — streak fields

models/User.ts

How streaks are incremented

Streak incrementing happens inside taskCompletionService.completeTask(), triggered by POST /api/task-completions. Only the first task completion of the day advances the streak; subsequent completions on the same day have no further effect on current_streak.
services/taskCompletion.service.ts
“Today” is determined by the UTC date. The query in taskCompletionRepository.findByUserIdToday() compares completed_at against the current UTC date. Users in time zones where midnight differs from UTC may see a streak advance slightly earlier or later than their local midnight.

The overnight streak-reset cron job

Incrementing the streak at completion time is only half of the mechanism. The other half is detecting when a user missed a day. This is handled by a scheduled cron job defined in src/jobs/streakReset.job.ts and started at server boot via startStreakCronJob(). The job runs every day at midnight UTC using node-cron:
jobs/streakReset.job.ts
The SQL logic: any user whose current_streak is greater than 0 and who has no task_completions row with a completed_at in yesterday’s date window has their current_streak set to 0.

Streak timeline example

After the missed day (Day 4), the cron job resets current_streak to 0. When the user resumes on Day 5, the streak begins rebuilding from 1. The max_streak of 3 is preserved throughout.