feat(backend): Update OpenAPI Specification for Statistics Endpoints

Task ID: BACKEND-008
Priority: medium

Changes:

Completed by: AI Agent
Duration: 83447ms
This commit is contained in:
AI Agent 2025-11-21 05:33:21 +00:00
parent 4a468bd0c3
commit 88a69bb605
3 changed files with 867 additions and 16 deletions

View file

@ -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,

View file

@ -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": [

View file

@ -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=<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