diff --git a/ai_docs/agent/backend/agent_state.json b/ai_docs/agent/backend/agent_state.json index 1eff644..5c4bfb7 100644 --- a/ai_docs/agent/backend/agent_state.json +++ b/ai_docs/agent/backend/agent_state.json @@ -1,7 +1,7 @@ { "component": "backend", - "current_task_id": "BACKEND-007", - "iteration_count": 5, + "current_task_id": "BACKEND-008", + "iteration_count": 6, "max_iterations": 10, "started_at": "2025-11-21T01:06:15.789515+00:00", "last_commit": null, diff --git a/ai_docs/agent/backend/task_list.json b/ai_docs/agent/backend/task_list.json index 093eafa..084fe6b 100644 --- a/ai_docs/agent/backend/task_list.json +++ b/ai_docs/agent/backend/task_list.json @@ -173,7 +173,7 @@ "id": "BACKEND-008", "title": "Update OpenAPI Specification for Statistics Endpoints", "priority": "medium", - "status": "pending", + "status": "in_progress", "estimated_hours": 2.0, "description": "Update public/open_api.yaml to include all statistics endpoints (detailed, packs, words, timeline, sessions, achievements) with proper request/response schemas, query parameters, and examples.", "acceptance_criteria": [ diff --git a/mnemo_cards_backend/public/open_api.yaml b/mnemo_cards_backend/public/open_api.yaml index 899cdc2..51591ff 100644 --- a/mnemo_cards_backend/public/open_api.yaml +++ b/mnemo_cards_backend/public/open_api.yaml @@ -117,61 +117,472 @@ paths: tags: - UsersApiV2 summary: getDetailedStatistics - description: "GET /api/v2/users/me/statistics/detailed\nReturns detailed user statistics including streaks, study time, achievements." + description: "GET /api/v2/users/me/statistics/detailed\nReturns detailed user statistics including streaks, study time, achievements, word statistics, and pack progress." operationId: getDetailedStatistics + security: + - bearerAuth: [] responses: 200: - description: "Operation completed!" + description: Detailed user statistics + content: + application/json: + schema: + $ref: '#/components/schemas/UserDataDto' + example: + allWordsStatistics: + words: + - word: "hello" + correct: 10.0 + incorrect: 2.0 + skipped: 0.0 + questionTypes: ["translation", "pronunciation"] + correct: 150.0 + incorrect: 30.0 + skipped: 5.0 + allTestsStatistics: + tests: [] + totalAttempts: 25 + averageScore: 0.85 + lastTimeOnline: "2024-01-15T10:30:00Z" + totalStudyTimeMinutes: 1200 + currentStreak: 7 + longestStreak: 15 + packProgress: + basic_pack: + packId: "basic_pack" + totalCards: 100 + learnedCards: 45 + studyTimeMinutes: 300 + lastStudyDate: "2024-01-15T09:00:00Z" + firstStudyDate: "2024-01-01T08:00:00Z" + cardAttempts: {} + averageAccuracy: 0.82 + studyDates: + - "2024-01-15T09:00:00Z" + - "2024-01-14T10:00:00Z" + categoryMinutes: + basic: 300 + achievements: + - id: "streak_7" + title: "Week Warrior" + description: "Study for 7 consecutive days" + type: "streak7Days" + unlockedAt: "2024-01-15T09:00:00Z" + progress: 1.0 + 401: + description: Unauthorized - Authentication required + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + example: + error: "unauthorized" + message: "Authentication required" + 404: + description: User data not found + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + example: + error: "user_data_not_found" + 500: + description: Internal server error + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + example: + error: "internal_server_error" + message: "An unexpected error occurred" /users/me/statistics/packs: get: tags: - UsersApiV2 summary: getPacksStatistics - description: "GET /api/v2/users/me/statistics/packs\nReturns statistics for all user packs or specific pack if packId provided.\nQuery parameters: ?packId=" + description: "GET /api/v2/users/me/statistics/packs\nReturns statistics for all user packs or specific pack if packId provided." operationId: getPacksStatistics + security: + - bearerAuth: [] + parameters: + - name: packId + in: query + description: Filter by specific pack ID + required: false + schema: + type: string + example: "basic_pack" responses: 200: - description: "Operation completed!" + description: List of pack progress statistics + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/PackProgressDto' + example: + - packId: "basic_pack" + totalCards: 100 + learnedCards: 45 + studyTimeMinutes: 300 + lastStudyDate: "2024-01-15T09:00:00Z" + firstStudyDate: "2024-01-01T08:00:00Z" + cardAttempts: {} + averageAccuracy: 0.82 + - packId: "advanced_pack" + totalCards: 200 + learnedCards: 120 + studyTimeMinutes: 600 + lastStudyDate: "2024-01-14T15:00:00Z" + firstStudyDate: "2023-12-01T10:00:00Z" + cardAttempts: {} + averageAccuracy: 0.75 + 401: + description: Unauthorized - Authentication required + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + example: + error: "unauthorized" + message: "Authentication required" + 500: + description: Internal server error + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + example: + error: "internal_server_error" + message: "An unexpected error occurred" /users/me/statistics/words: get: tags: - UsersApiV2 summary: getWordsStatistics - description: "GET /api/v2/users/me/statistics/words\nReturns paginated word statistics with optional filtering.\nQuery parameters:\n- packId: filter by specific pack\n- limit: number of results (default 50, max 100)\n- offset: pagination offset (default 0)\n- sortBy: 'difficulty', 'accuracy', 'recent' (default 'difficulty')\n- needsReview: 'true' to show only words needing review" + description: "GET /api/v2/users/me/statistics/words\nReturns paginated word statistics with optional filtering." operationId: getWordsStatistics + security: + - bearerAuth: [] + parameters: + - name: packId + in: query + description: Filter by specific pack ID + required: false + schema: + type: string + example: "basic_pack" + - name: limit + in: query + description: Number of results per page (default 50, max 100) + required: false + schema: + type: integer + minimum: 1 + maximum: 100 + default: 50 + example: 50 + - name: offset + in: query + description: Pagination offset (default 0) + required: false + schema: + type: integer + minimum: 0 + default: 0 + example: 0 + - name: sortBy + in: query + description: Sort order - 'difficulty', 'accuracy', 'recent', or 'alphabetical' (default 'difficulty') + required: false + schema: + type: string + enum: [difficulty, accuracy, recent, alphabetical] + default: difficulty + example: "difficulty" + - name: needsReview + in: query + description: Filter to show only words needing review (set to 'true') + required: false + schema: + type: string + enum: ["true", "false"] + example: "false" responses: 200: - description: "Operation completed!" + description: Paginated word statistics + content: + application/json: + schema: + $ref: '#/components/schemas/WordStatisticsPaginatedResponse' + example: + words: + - word: "hello" + correct: 10.0 + incorrect: 2.0 + skipped: 0.0 + questionTypes: ["translation"] + lastReviewed: "2024-01-15T09:00:00Z" + firstLearned: "2024-01-01T08:00:00Z" + recentAttempts: [] + difficultyScore: 0.17 + needsReview: false + packId: "basic_pack" + - word: "world" + correct: 5.0 + incorrect: 8.0 + skipped: 1.0 + questionTypes: ["translation", "pronunciation"] + lastReviewed: "2024-01-14T10:00:00Z" + firstLearned: "2024-01-01T08:00:00Z" + recentAttempts: [] + difficultyScore: 0.57 + needsReview: true + packId: "basic_pack" + totalCount: 45 + page: 0 + pageSize: 50 + hasMore: false + 400: + description: Bad request - Invalid query parameters + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + example: + error: "bad_request" + message: "Invalid limit parameter. Must be between 1 and 100." + 401: + description: Unauthorized - Authentication required + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + example: + error: "unauthorized" + message: "Authentication required" + 500: + description: Internal server error + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + example: + error: "internal_server_error" + message: "An unexpected error occurred" /users/me/statistics/timeline: get: tags: - UsersApiV2 summary: getTimelineStatistics - description: "GET /api/v2/users/me/statistics/timeline\nReturns timeline statistics for study activity.\nQuery parameters:\n- period: 'day', 'week', 'month', 'year' (default 'month')\n- from: ISO date string for start date\n- to: ISO date string for end date" + description: "GET /api/v2/users/me/statistics/timeline\nReturns timeline statistics for study activity over a specified period." operationId: getTimelineStatistics + security: + - bearerAuth: [] + parameters: + - name: period + in: query + description: Time period - 'day', 'week', 'month', or 'year' (default 'month') + required: false + schema: + type: string + enum: [day, week, month, year] + default: month + example: "month" + - name: from + in: query + description: Start date in ISO 8601 format (overrides period if provided) + required: false + schema: + type: string + format: date-time + example: "2024-01-01T00:00:00Z" + - name: to + in: query + description: End date in ISO 8601 format (defaults to now if not provided) + required: false + schema: + type: string + format: date-time + example: "2024-01-31T23:59:59Z" responses: 200: - description: "Operation completed!" + description: Timeline statistics for the specified period + content: + application/json: + schema: + $ref: '#/components/schemas/TimelineStatisticsResponse' + example: + period: "month" + startDate: "2024-01-01T00:00:00Z" + endDate: "2024-01-31T23:59:59Z" + totalDays: 31 + activeDays: 20 + totalMinutes: 1200 + averageDailyMinutes: 60.0 + currentStreak: 7 + dailyActivity: + "2024-01-15T00:00:00Z": 60 + "2024-01-14T00:00:00Z": 45 + "2024-01-13T00:00:00Z": 30 + studyDates: + - "2024-01-15T09:00:00Z" + - "2024-01-14T10:00:00Z" + - "2024-01-13T08:00:00Z" + 400: + description: Bad request - Invalid date format + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + example: + error: "bad_request" + message: "Invalid date format. Use ISO 8601 format (YYYY-MM-DDTHH:mm:ssZ)." + 401: + description: Unauthorized - Authentication required + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + example: + error: "unauthorized" + message: "Authentication required" + 500: + description: Internal server error + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + example: + error: "internal_server_error" + message: "An unexpected error occurred" /users/me/sessions: post: tags: - UsersApiV2 summary: recordStudySession - description: POST /api/v2/users/me/sessions\nRecords a study session for the user. + description: "POST /api/v2/users/me/sessions\nRecords a study session for the user. Used to track study activity and update statistics." operationId: recordStudySession + security: + - bearerAuth: [] + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/StudySessionDto' + example: + sessionId: "session_1234567890" + startTime: "2024-01-15T09:00:00Z" + endTime: "2024-01-15T09:30:00Z" + wordsLearned: 10 + testsCompleted: 2 + accuracy: 0.85 + packId: "basic_pack" + testId: null responses: 200: - description: "Operation completed!" + description: Session recorded successfully + content: + application/json: + schema: + type: object + properties: + result: + type: boolean + example: true + sessionId: + type: string + example: "session_1234567890" + example: + result: true + sessionId: "session_1234567890" + 400: + description: Bad request - Invalid session data + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + example: + error: "bad_request" + message: "Invalid session data: startTime is required" + 401: + description: Unauthorized - Authentication required + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + example: + error: "unauthorized" + message: "Authentication required" + 500: + description: Internal server error + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + example: + error: "internal_server_error" + message: "An unexpected error occurred" /users/me/achievements: get: tags: - UsersApiV2 summary: getAchievements - description: GET /api/v2/users/me/achievements\nReturns user's achievements and progress. + description: "GET /api/v2/users/me/achievements\nReturns user's achievements and progress. Includes both unlocked and locked achievements with progress indicators." operationId: getAchievements + security: + - bearerAuth: [] responses: 200: - description: "Operation completed!" + description: List of user achievements + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/AchievementDto' + example: + - id: "streak_7" + title: "Week Warrior" + description: "Study for 7 consecutive days" + iconUrl: null + unlockedAt: "2024-01-15T09:00:00Z" + type: "streak7Days" + progress: 1.0 + - id: "words_10" + title: "Word Explorer" + description: "Learn 10 words" + iconUrl: null + unlockedAt: "2024-01-10T08:00:00Z" + type: "words10Learned" + progress: 1.0 + - id: "streak_30" + title: "Monthly Master" + description: "Study for 30 consecutive days" + iconUrl: null + unlockedAt: null + type: "streak30Days" + progress: 0.23 + 401: + description: Unauthorized - Authentication required + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + example: + error: "unauthorized" + message: "Authentication required" + 500: + description: Internal server error + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + example: + error: "internal_server_error" + message: "An unexpected error occurred" /admin/users: get: tags: @@ -760,7 +1171,447 @@ paths: responses: 200: description: "Operation completed!" -components: { } +components: + securitySchemes: + bearerAuth: + type: http + scheme: bearer + bearerFormat: JWT + description: JWT Bearer token authentication + schemas: + ErrorResponse: + type: object + properties: + error: + type: string + description: Error code identifier + example: "bad_request" + message: + type: string + description: Human-readable error message + example: "Invalid request parameters" + required: + - error + UserDataDto: + type: object + description: Comprehensive user statistics and data + properties: + allWordsStatistics: + $ref: '#/components/schemas/AllWordsStatisticsDto' + allTestsStatistics: + $ref: '#/components/schemas/AllTestsStatisticsDto' + lastTimeOnline: + type: string + format: date-time + nullable: true + description: When user was last online + totalStudyTimeMinutes: + type: integer + description: Total study time in minutes + example: 1200 + currentStreak: + type: integer + description: Current consecutive days streak + example: 7 + longestStreak: + type: integer + description: Longest streak ever achieved + example: 15 + packProgress: + type: object + additionalProperties: + $ref: '#/components/schemas/PackProgressDto' + description: Map of pack ID to pack progress statistics + studyDates: + type: array + items: + type: string + format: date-time + description: List of dates when user studied + categoryMinutes: + type: object + additionalProperties: + type: integer + description: Study time by category/language in minutes + achievements: + type: array + items: + $ref: '#/components/schemas/AchievementDto' + description: User's achievements + AllWordsStatisticsDto: + type: object + description: Aggregated word statistics + properties: + words: + type: array + items: + $ref: '#/components/schemas/WordStatisticsDto' + correct: + type: number + format: double + description: Total correct answers + incorrect: + type: number + format: double + description: Total incorrect answers + skipped: + type: number + format: double + description: Total skipped answers + WordStatisticsDto: + type: object + description: Basic word statistics + properties: + word: + type: string + description: The word being tracked + example: "hello" + correct: + type: number + format: double + description: Number of correct answers + example: 10.0 + incorrect: + type: number + format: double + description: Number of incorrect answers + example: 2.0 + skipped: + type: number + format: double + description: Number of skipped answers + example: 0.0 + questionTypes: + type: array + items: + type: string + description: Types of questions attempted + example: ["translation", "pronunciation"] + AllTestsStatisticsDto: + type: object + description: Aggregated test statistics + properties: + tests: + type: array + items: + type: object + totalAttempts: + type: integer + description: Total number of test attempts + averageScore: + type: number + format: double + description: Average test score (0.0 to 1.0) + PackProgressDto: + type: object + description: Statistics about user's progress on a specific pack + properties: + packId: + type: string + description: Pack identifier + example: "basic_pack" + totalCards: + type: integer + description: Total number of cards in the pack + example: 100 + learnedCards: + type: integer + description: Number of cards learned by the user + example: 45 + studyTimeMinutes: + type: integer + description: Total study time spent on this pack in minutes + example: 300 + lastStudyDate: + type: string + format: date-time + nullable: true + description: Date when user last studied this pack + example: "2024-01-15T09:00:00Z" + firstStudyDate: + type: string + format: date-time + nullable: true + description: Date when user first started studying this pack + example: "2024-01-01T08:00:00Z" + cardAttempts: + type: object + additionalProperties: + type: integer + description: Map of card ID to number of attempts + example: {} + averageAccuracy: + type: number + format: double + description: Average accuracy across all attempts (0.0 to 1.0) + example: 0.82 + required: + - packId + - totalCards + DetailedWordStatisticsDto: + allOf: + - $ref: '#/components/schemas/WordStatisticsDto' + - type: object + properties: + lastReviewed: + type: string + format: date-time + nullable: true + description: When this word was last reviewed + firstLearned: + type: string + format: date-time + nullable: true + description: When this word was first learned + recentAttempts: + type: array + items: + $ref: '#/components/schemas/WordAttemptDto' + description: Recent attempts (last 10) + difficultyScore: + type: number + format: double + description: Difficulty score (0.0 = easy, 1.0 = hard) + example: 0.57 + needsReview: + type: boolean + description: Whether this word needs review + example: true + packId: + type: string + nullable: true + description: Which pack this word belongs to + example: "basic_pack" + WordAttemptDto: + type: object + description: Individual word attempt data + properties: + timestamp: + type: string + format: date-time + description: When the attempt happened + wasCorrect: + type: boolean + description: Whether the answer was correct + questionType: + type: string + description: Type of question asked + example: "translation" + wasSkipped: + type: boolean + description: Whether the question was skipped + default: false + required: + - timestamp + - wasCorrect + - questionType + WordStatisticsPaginatedResponse: + type: object + description: Paginated response for word statistics + properties: + words: + type: array + items: + $ref: '#/components/schemas/DetailedWordStatisticsDto' + description: List of word statistics + totalCount: + type: integer + description: Total number of words matching the filter + example: 45 + page: + type: integer + description: Current page number (0-based) + example: 0 + pageSize: + type: integer + description: Number of results per page + example: 50 + hasMore: + type: boolean + description: Whether there are more results available + example: false + required: + - words + - totalCount + - page + - pageSize + - hasMore + TimelineStatisticsResponse: + type: object + description: Timeline statistics for study activity + properties: + period: + type: string + description: Time period used + enum: [day, week, month, year] + example: "month" + startDate: + type: string + format: date-time + description: Start date of the period + example: "2024-01-01T00:00:00Z" + endDate: + type: string + format: date-time + description: End date of the period + example: "2024-01-31T23:59:59Z" + totalDays: + type: integer + description: Total days in the period + example: 31 + activeDays: + type: integer + description: Number of days with study activity + example: 20 + totalMinutes: + type: integer + description: Total study time in minutes + example: 1200 + averageDailyMinutes: + type: number + format: double + description: Average study time per active day in minutes + example: 60.0 + currentStreak: + type: integer + description: Current streak within the period + example: 7 + dailyActivity: + type: object + additionalProperties: + type: integer + description: Map of date (ISO string) to study minutes for that day + example: + "2024-01-15T00:00:00Z": 60 + "2024-01-14T00:00:00Z": 45 + studyDates: + type: array + items: + type: string + format: date-time + description: List of dates when user studied + example: + - "2024-01-15T09:00:00Z" + - "2024-01-14T10:00:00Z" + required: + - period + - startDate + - endDate + - totalDays + - activeDays + - totalMinutes + - averageDailyMinutes + - currentStreak + - dailyActivity + - studyDates + StudySessionDto: + type: object + description: Study session data for tracking learning activity + properties: + sessionId: + type: string + nullable: true + description: Unique session identifier + example: "session_1234567890" + startTime: + type: string + format: date-time + description: When the session started + example: "2024-01-15T09:00:00Z" + endTime: + type: string + format: date-time + nullable: true + description: When the session ended (null if still active) + example: "2024-01-15T09:30:00Z" + wordsLearned: + type: integer + description: Number of words learned during this session + default: 0 + example: 10 + testsCompleted: + type: integer + description: Number of tests completed during this session + default: 0 + example: 2 + accuracy: + type: number + format: double + description: Overall accuracy during this session (0.0 to 1.0) + default: 0.0 + example: 0.85 + packId: + type: string + nullable: true + description: Pack being studied (if focused on specific pack) + example: "basic_pack" + testId: + type: string + nullable: true + description: Test being taken (if part of a test) + required: + - startTime + AchievementDto: + type: object + description: Achievement data structure + properties: + id: + type: string + description: Unique achievement identifier + example: "streak_7" + title: + type: string + description: Achievement title + example: "Week Warrior" + description: + type: string + description: Achievement description + example: "Study for 7 consecutive days" + iconUrl: + type: string + nullable: true + description: URL to achievement icon/badge image + unlockedAt: + type: string + format: date-time + nullable: true + description: When this achievement was unlocked (null if locked) + example: "2024-01-15T09:00:00Z" + type: + type: string + description: Achievement type for categorization + enum: + - firstWordLearned + - firstTestCompleted + - firstPackCompleted + - streak3Days + - streak7Days + - streak30Days + - streak100Days + - words10Learned + - words50Learned + - words100Learned + - words500Learned + - words1000Learned + - perfectTestScore + - speedLearner + - dedicatedLearner + - nightOwl + - earlyBird + - consistentLearner + - languageMaster + example: "streak7Days" + progress: + type: number + format: double + description: Progress towards unlocking (0.0 to 1.0 for locked achievements) + default: 0.0 + example: 1.0 + required: + - id + - title + - description + - type tags: - name: PurchasesApiV2 description: Purchases API v2\n\nRESTful endpoints for managing purchases and payments