Backend half of the dashboard stat-card redesign. Three new data points the old DashboardResponse had no way to compute: - Week-over-week rating deltas: UserRating/CcsUserRating only ever stored the current Elo (mutated in place, UpdatedUtc just means "last touched"), so there was no way to know what a rating was 7 days ago. Added UserRatingSnapshot (new collection, unique on UserId+DateUtc) and UserRatingSnapshotService, a BackgroundService following AnswerStatisticsMaintenanceService's exact shape (a PeriodicTimer plus a Mongo lease so replicas behind the HPA don't race), writing one snapshot per user per day. No historical backfill - deltas are simply null for a user's first ~7 days after this ships, which the DTO represents honestly via nullable ints rather than a fake "+0". - Percentile rank: DashboardStore now counts how many users have a higher OverallElo/Elo than the current user out of the total. - Exam Readiness + projected pass rate: reuses the existing, tested IRT-based ExamSimulationScore.PassProbability (a real normal-CDF estimate of scoring >=200, computed in ExamSimulationScoring.Calculate) rather than inventing a new prediction model. DashboardStore pulls the latest completed simulation's score directly and maps PassProbability to a High/Medium/Low label via tunable thresholds. - Average Score's "+6% vs last 100" needed no new data source at all - just one more slice (Skip(100).Take(100)) over the QuestionAttempts already loaded for FirstAttemptAccuracy. Added DashboardStore.Percentile/ReadinessLabel as pure static helpers (matching the existing Percentage/CalculateCurrentStreak pattern) and unit tests for both. Full backend suite: 165 passed, 0 failed.
70 lines
2.5 KiB
C#
70 lines
2.5 KiB
C#
namespace QuestionsApi.Models;
|
|
|
|
public sealed class DashboardResponse
|
|
{
|
|
public int QuestionBankRating { get; set; } = 1000;
|
|
public int RatedQuestionCount { get; set; }
|
|
public int CcsRating { get; set; } = 1000;
|
|
public int RatedCcsCaseCount { get; set; }
|
|
public int QuestionsCompleted { get; set; }
|
|
public int CcsCasesCompleted { get; set; }
|
|
public int FirstAttemptAccuracy { get; set; }
|
|
public int AccuracySampleSize { get; set; }
|
|
public int? AccuracyDeltaVsPreviousSample { get; set; }
|
|
public int? QuestionBankRatingDeltaThisWeek { get; set; }
|
|
public int? QuestionBankPercentile { get; set; }
|
|
public int? CcsRatingDeltaThisWeek { get; set; }
|
|
public int? CcsPercentile { get; set; }
|
|
public string? ExamReadinessLabel { get; set; }
|
|
public int? ExamReadinessProjectedPassPercent { get; set; }
|
|
public int QuestionsThisWeek { get; set; }
|
|
public int StudyTimeSecondsThisWeek { get; set; }
|
|
public int CurrentStreak { get; set; }
|
|
public int MissedQuestionCount { get; set; }
|
|
public int DynamicReviewsDue { get; set; }
|
|
public int BookmarkCount { get; set; }
|
|
public int NoteCount { get; set; }
|
|
public int FlashcardsDue { get; set; }
|
|
public int FlashcardsNewAvailable { get; set; }
|
|
public int FlashcardsReviewedThisWeek { get; set; }
|
|
public List<DashboardTrendPoint> PerformanceTrend { get; set; } = [];
|
|
public List<DashboardSystemPerformance> Systems { get; set; } = [];
|
|
public List<DashboardActivityDay> WeeklyActivity { get; set; } = [];
|
|
public List<DashboardRecentActivity> RecentActivity { get; set; } = [];
|
|
}
|
|
|
|
public sealed class DashboardTrendPoint
|
|
{
|
|
public DateTime DateUtc { get; set; }
|
|
public int Correct { get; set; }
|
|
public int Total { get; set; }
|
|
public int Accuracy { get; set; }
|
|
public int? QuestionBankRating { get; set; }
|
|
public int? CcsRating { get; set; }
|
|
}
|
|
|
|
public sealed class DashboardSystemPerformance
|
|
{
|
|
public string System { get; set; } = "General";
|
|
public int Correct { get; set; }
|
|
public int Total { get; set; }
|
|
public int Accuracy { get; set; }
|
|
}
|
|
|
|
public sealed class DashboardActivityDay
|
|
{
|
|
public DateTime DateUtc { get; set; }
|
|
public int Questions { get; set; }
|
|
public int CcsCases { get; set; }
|
|
public int StudyTimeSeconds { get; set; }
|
|
}
|
|
|
|
public sealed class DashboardRecentActivity
|
|
{
|
|
public string Type { get; set; } = "question";
|
|
public string Title { get; set; } = "";
|
|
public string Detail { get; set; } = "";
|
|
public DateTime OccurredUtc { get; set; }
|
|
public string Route { get; set; } = "";
|
|
}
|