package repository import ( "context" "time" "github.com/google/uuid" ) // ReportTypeCount aggregates growth_reports by type. type ReportTypeCount struct { Type string `json:"type"` Count int `json:"count"` } // BehaviorEventBrief is a recent analytics event for ops insight. type BehaviorEventBrief struct { Name string `json:"name"` PagePath string `json:"page_path,omitempty"` ReceivedAt time.Time `json:"received_at"` } // CountReportsByType groups non-deleted reports for a user. func (r *AdminRepo) CountReportsByType(ctx context.Context, userID uuid.UUID) ([]ReportTypeCount, error) { rows, err := r.Pool.Query(ctx, ` SELECT type, count(*)::int FROM growth_reports WHERE user_id=$1 AND deleted_at IS NULL GROUP BY type ORDER BY count(*) DESC, type ASC`, userID) if err != nil { return nil, err } defer rows.Close() var out []ReportTypeCount for rows.Next() { var c ReportTypeCount if err := rows.Scan(&c.Type, &c.Count); err != nil { return nil, err } out = append(out, c) } return out, rows.Err() } // CountProfilesForUser returns active profile count. func (r *AdminRepo) CountProfilesForUser(ctx context.Context, userID uuid.UUID) (int, error) { var n int err := r.Pool.QueryRow(ctx, ` SELECT count(*)::int FROM profiles WHERE user_id=$1 AND deleted_at IS NULL`, userID).Scan(&n) return n, err } // CountAskThreadsForUser returns non-deleted ask threads. func (r *AdminRepo) CountAskThreadsForUser(ctx context.Context, userID uuid.UUID) (int, error) { var n int err := r.Pool.QueryRow(ctx, ` SELECT count(*)::int FROM ask_threads WHERE user_id=$1 AND deleted_at IS NULL`, userID).Scan(&n) return n, err } // ListRecentEventsForUser returns recent analytics events (may be empty). func (r *AdminRepo) ListRecentEventsForUser(ctx context.Context, userID uuid.UUID, limit int) ([]BehaviorEventBrief, error) { if limit <= 0 || limit > 50 { limit = 20 } rows, err := r.Pool.Query(ctx, ` SELECT name, coalesce(page_path, ''), received_at FROM analytics_events WHERE user_id=$1 ORDER BY received_at DESC LIMIT $2`, userID, limit) if err != nil { return nil, err } defer rows.Close() var out []BehaviorEventBrief for rows.Next() { var e BehaviorEventBrief if err := rows.Scan(&e.Name, &e.PagePath, &e.ReceivedAt); err != nil { return nil, err } out = append(out, e) } return out, rows.Err() }