Platform-Wide and Course-Specific Analytics and Reporting - Technical Documentation
Generated on 9/18/2025 | AI Workflow Portal
π Executive Summary
The Xikolo 31_ADMIN_Analytics cluster provides a centralized and comprehensive system for analytics and reporting across the learning platform. Its core purpose is to offer administrators and stakeholders deep insights into platform-wide usage, granular course performance, and user activity through a suite of administrative controllers and specialized models. This cluster enables the generation, management, and display of diverse statistical data and custom reports, consolidating information from various microservices and internal data models to ensure data-driven decision-making and operational oversight. Key components include AJAX controllers for dynamic data retrieval, dedicated models for statistical calculations, and a robust reporting interface.
ποΈ Architecture Overview
The architecture for the 31_ADMIN_Analytics cluster is designed to aggregate and present analytics from various microservices and internal models. It primarily relies on specialized administrative controllers acting as an intermediary layer between the user interface and distributed data sources. Caching mechanisms are extensively utilized to enhance performance and reduce load on backend services. The reporting subsystem provides flexible job management and data presentation through dedicated presenters.
Key Components:
- Admin Dashboard (UI): The primary user interface for administrators to view statistics and manage reports, initiating data requests to the backend controllers.
- Admin::Ajax::PlatformStatisticsController: This controller is responsible for gathering and consolidating high-level platform statistics, such as user counts, total enrollments, and overall activity, from various APIs.
- Admin::Ajax::DetailStatisticsController: Focuses on providing in-depth, course-specific metrics, including geographical data, top content types, and video engagement. It leverages external APIs and a GeoIP lookup service.
- Admin::ReportsController: Serves as the central component for managing custom reports, facilitating their creation, listing, restarting, and deletion. It interacts heavily with the
lanalytics_api. - Lanalytics Microservice API: A critical backend service that stores and processes analytics data, providing aggregated metrics and managing report generation jobs.
- External Data Services (Course, Account, Pinboard APIs): Represents various microservices (
course_api,account_api,pinboard_api) that are queried by the administrative controllers to enrich analytics data with user, course, and specific feature (e.g., pinboard) details.
Architecture Diagrams
Main Architecture Overview
graph TD adminUI["Admin Dashboard (UI)"] platformStatsCtrl["Admin::Ajax::PlatformStatisticsController"] detailStatsCtrl["Admin::Ajax::DetailStatisticsController"] reportsCtrl["Admin::ReportsController"] lanalyticsAPI["Lanalytics Microservice API"] externalServices["Course/Account/Pinboard APIs"] adminUI -->|"requests platform stats"| platformStatsCtrl adminUI -->|"requests course stats"| detailStatsCtrl adminUI -->|"manages reports"| reportsCtrl platformStatsCtrl -->|"fetches global metrics"| lanalyticsAPI detailStatsCtrl -->|"fetches detailed metrics"| lanalyticsAPI reportsCtrl -->|"manages report jobs"| lanalyticsAPI platformStatsCtrl -->|"queries users/courses"| externalServices detailStatsCtrl -->|"queries courses/pinboard"| externalServices reportsCtrl -->|"fetches course options"| externalServices
π Component Interactions
Key interactions between components in this cluster:
- Admin::Ajax::ClassifiersController: Interacts with
Course::Classifiermodel to retrieve classifier data. - Admin::Ajax::CoursesController: Communicates with
course_apiservice to fetch course details. - Admin::Ajax::DetailStatisticsController: Fetches βtop_countriesβ, βtop_citiesβ, βtop_itemsβ, βvideo_statisticsβ metrics from
learnanalytics_apiviafetch_metrichelper. [Source: app/controllers/admin/ajax/detail_statistics_controller.rb] - Admin::Ajax::DetailStatisticsController: Fetches course items from
course_api. [Source: app/controllers/admin/ajax/detail_statistics_controller.rb] - Admin::Ajax::PlatformStatisticsController: Fetches account statistics from
account_api. [Source: app/controllers/admin/ajax/platform_statistics_controller.rb] - Admin::Ajax::PlatformStatisticsController: Fetches course statistics (global enrollments, course count) from
course_api. [Source: app/controllers/admin/ajax/platform_statistics_controller.rb] - Admin::Ajax::StreamsController: Interacts with
Video::Streammodel to retrieve stream data. - Admin::Ajax::UsersController: Communicates with
account_apiservice to fetch user details. - Admin::ReportsController: Fetches report jobs and report types from
learnanalytics_api. [Source: app/controllers/admin/reports_controller.rb] - Admin::ReportsController: Creates, restarts, and deletes report jobs via
learnanalytics_api. [Source: app/controllers/admin/reports_controller.rb] - Admin::StatisticsController: Initializes
IconNavigationPresenterfor dashboard navigation. [Source: app/controllers/admin/statistics_controller.rb] - LanalyticsHelper: Accesses
current_userto determine user ID. - LanalyticsHelper: Reads
ENV['RELEASE_NUMBER']for build version. - Course::EnrollmentsStatistics: Queries
Course::Enrollmentrecords directly from the database. [Source: app/models/course/enrollments_statistics.rb] - Course::EnrollmentsStatistics: Considers
course.enrollment_deltafor adjusted counts. [Source: app/models/course/enrollments_statistics.rb] - Course::Statistics: Uses
Course::EnrollmentsStatisticsto get enrollment data. [Source: app/models/course/statistics.rb] - Course::Statistics: Queries
Course::Visitrecords to determine user shows. [Source: app/models/course/statistics.rb] - Admin::ReportJobPresenter: Receives raw job data and
current_userobject. [Source: app/presenters/admin/report_job_presenter.rb] - Admin::ReportJobPresenter: Determines if a job is downloadable, error-prone, or restartable based on its status. [Source: app/presenters/admin/report_job_presenter.rb]
- Admin::ReportPresenter: Receives report type definition, list of courses, list of classifiers, and prefill data. [Source: app/presenters/admin/report_presenter.rb]
- Admin::ReportPresenter: Maps
coursesandclassifiersdata to select input options. [Source: app/presenters/admin/report_presenter.rb] - Admin::StatisticsPresenter: Queries
Course::Classifierto find relevant courses. [Source: app/presenters/admin/statistics_presenter.rb] - Admin::StatisticsPresenter: Wraps
Course::Courseobjects with an innerCourseclass for formatted display. [Source: app/presenters/admin/statistics_presenter.rb] - GeoIP::Lookup: Reads from the
vendor/GeoLite2-Country/GeoLite2-Country.mmdbdatabase. - Course::Admin::StatisticsController: Uses
CourseContextHelperto establish course context. [Source: app/controllers/course/admin/statistics_controller.rb] - Course::Admin::StatisticsController: Uses
Acfs.run(likely a frontend data fetching mechanism) for each statistics view. [Source: app/controllers/course/admin/statistics_controller.rb] - Poll::Stats: Directly queries the database (
poll_responsestable) using raw SQL to count responses. [Source: app/models/poll/stats.rb] - Voucher::Stats: Queries
Voucher::VoucherandCourse::Coursemodels directly from the database. [Source: app/models/voucher/stats.rb] - report-jobs.js: Polls the
/reportsendpoint every 10 seconds to update the report jobs table. [Source: app/assets/admin/reports/report-jobs.js] - report-jobs.js: Fetches HTML content from
/reportsand injects it into the[data-id="report-jobs"]element. [Source: app/assets/admin/reports/report-jobs.js] - lanalytics.report.admin Role: Includes
lanalytics.report.createpermission. [Source: RAG: services/account/lib/tasks/permissions/lanalytics.yml] - lanalytics.report.admin Role: Includes
lanalytics.report.deletepermission. [Source: RAG: services/account/lib/tasks/permissions/lanalytics.yml]
βοΈ Technical Workflows
1. Platform-Wide Statistics Retrieval
graph TD adminClient["Admin UI Request"] platformCtrl["PlatformStatisticsController"] cache["Rails Cache"] accountCourseAPI["Account/Course APIs"] lanalyticsAPI["Lanalytics API"] dataResponse["Aggregated Data Response"] adminClient -->|"initiates request"| platformCtrl platformCtrl -->|"check/store data"| cache platformCtrl -->|"fetches user/course data"| accountCourseAPI platformCtrl -->|"fetches activity/certs"| lanalyticsAPI accountCourseAPI -->|"returns data"| platformCtrl lanalyticsAPI -->|"returns metrics"| platformCtrl platformCtrl -->|"aggregates and process"| dataResponse dataResponse -->|"display to user"| adminClient
This workflow describes how platform-level statistics are retrieved and presented to an administrator. The process emphasizes concurrent data fetching and aggressive caching to ensure responsiveness.
An administrator initiates a request for platform statistics from the Admin UI. The Admin::Ajax::PlatformStatisticsController intercepts this request and first attempts to retrieve the data from Rails.cache. If the data is not cached or has expired, the controller performs concurrent API calls using Restify::Promise to account_api for user statistics (e.g., confirmed users, daily registrations) and course_api for global course statistics (e.g., total enrollments, course counts). Simultaneously, it fetches active user counts and certificate statistics from the learnanalytics_api via a fetch_metric helper. Once all data is gathered, it applies any configured global deltas (e.g., Xikolo.config.global_users_delta), aggregates the results, stores them in Rails.cache for future requests (with expiration times ranging from 30 minutes to 1 hour), and renders the aggregated data for display in the Admin UI.
2. Custom Report Generation and Management
graph TD adminUser["Admin User"] reportsPage["Reports UI Page"] reportsJS["report-jobs.js"] reportsCtrl["Admin::ReportsController"] lanalyticsAPI["Lanalytics API"] presenters["Report Presenters"] adminUser -->|"accesses"| reportsPage reportsPage -->|"loads script"| reportsJS reportsJS -->|"polls /reports endpoint"| reportsCtrl reportsCtrl -->|"fetches jobs/types"| lanalyticsAPI lanalyticsAPI -->|"returns data"| reportsCtrl reportsCtrl -->|"uses for formatting"| presenters presenters -->|"formats for display"| reportsPage reportsPage -->|"updates view"| reportsJS
This workflow outlines the process an administrator follows to create, manage, and view custom reports within the system.
The administrator navigates to the reports management page, which is managed by the Admin::ReportsController. Upon loading, the report-jobs.js frontend script initiates polling of the /reports endpoint every 10 seconds to keep the report jobs table updated asynchronously. The Admin::ReportsController fetches available report types and existing report jobs from the lanalytics_api. It then uses Admin::ReportJobPresenter to format existing jobs for display and Admin::ReportPresenter to prepare report creation forms, dynamically populating options like courses (from course_api) and classifiers (from Course::Classifier). When an administrator submits a new report creation request, the Admin::ReportsController sends this request, including task_type, task_scope, and options, to the lanalytics_api. For managing existing jobs, the controller also facilitates restarting failed jobs and deleting completed or failed jobs through direct interactions with the lanalytics_api. The frontend continuously updates the display, showing job progress, completion status, or error details in a modal if a job fails.
3. Detailed Course Statistics Retrieval
graph TD adminClient["Admin UI Request"] detailCtrl["DetailStatisticsController"] cache["Rails Cache"] lanalyticsAPI["Lanalytics API"] courseAPI["Course API"] pinboardAPI["Pinboard API (Beta Feature)"] adminClient -->|"requests course stats"| detailCtrl detailCtrl -->|"check/store data"| cache detailCtrl -->|"fetches geo/video metrics"| lanalyticsAPI detailCtrl -->|"fetches course items"| courseAPI detailCtrl -->|"fetches pinboard activity"| pinboardAPI lanalyticsAPI -->|"provides metrics"| detailCtrl courseAPI -->|"provides items"| detailCtrl pinboardAPI -->|"provides activity"| detailCtrl detailCtrl -->|"aggregates and returns"| adminClient
This workflow details how specific analytical data for individual courses is fetched and presented, including geographical and content engagement metrics.
An administrator selects a specific course and requests its detailed statistics from the Admin UI. This request is handled by the Admin::Ajax::DetailStatisticsController. Similar to platform statistics, the controller first checks Rails.cache for existing data, caching results for up to 6 hours. If a cache miss occurs, the controller proceeds to fetch various metrics. It requests top_countries, top_cities, top_items, and video_statistics from the learnanalytics_api using the fetch_metric helper. To determine top_item_types, it first retrieves all course items from course_api and then combines this with the top_items metrics. Additionally, if the teaching_team_pinboard_activity beta feature is enabled, the controller queries the pinboard_api for pinboard activity statistics. Geographical data might implicitly rely on GeoIP::Lookup being used by an underlying service to enrich IP addresses. Once all data is collected and processed, itβs served to the Admin UI for display.
π§ Implementation Details
The 31_ADMIN_Analytics cluster integrates deeply with various microservices and internal models to provide comprehensive insights. Frontend interactions, primarily driven by AJAX, ensure a dynamic user experience, while backend processes focus on efficient data aggregation and presentation.
Technical Considerations:
- Caching Strategy:
Rails.cacheis extensively used acrossAdmin::Ajax::PlatformStatisticsController(30 mins to 1 hour expiration) andAdmin::Ajax::DetailStatisticsController(6 hours expiration) for platform-wide and course-specific statistics respectively, along with arace_condition_ttlto prevent thundering herd problems.Course::Statisticsalso caches certificate data for 1 hour. This indicates a strong emphasis on performance optimization for frequently accessed statistics. - Concurrent API Calls:
Restify::Promiseis employed inAdmin::Ajax::PlatformStatisticsControllerto make concurrent API calls toaccount_apiandcourse_api, significantly reducing latency for fetching multiple data points simultaneously. - Data Transformation: Presenters like
Admin::ReportJobPresenterandAdmin::ReportPresenterare crucial for formatting raw data received from APIs or models into a user-friendly format for display, including mapping IDs to human-readable titles and handling conditional display logic (e.g., job restartability). - Asynchronous Frontend Updates: The
report-jobs.jsscript exemplifies a client-side polling mechanism, updating report job listings every 10 seconds. This pushes the responsibility of maintaining an up-to-date view to the client, reducing server-side complexity for real-time updates. - Direct Database Queries & Raw SQL: Components like
Course::EnrollmentsStatistics,Course::Statistics,Poll::Stats, andVoucher::Statsdirectly query the database.Poll::Statsnotably uses raw SQL forpoll_responsescounting, which might be a performance optimization but poses a technical debt due to maintainability.
Dependencies and Integrations:
- Microservices: Direct API interactions with
account_api,course_api,lanalytics_api, andpinboard_apiare fundamental for data retrieval and report job management. These are accessed viaXikolo.api()orRestify::Promise. - Internal Models: Relies heavily on internal ActiveRecord models such as
Course::Classifier,Video::Stream,Course::Enrollment,Course::Visit,Poll::Poll, andVoucher::Voucherfor data that resides within the primary applicationβs database or is managed directly. - Utility Modules:
GeoIP::Lookupprovides IP address to geographical location resolution, reading fromvendor/GeoLite2-Country/GeoLite2-Country.mmdb.LanalyticsHelperprovides frontend configuration details like user ID andENV['RELEASE_NUMBER']. - Frontend Data Fetching:
Acfs.runis utilized withinCourse::Admin::StatisticsControllerfor various course statistics views, indicating a specialized frontend data fetching mechanism.
Configuration Requirements:
- Global Deltas:
Xikolo.config.global_enrollment_deltaandXikolo.config.global_users_deltaare used to adjust global enrollment and user counts, respectively. These are critical for accurate platform-wide reporting. - Feature Flags: The
teaching_team_pinboard_activitybeta feature controls access to pinboard statistics inAdmin::Ajax::DetailStatisticsControllerandCourse::Admin::StatisticsController. - Environment Variables:
ENV['RELEASE_NUMBER']is read byLanalyticsHelperto include the build version in frontend analytics data, which is useful for debugging and tracking. - GeoIP Database: The presence of
vendor/GeoLite2-Country/GeoLite2-Country.mmdbis explicitly required byGeoIP::Lookupfor geographical data resolution. This database is not included in the open-source codebase and must be sourced externally. - Permissions: Specific permissions are required for various actions, such as
global.dashboard.showfor viewing dashboards,lanalytics.report.createandlanalytics.report.deletefor report management. Thelanalytics.report.adminrole bundles these reporting permissions, managed manually via Rails console in theaccountservice, which is noted as a potential technical debt for its lack of a user-friendly interface.
π Technical Sources & References
Components
- π Admin::Ajax::ClassifiersController
app/controllers/admin/ajax/classifiers_controller.rb - π Admin::Ajax::CoursesController
app/controllers/admin/ajax/courses_controller.rb - π Admin::Ajax::DetailStatisticsController
app/controllers/admin/ajax/detail_statistics_controller.rb - π Admin::Ajax::PlatformStatisticsController
app/controllers/admin/ajax/platform_statistics_controller.rb - π Admin::Ajax::StreamsController
app/controllers/admin/ajax/streams_controller.rb - π Admin::Ajax::UsersController
app/controllers/admin/ajax/users_controller.rb - π Admin::ReportsController
app/controllers/admin/reports_controller.rb - π Admin::StatisticsController
app/controllers/admin/statistics_controller.rb - π Admin::ReportJobPresenter
app/presenters/admin/report_job_presenter.rb - π Admin::ReportPresenter
app/presenters/admin/report_presenter.rb - π Admin::StatisticsPresenter
app/presenters/admin/statistics_presenter.rb - π Course::Admin::StatisticsController
app/controllers/course/admin/statistics_controller.rb
Configuration
- π LanalyticsHelper
app/helpers/lanalytics_helper.rb - π Course::EnrollmentsStatistics
app/models/course/enrollments_statistics.rb - π Course::Statistics
app/models/course/statistics.rb - π GeoIP::Lookup
lib/geo_ip/lookup.rb - π Poll::Stats
app/models/poll/stats.rb - π Voucher::Stats
app/models/voucher/stats.rb - π lanalytics.report.admin Role
RAG: services/account/lib/tasks/permissions/lanalytics.yml - π Configuration
config/application.rb, Gemfile, config/database.yml - π Process Management
Procfile, Procfile.web - π Build & Deploy
Rakefile, package.json
Documentation
- π lanalytics.report.admin Role
RAG: docs/app/features/permissions/reporting.md
Other
- π report-jobs.js
app/assets/admin/reports/report-jobs.js
This documentation is automatically generated from cluster analysis and should be validated against the actual codebase.