In the modern e-learning ecosystem, personalized dashboards have become a necessity. Students, trainers, and administrators want tailored insights—like progress tracking, suggested courses, and learning analytics. By integrating AI models, these dashboards can recommend courses, identify weak areas, and even predict student performance.
This article will guide you step by step to build a production-ready AI-powered personalized learning dashboard using:
We will focus on dynamic dashboards, personalization, data persistence, and scalability.
1. Understanding the System Architecture
A modern AI-powered learning dashboard has three main layers:
1. Frontend (Angular)
Displays widgets like Course Progress, Recommended Lessons, Performance Graphs
Sends user actions and feedback to the backend
Supports dynamic widgets and drag-drop layouts
2. Backend (ASP.NET Core)
Serves API endpoints for user data, courses, and analytics
Integrates AI/ML models to generate recommendations
Stores user preferences and dashboard layout
3. AI Service / Machine Learning
Recommends courses or content using collaborative filtering or content-based models
Predicts student performance based on historical activity
Suggests skill gaps and next learning steps
High-Level Flow
User -> Angular Frontend -> ASP.NET Core API -> AI/ML Service
<- Response <- <- Predictions/Recommendations
2. Project Setup
Step 1: Create Backend Project
dotnet new webapi -n LearningDashboardAPI
cd LearningDashboardAPI
Step 2: Install Required Packages
For ML.NET recommendations or predictive models:
dotnet add package Microsoft.ML
dotnet add package Microsoft.ML.Recommender
For AI/ML API integration:
dotnet add package System.Net.Http.Json
Step 3: Create Models
Models/UserDashboard.cs
public class UserDashboard
{
public string UserId { get; set; } = string.Empty;
public List<WidgetConfig> Widgets { get; set; } = new List<WidgetConfig>();
}
Models/WidgetConfig.cs
public class WidgetConfig
{
public string Id { get; set; } = Guid.NewGuid().ToString();
public string Type { get; set; } = string.Empty; // progress, recommendations, charts
public string Title { get; set; } = string.Empty;
public int PositionX { get; set; }
public int PositionY { get; set; }
public int Width { get; set; } = 300;
public int Height { get; set; } = 250;
}
Models/CourseRecommendation.cs
public class CourseRecommendation
{
public string CourseId { get; set; } = string.Empty;
public string CourseName { get; set; } = string.Empty;
public double Score { get; set; }
}
3. AI-Based Recommendation Service
Step 1: Using ML.NET Collaborative Filtering
using Microsoft.ML;
using Microsoft.ML.Trainers;
public class RecommendationService
{
private MLContext _mlContext;
private ITransformer? _model;
public RecommendationService()
{
_mlContext = new MLContext();
TrainModel();
}
private void TrainModel()
{
// Sample: user-course interactions
var data = _mlContext.Data.LoadFromTextFile<UserCourseData>("Data/UserCourses.csv", hasHeader: true, separatorChar: ',');
var pipeline = _mlContext.Recommendation().Trainers.MatrixFactorization(
new MatrixFactorizationTrainer.Options
{
MatrixColumnIndexColumnName = nameof(UserCourseData.UserId),
MatrixRowIndexColumnName = nameof(UserCourseData.CourseId),
LabelColumnName = nameof(UserCourseData.Rating),
NumberOfIterations = 20,
ApproximationRank = 100
});
_model = pipeline.Fit(data);
}
public float PredictRating(int userId, int courseId)
{
if (_model == null) return 0;
var predictionEngine = _mlContext.Model.CreatePredictionEngine<UserCourseData, CourseRatingPrediction>(_model);
return predictionEngine.Predict(new UserCourseData { UserId = userId, CourseId = courseId }).Score;
}
}
Models/UserCourseData.cs
public class UserCourseData
{
public int UserId { get; set; }
public int CourseId { get; set; }
public float Rating { get; set; }
}
public class CourseRatingPrediction
{
public float Score { get; set; }
}
Step 2: Expose Recommendations via API
[ApiController]
[Route("api/[controller]")]
public class RecommendationsController : ControllerBase
{
private readonly RecommendationService _recommendationService;
public RecommendationsController(RecommendationService recommendationService)
{
_recommendationService = recommendationService;
}
[HttpGet("{userId}")]
public IActionResult GetRecommendations(int userId)
{
var recommendedCourses = new List<CourseRecommendation>();
for (int courseId = 1; courseId <= 10; courseId++)
{
recommendedCourses.Add(new CourseRecommendation
{
CourseId = courseId.ToString(),
CourseName = $"Course {courseId}",
Score = _recommendationService.PredictRating(userId, courseId)
});
}
var sorted = recommendedCourses.OrderByDescending(c => c.Score).ToList();
return Ok(sorted);
}
}
4. Backend: Dashboard Persistence
Services/DashboardService.cs
public class DashboardService
{
private readonly Dictionary<string, UserDashboard> _store = new();
public UserDashboard GetDashboard(string userId)
{
if (!_store.ContainsKey(userId))
_store[userId] = new UserDashboard { UserId = userId };
return _store[userId];
}
public void SaveDashboard(UserDashboard dashboard)
{
_store[dashboard.UserId] = dashboard;
}
}
In production, replace this with database persistence (SQL Server, MongoDB, etc.)
5. Angular Frontend
Step 1: Generate Angular Project
ng new learning-dashboard --routing --style=scss
cd learning-dashboard
ng serve
Step 2: Create Models
src/app/models/widget.model.ts
export interface WidgetConfig {
id: string;
type: string;
title: string;
positionX: number;
positionY: number;
width: number;
height: number;
}
src/app/models/course-recommendation.model.ts
export interface CourseRecommendation {
courseId: string;
courseName: string;
score: number;
}
Step 3: Services
src/app/services/dashboard.service.ts
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
import { WidgetConfig } from '../models/widget.model';
import { CourseRecommendation } from '../models/course-recommendation.model';
@Injectable({ providedIn: 'root' })
export class DashboardService {
private apiUrl = 'https://localhost:5001/api';
constructor(private http: HttpClient) {}
getUserDashboard(userId: string): Observable<WidgetConfig[]> {
return this.http.get<WidgetConfig[]>(`${this.apiUrl}/dashboard/${userId}`);
}
saveUserDashboard(dashboard: WidgetConfig[]): Observable<any> {
return this.http.post(`${this.apiUrl}/dashboard/save`, dashboard);
}
getRecommendations(userId: string): Observable<CourseRecommendation[]> {
return this.http.get<CourseRecommendation[]>(`${this.apiUrl}/recommendations/${userId}`);
}
}
Step 4: Dashboard Component
src/app/components/dashboard/dashboard.component.ts
import { Component, OnInit } from '@angular/core';
import { DashboardService } from '../../services/dashboard.service';
import { WidgetConfig } from '../../models/widget.model';
import { CourseRecommendation } from '../../models/course-recommendation.model';
@Component({
selector: 'app-dashboard',
templateUrl: './dashboard.component.html',
styleUrls: ['./dashboard.component.scss']
})
export class DashboardComponent implements OnInit {
widgets: WidgetConfig[] = [];
recommendations: CourseRecommendation[] = [];
userId = '123';
constructor(private dashboardService: DashboardService) {}
ngOnInit(): void {
this.loadDashboard();
this.loadRecommendations();
}
loadDashboard(): void {
this.dashboardService.getUserDashboard(this.userId).subscribe(w => this.widgets = w);
}
loadRecommendations(): void {
this.dashboardService.getRecommendations(this.userId).subscribe(r => this.recommendations = r);
}
saveDashboard(): void {
this.dashboardService.saveUserDashboard(this.widgets).subscribe();
}
}
Step 5: Dashboard Template
dashboard.component.html
<div class="dashboard-container">
<div class="widgets">
<div *ngFor="let widget of widgets" class="widget-box" [style.width.px]="widget.width" [style.height.px]="widget.height">
<h3>{{ widget.title }}</h3>
<ng-container [ngSwitch]="widget.type">
<div *ngSwitchCase="'recommendations'">
<ul>
<li *ngFor="let rec of recommendations">{{ rec.courseName }} (Score: {{ rec.score | number:'1.1-2' }})</li>
</ul>
</div>
<div *ngSwitchDefault>Widget content here</div>
</ng-container>
</div>
</div>
<button (click)="saveDashboard()">Save Dashboard</button>
</div>
6. AI-Powered Personalization Logic
Course Recommendation Widget
Progress Widget
Skill Gap Widget
Dynamic Widget Management
7. Best Practices
Backend AI Service Separation: Keep AI/ML logic separate from API controllers.
Caching: Cache recommendations for frequent queries.
Security: Authenticate API endpoints; prevent unauthorized access to personalized dashboards.
Persistence: Use databases for dashboard layout and user interaction history.
Scalability: Use async processing or queue-based systems for heavy AI tasks.
Observability: Log dashboard metrics, recommendation usage, and AI model latency.
Front-end UX: Use loading indicators when recommendations are being fetched.
8. Folder Structure
LearningDashboardAPI/
Controllers/
DashboardController.cs
RecommendationsController.cs
Models/
UserDashboard.cs
WidgetConfig.cs
CourseRecommendation.cs
UserCourseData.cs
Services/
RecommendationService.cs
DashboardService.cs
Data/
UserCourses.csv
AngularApp/
src/app/
components/
dashboard/
dashboard.component.ts
dashboard.component.html
dashboard.component.scss
services/
dashboard.service.ts
models/
widget.model.ts
course-recommendation.model.ts
9. Conclusion
By combining Angular and ASP.NET Core with AI-powered ML models, you can build dynamic personalized learning dashboards that adapt to each user. Key benefits include:
Personalized course recommendations
Progress tracking and analytics
Skill gap identification
Dynamic widgets with drag-drop and persistence
This architecture is scalable, maintainable, and production-ready, making it suitable for:
Online learning platforms
Corporate training systems
EdTech SaaS applications
Student performance analytics portals
This sets up a full-stack personalized AI dashboard with clear separation between frontend, backend, and AI services.