Skip to content

feat: Add Interview Streak Tracking Feature (#625) - #1533

Open
Aasritha-sure wants to merge 1 commit into
Canopus-Labs:mainfrom
Aasritha-sure:issue-625-clean
Open

feat: Add Interview Streak Tracking Feature (#625)#1533
Aasritha-sure wants to merge 1 commit into
Canopus-Labs:mainfrom
Aasritha-sure:issue-625-clean

Conversation

@Aasritha-sure

@Aasritha-sure Aasritha-sure commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Summary

This PR implements the Interview Streak Tracking feature.

Changes made

  • Added interview streak tracking logic.
  • Tracks consecutive interview practice days.
  • Updates longest streak.
  • Supports achievement tracking for streak milestones.
  • Updated user model to persist streak information.
  • Integrated streak updates into the interview session flow.

Fixes #625

Summary

Ready to merge. The PR adds interview practice streak tracking with milestone achievements, streak persistence, and session-flow integration.

Key changes

  • Tracks current streak, longest streak, and last practice date.
  • Resets the current streak after a missed practice day.
  • Adds 3-day, 7-day, and 30-day achievement milestones.
  • Updates streak data after successful interview sessions.
  • Displays accurate streak data through profile and achievement endpoints.

@coderabbitai

coderabbitai Bot commented Aug 7, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The PR adds streak fields and milestone achievements. Session creation updates current and longest streaks. Profile and achievement reads reset the current streak after more than one missed UTC calendar day.

Changes

Interview practice streak tracking

Layer / File(s) Summary
Streak data and achievement contracts
backend/models/User.js, backend/constants/achievements.js
UserSchema stores current streak, longest streak, and last practice date. The valid achievement set includes 3-day, 7-day, and 30-day streak achievements.
Session streak updates
backend/controllers/sessionController.js
Session creation updates streak state, longest streak, practice date, and milestone achievements within the transaction.
Stale streak reset reads
backend/controllers/achievementController.js, backend/controllers/authController.js
Achievement and profile reads reset currentStreak to zero when more than one UTC calendar day has elapsed since the last practice date.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant SessionController
  participant Session
  participant User
  SessionController->>Session: create session and questions
  SessionController->>User: load user in transaction
  SessionController->>User: update streak and achievements
  User-->>SessionController: save completed
Loading

Possibly related PRs

Suggested reviewers: hariom888, karanunique

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning The PR implements streak tracking, persistence, resets, and milestone badges, but it does not show dashboard display integration required by issue #625. Add dashboard integration that displays the user’s current interview practice streak.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly identifies the interview streak tracking feature and matches the primary changes.
Out of Scope Changes check ✅ Passed All changes support interview streak tracking, streak resets, persistence, or milestone achievements described in issue #625.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands.

@Aasritha-sure

Copy link
Copy Markdown
Contributor Author

Hi @KaranUnique,

I have recreated this PR from a clean branch to keep it scoped only to Issue #625.

Changes made
Added interview streak tracking.
Tracks consecutive interview practice days.
Updates the longest streak.
Integrated streak updates into the interview session flow.
Added achievement support for streak milestones.
Updated the user model to persist streak data.
This PR contains only the files required for the Interview Streak feature and excludes the unrelated Google Calendar changes from my previous attempt.

Kindly review the changes. Thank you!

now you can merge> pls give me 150 points.....>thankyou!!

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@backend/constants/achievements.js`:
- Around line 13-15: Remove "3-Day Streak", "7-Day Streak", and "30-Day Streak"
from VALID_ACHIEVEMENTS, or explicitly reject them in saveAchievements, so
clients cannot write server-managed streak badges. Preserve sessionController as
the only code path that awards these identifiers.

In `@backend/controllers/achievementController.js`:
- Around line 16-18: Replace the direct streak reset and save in both
achievementController.js (lines 16-18) and authController.js (lines 412-414)
with an atomic conditional update that matches the user only when
lastPracticeDate remains before the UTC yesterday boundary. In getUserProfile,
reload the user after the conditional update and before res.json(user) so
skipped resets return the latest streak.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 3977c7fe-cfeb-46b7-aa19-863367418479

📥 Commits

Reviewing files that changed from the base of the PR and between 4ba01aa and 9afe87e.

📒 Files selected for processing (5)
  • backend/constants/achievements.js
  • backend/controllers/achievementController.js
  • backend/controllers/authController.js
  • backend/controllers/sessionController.js
  • backend/models/User.js

Comment on lines +13 to +15
"3-Day Streak",
"7-Day Streak",
"30-Day Streak",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Keep streak badges out of the client-writable allowlist.

saveAchievements accepts every value in VALID_ACHIEVEMENTS. A client can submit "3-Day Streak", "7-Day Streak", or "30-Day Streak" without completing the required streak.

Reject server-managed streak badges in saveAchievements, or remove these identifiers from VALID_ACHIEVEMENTS. Keep sessionController as the only writer for these badges.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@backend/constants/achievements.js` around lines 13 - 15, Remove "3-Day
Streak", "7-Day Streak", and "30-Day Streak" from VALID_ACHIEVEMENTS, or
explicitly reject them in saveAchievements, so clients cannot write
server-managed streak badges. Preserve sessionController as the only code path
that awards these identifiers.

Comment on lines +16 to +18
if (diffDays > 1) {
user.currentStreak = 0;
await user.save();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

# Inspect the affected handlers and Mongoose concurrency configuration.
ast-grep outline backend/controllers/achievementController.js --items all
ast-grep outline backend/controllers/authController.js --items all
ast-grep outline backend/models/User.js --items all

# Expect no custom protection to be required after the reset becomes conditional.
rg -n -C 3 'optimisticConcurrency|versionKey|pre\(|post\(|currentStreak|lastPracticeDate' \
  backend/controllers/achievementController.js \
  backend/controllers/authController.js \
  backend/controllers/sessionController.js \
  backend/models/User.js

Repository: Canopus-Labs/PrepPilot

Length of output: 8050


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

printf '%s\n' '--- achievement handler ---'
sed -n '1,80p' backend/controllers/achievementController.js

printf '%s\n' '--- profile handler ---'
sed -n '390,455p' backend/controllers/authController.js

printf '%s\n' '--- session write path ---'
sed -n '70,155p' backend/controllers/sessionController.js

printf '%s\n' '--- User schema ---'
sed -n '1,110p' backend/models/User.js

printf '%s\n' '--- dependency and schema configuration ---'
rg -n -C 2 '"mongoose"|optimisticConcurrency|versionKey|findOneAndUpdate|findByIdAndUpdate|save\(' \
  package.json backend package-lock.json yarn.lock 2>/dev/null || true

Repository: Canopus-Labs/PrepPilot

Length of output: 35642


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

printf '%s\n' '--- authentication middleware ---'
sed -n '1,180p' backend/middlewares/authMiddleware.js

printf '%s\n' '--- routes for the affected handlers ---'
rg -n -C 4 'getUserProfile|getAchievements|createSession|profile|achievements' \
  backend/routes backend/controllers backend/middlewares

printf '%s\n' '--- relevant controller tests ---'
sed -n '1,240p' backend/tests/achievementController.unit.test.js
rg -n -C 5 'getUserProfile|currentStreak|lastPracticeDate|createSession' backend/tests

Repository: Canopus-Labs/PrepPilot

Length of output: 27972


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

python3 - <<'PY'
from pathlib import Path
import re

achievement = Path("backend/controllers/achievementController.js").read_text()
auth = Path("backend/controllers/authController.js").read_text()
session = Path("backend/controllers/sessionController.js").read_text()
user = Path("backend/models/User.js").read_text()

checks = {
    "achievement reads then saves reset": re.search(
        r"findById\(req\.user\._id\).*?currentStreak.*?user\.currentStreak\s*=\s*0;\s*await user\.save\(\)",
        achievement, re.S
    ),
    "profile uses middleware-loaded document": re.search(
        r"const user = req\.user;.*?user\.currentStreak\s*=\s*0;\s*await user\.save\(\)",
        auth, re.S
    ),
    "session updates streak and practice date": re.search(
        r"user\.currentStreak.*?user\.lastPracticeDate\s*=\s*now;.*?await user\.save",
        session, re.S
    ),
    "User schema has no optimisticConcurrency": not re.search(
        r"optimisticConcurrency\s*:\s*true", user
    ),
}

for name, result in checks.items():
    print(f"{'PASS' if result else 'FAIL'}: {name}")

if not all(checks.values()):
    raise SystemExit(1)

print("Both reset handlers can issue an unconditional save after a stale read.")
print("The session path can write a new currentStreak and lastPracticeDate between that read and save.")
PY

Repository: Canopus-Labs/PrepPilot

Length of output: 509


Prevent stale streak resets from overwriting new practice data.

Use an atomic conditional update in both handlers. Match the user only when lastPracticeDate is still before the UTC yesterday boundary. In getUserProfile, reload the user before res.json(user) so a skipped reset returns the current streak.

📍 Affects 2 files
  • backend/controllers/achievementController.js#L16-L18 (this comment)
  • backend/controllers/authController.js#L412-L414
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@backend/controllers/achievementController.js` around lines 16 - 18, Replace
the direct streak reset and save in both achievementController.js (lines 16-18)
and authController.js (lines 412-414) with an atomic conditional update that
matches the user only when lastPracticeDate remains before the UTC yesterday
boundary. In getUserProfile, reload the user after the conditional update and
before res.json(user) so skipped resets return the latest streak.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

TAdd Interview Streak Tracking Feature

1 participant