История прослушиваний
Relevant source files
The following files were used as context for generating this wiki page:
- internal/features/history/model/history.go
- internal/features/history/transport/http/get_history.go
- internal/features/history/repository/postgres/history_repository.go
- internal/features/tracks/repository/postgres/track_repository.go
- internal/features/tracks/service/play.go
- migrations/001_init.up.sql
- cmd/app/main.go
The "Listening History" (История прослушиваний) module is a core feature of the Music Subscription Service responsible for tracking and retrieving the logs of tracks played by users. It serves as a persistent record of user activity, allowing users to view their chronological listening history and enabling the system to enforce business rules such as daily play limits for specific subscription tiers.
This feature is integrated across the transport, service, and repository layers. It captures playback events when a user initiates a track play and provides a dedicated API endpoint to fetch the history. The data is stored in a relational PostgreSQL database with optimized indexing for chronological retrieval.
Sources: README.md:121, cmd/app/main.go:132-133, internal/features/history/transport/http/get_history.go:18-21
Архитектура и поток данных
The system follows a standard clean architecture pattern where history data is recorded during track playback and retrieved through a specific history handler.
Процесс записи прослушивания
When a user requests to play a track, the TrackService orchestrates the logic, which includes verifying subscription limits (for FREE users) and eventually calling the repository to save the event. The record is created automatically in the listening_history table with a timestamp.
The diagram shows the logic flow when a track is played, leading to a history entry creation.
Sources: internal/features/tracks/service/play.go:21-82, internal/features/tracks/repository/postgres/track_repository.go:135-142
Процесс получения истории
Retrieval is handled by a dedicated history transport layer that extracts the user's ID from the JWT claims and queries the database for all related entries, joined with track and artist metadata.
This sequence illustrates the retrieval of the listening log for the authenticated user.
Sources: internal/features/history/transport/http/get_history.go:28-51, internal/features/history/repository/postgres/history_repository.go:19-35
Структура данных (Schema)
The history is persisted in the listening_history table. It maintains foreign key relationships with the users and tracks tables.
Database Table: listening_history
| Field | Type | Constraints | Description |
|---|---|---|---|
id | BIGSERIAL | PRIMARY KEY | Unique identifier for the history record |
user_id | BIGINT | REFERENCES users(id) | The user who listened to the track |
track_id | BIGINT | REFERENCES tracks(id) | The track that was played |
listened_at | TIMESTAMP | DEFAULT NOW() | Timestamp of the event |
An index idx_listening_history_user_listened_at is created on (user_id, listened_at DESC) to optimize performance for user-specific history queries sorted by time.
Sources: migrations/001_init.up.sql:85-93, migrations/001_init.up.sql:95-96
Data Models
The application uses the HistoryEntry struct to represent the data returned to the user, which includes flattened metadata from joined tables.
type HistoryEntry struct {
ID int64 `db:"id" json:"id"`
TrackID int64 `db:"track_id" json:"track_id"`
TrackTitle string `db:"track_title" json:"track_title"`
ArtistName string `db:"artist_name" json:"artist_name"`
ListenedAt time.Time `db:"listened_at" json:"listened_at"`
}
Sources: internal/features/history/model/history.go:8-14
API Эндпоинты
The history module provides a single primary endpoint for end-users.
| Method | Endpoint | Description | Auth Required |
|---|---|---|---|
| GET | /api/v1/listening-history | Returns the full listening history for the current user | Yes (Bearer Token) |
Детали запроса
- Security: Requires a valid JWT access token. The
UserIDis extracted from theuser_claimscontext key. - Response: A JSON array of
HistoryEntryobjects sorted bylistened_atin descending order.
Sources: internal/features/history/transport/http/get_history.go:15-27, cmd/app/main.go:183
Реализация репозитория
The HistoryRepository performs a complex SQL query to provide a user-friendly history view. It joins the history table with tracks and artists to provide titles and names instead of just raw IDs.
SELECT lh.id, lh.track_id, t.title AS track_title, art.name AS artist_name, lh.listened_at
FROM listening_history lh
JOIN tracks t ON lh.track_id = t.id
JOIN artists art ON t.artist_id = art.id
WHERE lh.user_id = $1
ORDER BY lh.listened_at DESC
Sources: internal/features/history/repository/postgres/history_repository.go:21-28
Интеграция с лимитами прослушивания
For users with a FREE subscription, the history logic is indirectly tied to the TrackService.Play method. Before a record is saved to listening_history, the system checks a daily limit stored in Redis.
- Redis Key:
user:{id}:daily_play_count:{YYYY-MM-DD} - Constraint: If the count exceeds the
FREE_DAILY_PLAY_LIMIT(default 10), the play is rejected, and no history record is created.
Sources: internal/features/tracks/service/play.go:41-75, internal/core/config/config.go:49
Заключение
Модуль истории прослушиваний обеспечивает прозрачность активности пользователя в системе. Благодаря индексации в базе данных и интеграции с процессом воспроизведения треков, система поддерживает высокую производительность при получении данных и точность при применении бизнес-ограничений для бесплатных учетных записей.