Yimaru-BackEnd/internal/web_server/handlers/analytics_params.go
Yared Yemane 3f73afb4bf Add video engagement tracking and analytics metrics.
Record playback heartbeats via POST /api/v1/videos/engagement/heartbeat and expose completion, replay, and drop-off rates on the analytics dashboard.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-24 02:59:46 -07:00

130 lines
6.2 KiB
Go

package handlers
import (
dbgen "Yimaru-Backend/gen/db"
"Yimaru-Backend/internal/domain"
"time"
"github.com/jackc/pgx/v5/pgtype"
)
type analyticsQueryParams struct {
UsersSummary dbgen.AnalyticsUsersSummaryParams
UsersByRole dbgen.AnalyticsUsersByRoleParams
UsersByStatus dbgen.AnalyticsUsersByStatusParams
UsersByAgeGroup dbgen.AnalyticsUsersByAgeGroupParams
UsersByEducationLevel dbgen.AnalyticsUsersByEducationLevelParams
UsersByOccupation dbgen.AnalyticsUsersByOccupationParams
UsersByLearningGoal dbgen.AnalyticsUsersByLearningGoalParams
UsersByLanguageChallange dbgen.AnalyticsUsersByLanguageChallangeParams
UsersByKnowledgeLevel dbgen.AnalyticsUsersByKnowledgeLevelParams
UsersByCountry dbgen.AnalyticsUsersByCountryParams
UsersByRegion dbgen.AnalyticsUsersByRegionParams
UserRegistrationsSeries dbgen.AnalyticsUserRegistrationsLast30DaysParams
SubscriptionsSummary dbgen.AnalyticsSubscriptionsSummaryParams
SubscriptionsByStatus dbgen.AnalyticsSubscriptionsByStatusParams
RevenueByPlan dbgen.AnalyticsRevenueByPlanParams
NewSubscriptionsSeries dbgen.AnalyticsNewSubscriptionsLast30DaysParams
PaymentsSummary dbgen.AnalyticsPaymentsSummaryParams
PaymentsByStatus dbgen.AnalyticsPaymentsByStatusParams
PaymentsByMethod dbgen.AnalyticsPaymentsByMethodParams
RevenueSeries dbgen.AnalyticsRevenueLast30DaysParams
QuestionsCounts dbgen.AnalyticsQuestionsCountsParams
QuestionsByType dbgen.AnalyticsQuestionsByTypeParams
QuestionSetsByType dbgen.AnalyticsQuestionSetsByTypeParams
NotificationsSummary dbgen.AnalyticsNotificationsSummaryParams
NotificationsChannel dbgen.AnalyticsNotificationsByChannelParams
NotificationsType dbgen.AnalyticsNotificationsByTypeParams
IssuesSummary dbgen.AnalyticsIssuesSummaryParams
IssuesByStatus dbgen.AnalyticsIssuesByStatusParams
IssuesByType dbgen.AnalyticsIssuesByTypeParams
TeamSummary dbgen.AnalyticsTeamSummaryParams
TeamByRole dbgen.AnalyticsTeamByRoleParams
TeamByStatus dbgen.AnalyticsTeamByStatusParams
VideoEngagementSummary dbgen.AnalyticsVideoEngagementSummaryParams
VideoDropOffByCheckpoint dbgen.AnalyticsVideoDropOffByCheckpointParams
}
func newAnalyticsQueryParams(f domain.AnalyticsDateFilter) analyticsQueryParams {
ref := pgAnalyticsDate(f.RefDate)
rs, re := pgAnalyticsTimestamptzPtr(f.RangeStart), pgAnalyticsTimestamptzPtr(f.RangeEnd)
series := dbgen.AnalyticsUserRegistrationsLast30DaysParams{
SeriesStart: pgAnalyticsDate(f.SeriesStart),
SeriesEnd: pgAnalyticsDate(f.SeriesEnd),
RangeStart: rs,
RangeEnd: re,
}
return analyticsQueryParams{
UsersSummary: dbgen.AnalyticsUsersSummaryParams{RefDate: ref, RangeStart: rs, RangeEnd: re},
UsersByRole: dbgen.AnalyticsUsersByRoleParams{RangeStart: rs, RangeEnd: re},
UsersByStatus: dbgen.AnalyticsUsersByStatusParams{RangeStart: rs, RangeEnd: re},
UsersByAgeGroup: dbgen.AnalyticsUsersByAgeGroupParams{RangeStart: rs, RangeEnd: re},
UsersByEducationLevel: dbgen.AnalyticsUsersByEducationLevelParams{RangeStart: rs, RangeEnd: re},
UsersByOccupation: dbgen.AnalyticsUsersByOccupationParams{RangeStart: rs, RangeEnd: re},
UsersByLearningGoal: dbgen.AnalyticsUsersByLearningGoalParams{RangeStart: rs, RangeEnd: re},
UsersByLanguageChallange: dbgen.AnalyticsUsersByLanguageChallangeParams{RangeStart: rs, RangeEnd: re},
UsersByKnowledgeLevel: dbgen.AnalyticsUsersByKnowledgeLevelParams{RangeStart: rs, RangeEnd: re},
UsersByCountry: dbgen.AnalyticsUsersByCountryParams{RangeStart: rs, RangeEnd: re},
UsersByRegion: dbgen.AnalyticsUsersByRegionParams{RangeStart: rs, RangeEnd: re},
UserRegistrationsSeries: series,
SubscriptionsSummary: dbgen.AnalyticsSubscriptionsSummaryParams{RefDate: ref, RangeStart: rs, RangeEnd: re},
SubscriptionsByStatus: dbgen.AnalyticsSubscriptionsByStatusParams{RangeStart: rs, RangeEnd: re},
RevenueByPlan: dbgen.AnalyticsRevenueByPlanParams{RangeStart: rs, RangeEnd: re},
NewSubscriptionsSeries: dbgen.AnalyticsNewSubscriptionsLast30DaysParams{
SeriesStart: series.SeriesStart,
SeriesEnd: series.SeriesEnd,
RangeStart: rs,
RangeEnd: re,
},
PaymentsSummary: dbgen.AnalyticsPaymentsSummaryParams{RangeStart: rs, RangeEnd: re},
PaymentsByStatus: dbgen.AnalyticsPaymentsByStatusParams{RangeStart: rs, RangeEnd: re},
PaymentsByMethod: dbgen.AnalyticsPaymentsByMethodParams{RangeStart: rs, RangeEnd: re},
RevenueSeries: dbgen.AnalyticsRevenueLast30DaysParams{
SeriesStart: series.SeriesStart,
SeriesEnd: series.SeriesEnd,
RangeStart: rs,
RangeEnd: re,
},
QuestionsCounts: dbgen.AnalyticsQuestionsCountsParams{RangeStart: rs, RangeEnd: re},
QuestionsByType: dbgen.AnalyticsQuestionsByTypeParams{RangeStart: rs, RangeEnd: re},
QuestionSetsByType: dbgen.AnalyticsQuestionSetsByTypeParams{RangeStart: rs, RangeEnd: re},
NotificationsSummary: dbgen.AnalyticsNotificationsSummaryParams{RangeStart: rs, RangeEnd: re},
NotificationsChannel: dbgen.AnalyticsNotificationsByChannelParams{RangeStart: rs, RangeEnd: re},
NotificationsType: dbgen.AnalyticsNotificationsByTypeParams{RangeStart: rs, RangeEnd: re},
IssuesSummary: dbgen.AnalyticsIssuesSummaryParams{RangeStart: rs, RangeEnd: re},
IssuesByStatus: dbgen.AnalyticsIssuesByStatusParams{RangeStart: rs, RangeEnd: re},
IssuesByType: dbgen.AnalyticsIssuesByTypeParams{RangeStart: rs, RangeEnd: re},
TeamSummary: dbgen.AnalyticsTeamSummaryParams{RangeStart: rs, RangeEnd: re},
TeamByRole: dbgen.AnalyticsTeamByRoleParams{RangeStart: rs, RangeEnd: re},
TeamByStatus: dbgen.AnalyticsTeamByStatusParams{RangeStart: rs, RangeEnd: re},
VideoEngagementSummary: dbgen.AnalyticsVideoEngagementSummaryParams{RangeStart: rs, RangeEnd: re},
VideoDropOffByCheckpoint: dbgen.AnalyticsVideoDropOffByCheckpointParams{RangeStart: rs, RangeEnd: re},
}
}
func pgAnalyticsDate(t time.Time) pgtype.Date {
return pgtype.Date{Time: t.UTC(), Valid: true}
}
func pgAnalyticsTimestamptzPtr(t *time.Time) pgtype.Timestamptz {
if t == nil {
return pgtype.Timestamptz{Valid: false}
}
return pgtype.Timestamptz{Time: t.UTC(), Valid: true}
}