# 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:** 1. `mnemo_cards_common/lib/src/dtos/user/data/pack_progress_dto.dart` ```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 cardAttempts; final double averageAccuracy; } ``` 2. `mnemo_cards_common/lib/src/dtos/user/achievement_dto.dart` ```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, } ``` 3. `mnemo_cards_common/lib/src/dtos/user/data/detailed_word_statistics_dto.dart` ```dart @JsonSerializable() @CopyWith() class DetailedWordStatisticsDto { final String word; final double correct; final double incorrect; final double skipped; final Set questionTypes; final DateTime? lastReviewed; final DateTime? firstLearned; final double difficultyScore; // 0.0 to 1.0 final bool needsReview; final String? packId; } ``` 4. `mnemo_cards_common/lib/src/dtos/user/study_session_dto.dart` ```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.sh` to 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:** ```dart @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 packProgress; final List studyDates; // for streak calculation final Map categoryMinutes; // category -> minutes final List 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:** 1. `mnemo_cards_common_backend/lib/src/models/pack_progress_model.dart` 2. `mnemo_cards_common_backend/lib/src/models/achievement_model.dart` 3. `mnemo_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:** ```dart @lazySingleton class StatisticsCalculator { /// Calculate pack progress for user Future calculatePackProgress( UserModel user, String packId, ); /// Calculate current streak int calculateStreak(List studyDates); /// Find difficult words that need review List findDifficultWords( UserDataModel data, {int limit = 20} ); /// Calculate overall accuracy double calculateAccuracy(AllWordsStatisticsDto stats); /// Calculate daily study time Map calculateDailyStudyTime( List sessions, ); /// Calculate total study time int calculateTotalStudyTime(UserDataModel data); /// Get timeline statistics Map 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:** ```dart /// GET /api/v2/users/me/statistics/detailed /// Returns detailed user statistics @Route.get('/users/me/statistics/detailed') Future 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 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 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 getTimelineStatistics(Request request); /// POST /api/v2/users/me/sessions /// Start or end study session @Route.post('/users/me/sessions') Future recordStudySession(Request request); /// GET /api/v2/users/me/achievements /// Returns user achievements @Route.get('/users/me/achievements') Future 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:** ```dart class UserManager { final StatisticsCalculator _statsCalculator; // Existing methods... /// Get detailed user statistics Future getDetailedStatistics(UserModel user); /// Get pack statistics Future> getPacksStatistics( UserModel user, {String? packId} ); /// Get word statistics with pagination Future> getWordsStatistics( UserModel user, { String? packId, int limit = 50, int offset = 0, String sortBy = 'difficulty', bool needsReview = false, }); /// Record study session Future recordStudySession( UserModel user, StudySessionDto session, ); /// Update user streak Future 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:** ```dart @lazySingleton class AchievementManager { /// Check and award achievements after action Future> checkAchievements(UserModel user); /// Check specific achievement Future checkAchievement( UserModel user, AchievementType type, ); /// Award achievement Future awardAchievement( UserModel user, AchievementDto achievement, ); /// Get all possible achievements List 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.dart` - `test/statistics/achievement_manager_test.dart` - `test/statistics/session_tracker_test.dart` - `test/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.md` with API documentation --- ## Summary **Total Estimated Time:** 35-47 hours **Priority Order:** 1. Task 1.1, 1.2, 1.3 - Models and DTOs (6-9 hours) 2. Task 2.1 - StatisticsCalculator (4-5 hours) 3. Task 2.2, 2.3 - API Endpoints (6-8 hours) 4. Task 3.1, 3.2, 3.3 - Auto Tracking (9-12 hours) 5. Task 4.1, 4.2 - Testing (5-7 hours) 6. 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