12 KiB
Statistics Backend Tasks
Project: mnemo_cards_backend
Feature: Statistics System Upgrade
Created: 2025-11-08
Phase 1: Backend - Models and DTOs
Task 1.1: Create New DTOs in mnemo_cards_common ✅ PRIORITY
Estimated Time: 3-4 hours
Files to Create:
mnemo_cards_common/lib/src/dtos/user/data/pack_progress_dto.dart
@JsonSerializable()
@CopyWith()
class PackProgressDto {
final String packId;
final int totalCards;
final int learnedCards;
final int studyTimeMinutes;
final DateTime? lastStudyDate;
final DateTime? firstStudyDate;
final Map<String, int> cardAttempts;
final double averageAccuracy;
}
mnemo_cards_common/lib/src/dtos/user/achievement_dto.dart
@JsonSerializable()
@CopyWith()
class AchievementDto {
final String id;
final String title;
final String description;
final String? iconUrl;
final DateTime? unlockedAt;
final AchievementType type;
final double progress; // 0.0 to 1.0
}
enum AchievementType {
firstSteps,
streak,
wordsMaster,
perfectScore,
speedLearner,
dedicated,
}
mnemo_cards_common/lib/src/dtos/user/data/detailed_word_statistics_dto.dart
@JsonSerializable()
@CopyWith()
class DetailedWordStatisticsDto {
final String word;
final double correct;
final double incorrect;
final double skipped;
final Set<TestQuestionType> questionTypes;
final DateTime? lastReviewed;
final DateTime? firstLearned;
final double difficultyScore; // 0.0 to 1.0
final bool needsReview;
final String? packId;
}
mnemo_cards_common/lib/src/dtos/user/study_session_dto.dart
@JsonSerializable()
@CopyWith()
class StudySessionDto {
final String? sessionId;
final DateTime startTime;
final DateTime? endTime;
final int wordsLearned;
final int testsCompleted;
final double accuracy;
final String? packId;
final String? testId;
}
Steps:
- Create PackProgressDto with all fields
- Create AchievementDto and AchievementType enum
- Create DetailedWordStatisticsDto extending WordStatisticsDto
- Create StudySessionDto
- Run
./codegen.shto generate .g.dart files - Export all new DTOs in main export file
- Write unit tests for DTO serialization/deserialization
Task 1.2: Extend UserDataDto
Estimated Time: 1-2 hours
File: mnemo_cards_common/lib/src/dtos/user/data/user_data_dto.dart
Add Fields:
@JsonSerializable()
@CopyWith()
class UserDataDto {
// Existing
final AllWordsStatisticsDto? allWordsStatistics;
final AllTestsStatisticsDto? allTestsStatistics;
// NEW FIELDS
final DateTime? lastTimeOnline;
final int totalStudyTimeMinutes;
final int currentStreak;
final int longestStreak;
final Map<String, PackProgressDto> packProgress;
final List<DateTime> studyDates; // for streak calculation
final Map<String, int> categoryMinutes; // category -> minutes
final List<AchievementDto> achievements;
}
Steps:
- Add new fields to UserDataDto
- Update copyWith to include new fields
- Run codegen
- Update tests
Task 1.3: Create Backend Isar Models
Estimated Time: 2-3 hours
Files to Create:
mnemo_cards_common_backend/lib/src/models/pack_progress_model.dartmnemo_cards_common_backend/lib/src/models/achievement_model.dartmnemo_cards_common_backend/lib/src/models/study_session_model.dart
Steps:
- Create Isar models corresponding to DTOs
- Add toDto() methods
- Add fromDto() methods
- Update UserDataModel to include new relations
- Run codegen
- Write unit tests for model conversions
Phase 2: Backend - API Endpoints
Task 2.1: Create StatisticsCalculator Service
Estimated Time: 4-5 hours
File: mnemo_cards_backend/lib/statistics/statistics_calculator.dart (new)
Methods:
@lazySingleton
class StatisticsCalculator {
/// Calculate pack progress for user
Future<PackProgressDto> calculatePackProgress(
UserModel user,
String packId,
);
/// Calculate current streak
int calculateStreak(List<DateTime> studyDates);
/// Find difficult words that need review
List<DetailedWordStatisticsDto> findDifficultWords(
UserDataModel data,
{int limit = 20}
);
/// Calculate overall accuracy
double calculateAccuracy(AllWordsStatisticsDto stats);
/// Calculate daily study time
Map<DateTime, int> calculateDailyStudyTime(
List<StudySessionModel> sessions,
);
/// Calculate total study time
int calculateTotalStudyTime(UserDataModel data);
/// Get timeline statistics
Map<String, dynamic> getTimelineStatistics(
UserDataModel data,
{required String period, DateTime? from, DateTime? to}
);
}
Steps:
- Create StatisticsCalculator class
- Implement calculatePackProgress
- Implement calculateStreak (consecutive days logic)
- Implement findDifficultWords (based on accuracy)
- Implement calculateAccuracy
- Implement calculateDailyStudyTime
- Implement calculateTotalStudyTime
- Implement getTimelineStatistics
- Add to DI
- Write comprehensive unit tests
Task 2.2: Add Statistics Endpoints to UsersApiV2
Estimated Time: 4-5 hours
File: mnemo_cards_backend/lib/api/v2/users_api_v2.dart
New Endpoints:
/// GET /api/v2/users/me/statistics/detailed
/// Returns detailed user statistics
@Route.get('/users/me/statistics/detailed')
Future<Response> getDetailedStatistics(Request request);
/// GET /api/v2/users/me/statistics/packs
/// Returns statistics for all packs or specific pack
/// Query: ?packId=xxx
@Route.get('/users/me/statistics/packs')
Future<Response> getPacksStatistics(Request request);
/// GET /api/v2/users/me/statistics/words
/// Returns paginated word statistics
/// Query: ?packId=xxx&limit=50&offset=0&sortBy=difficulty&needsReview=true
@Route.get('/users/me/statistics/words')
Future<Response> getWordsStatistics(Request request);
/// GET /api/v2/users/me/statistics/timeline
/// Returns timeline statistics
/// Query: ?period=week&from=2024-01-01&to=2024-12-31
@Route.get('/users/me/statistics/timeline')
Future<Response> getTimelineStatistics(Request request);
/// POST /api/v2/users/me/sessions
/// Start or end study session
@Route.post('/users/me/sessions')
Future<Response> recordStudySession(Request request);
/// GET /api/v2/users/me/achievements
/// Returns user achievements
@Route.get('/users/me/achievements')
Future<Response> getAchievements(Request request);
Steps:
- Add getDetailedStatistics endpoint
- Add getPacksStatistics endpoint with optional packId filter
- Add getWordsStatistics endpoint with pagination and filters
- Add getTimelineStatistics endpoint
- Add recordStudySession endpoint
- Add getAchievements endpoint
- Implement proper error handling
- Add request validation
- Write integration tests for all endpoints
Task 2.3: Update UserManager with Statistics Methods
Estimated Time: 2-3 hours
File: mnemo_cards_backend/lib/user/user_manager.dart
New Methods:
class UserManager {
final StatisticsCalculator _statsCalculator;
// Existing methods...
/// Get detailed user statistics
Future<UserDataDto> getDetailedStatistics(UserModel user);
/// Get pack statistics
Future<List<PackProgressDto>> getPacksStatistics(
UserModel user,
{String? packId}
);
/// Get word statistics with pagination
Future<Map<String, dynamic>> getWordsStatistics(
UserModel user, {
String? packId,
int limit = 50,
int offset = 0,
String sortBy = 'difficulty',
bool needsReview = false,
});
/// Record study session
Future<void> recordStudySession(
UserModel user,
StudySessionDto session,
);
/// Update user streak
Future<void> updateStreak(UserModel user);
}
Steps:
- Add StatisticsCalculator to constructor
- Implement getDetailedStatistics
- Implement getPacksStatistics with optional filtering
- Implement getWordsStatistics with pagination/sorting
- Implement recordStudySession
- Implement updateStreak (call daily)
- Write unit tests
Phase 3: Backend - Automatic Tracking
Task 3.1: Create Session Tracking Middleware
Estimated Time: 3-4 hours
File: mnemo_cards_backend/lib/statistics/session_tracker.dart (new)
Features:
- Track when user starts/ends session
- Auto-update lastTimeOnline
- Calculate session duration
- Store session in database
Steps:
- Create SessionTracker class
- Add session start/end logic
- Integrate with existing auth middleware
- Store active sessions in memory (with TTL)
- Auto-cleanup expired sessions
- Write unit tests
Task 3.2: Add Hooks for Statistics Updates
Estimated Time: 2-3 hours
Files to Modify:
mnemo_cards_backend/lib/api/v2/users_api_v2.dart(addUserTestStatistics)mnemo_cards_backend/lib/user/user_manager.dart(addTestStatistics)
Add After Test Completion:
- Update pack progress
- Update streak (if needed)
- Check and award achievements
- Update total study time
Steps:
- Add hook in addTestStatistics
- Call statistics calculator
- Update pack progress
- Update streak
- Trigger achievement check
- Write tests
Task 3.3: Create Achievement Manager
Estimated Time: 4-5 hours
File: mnemo_cards_backend/lib/statistics/achievement_manager.dart (new)
Features:
@lazySingleton
class AchievementManager {
/// Check and award achievements after action
Future<List<AchievementDto>> checkAchievements(UserModel user);
/// Check specific achievement
Future<AchievementDto?> checkAchievement(
UserModel user,
AchievementType type,
);
/// Award achievement
Future<void> awardAchievement(
UserModel user,
AchievementDto achievement,
);
/// Get all possible achievements
List<AchievementDto> getAllAchievements();
}
Achievement Types:
- First word learned
- First test completed
- First pack completed
- Streak milestones (3, 7, 30, 100 days)
- Words milestones (10, 50, 100, 500, 1000)
- Perfect test score
- Speed learner
- Night owl / Early bird
- Total study time milestones
Steps:
- Create AchievementManager
- Define all achievement types
- Implement check logic for each type
- Implement award logic
- Add to DI
- Write comprehensive tests
Phase 4: Testing
Task 4.1: Unit Tests
Estimated Time: 3-4 hours
Test Files:
test/statistics/statistics_calculator_test.darttest/statistics/achievement_manager_test.darttest/statistics/session_tracker_test.darttest/user/user_manager_statistics_test.dart
Coverage:
- All StatisticsCalculator methods
- Achievement checking logic
- Session tracking
- DTO conversions
- Streak calculations
- Difficulty calculations
Task 4.2: Integration Tests
Estimated Time: 2-3 hours
Test File: test/api/v2/users_api_v2_statistics_test.dart
Tests:
- GET /users/me/statistics/detailed
- GET /users/me/statistics/packs
- GET /users/me/statistics/words (with filters)
- GET /users/me/statistics/timeline
- POST /users/me/sessions
- GET /users/me/achievements
Phase 5: Documentation
Task 5.1: Update OpenAPI Spec
Estimated Time: 1-2 hours
File: mnemo_cards_backend/public/open_api.yaml
Add:
- All new statistics endpoints
- Request/response schemas
- Query parameters
- Examples
Task 5.2: Update Documentation
Estimated Time: 1 hour
Files:
- Update
PROGRESS.md - Update
TODO.md - Create
STATISTICS_API.mdwith API documentation
Summary
Total Estimated Time: 35-47 hours
Priority Order:
- Task 1.1, 1.2, 1.3 - Models and DTOs (6-9 hours)
- Task 2.1 - StatisticsCalculator (4-5 hours)
- Task 2.2, 2.3 - API Endpoints (6-8 hours)
- Task 3.1, 3.2, 3.3 - Auto Tracking (9-12 hours)
- Task 4.1, 4.2 - Testing (5-7 hours)
- Task 5.1, 5.2 - Documentation (2-3 hours)
Dependencies:
- Tasks 1.x must be done first
- Tasks 2.x depend on 1.x
- Tasks 3.x depend on 2.x
- Tasks 4.x can be done in parallel with development
- Tasks 5.x should be done last
Start Date: TBD
Target Completion: TBD