Intelligent Educational Progress Tracking System
AI-powered learning analytics with predictive intervention and personalized learning paths
typescript
import { cronflow } from 'cronflow';
import express from 'express';
import { z } from 'zod';
const app = express();
app.use(express.json());
// Types for educational progress tracking
interface Student {
id: string;
name: string;
grade: number;
age: number;
learningStyle: 'visual' | 'auditory' | 'kinesthetic' | 'reading';
specialNeeds?: string[];
parentEmails: string[];
enrollmentDate: string;
currentGPA: number;
attendanceRate: number;
}
interface Assignment {
id: string;
title: string;
subject: string;
type: 'homework' | 'quiz' | 'test' | 'project' | 'participation';
totalPoints: number;
dueDate: string;
difficultyLevel: 1 | 2 | 3 | 4 | 5;
learningObjectives: string[];
estimatedTimeMinutes: number;
}
interface Submission {
id: string;
studentId: string;
assignmentId: string;
submittedAt: string;
score: number;
maxScore: number;
timeSpent?: number; // minutes
attemptCount: number;
feedback?: string;
teacherNotes?: string;
rubricScores?: Record<string, number>; // rubric criteria -> score
}
interface LearningAnalytics {
studentId: string;
subject: string;
conceptMastery: Record<string, number>; // concept -> mastery percentage
learningVelocity: number; // concepts mastered per week
strugglingAreas: string[];
strengthAreas: string[];
engagementLevel: number; // 0-1 scale
predictedGrade: string;
riskLevel: 'low' | 'medium' | 'high';
interventionRecommendations: string[];
}
interface PersonalizedPath {
studentId: string;
subject: string;
nextRecommendations: Array<{
type: 'review' | 'practice' | 'advanced' | 'remediation';
content: string;
estimatedTime: number;
priority: 'high' | 'medium' | 'low';
reason: string;
}>;
adaptiveStrategies: string[];
preferredResources: string[];
}
interface InterventionAlert {
studentId: string;
alertType: 'academic' | 'attendance' | 'engagement' | 'behavioral';
severity: 'low' | 'medium' | 'high' | 'critical';
description: string;
recommendedActions: string[];
stakeholders: string[]; // who should be notified
deadline?: string;
}
// Mock educational data services
async function getStudentProfile(studentId: string): Promise<Student> {
console.log('👨🎓 Loading student profile for:', studentId);
// Mock student data
return {
id: studentId,
name: `Student ${studentId.slice(-3)}`,
grade: 8,
age: 14,
learningStyle: 'visual',
specialNeeds: ['ADHD'],
parentEmails: ['parent1@example.com', 'parent2@example.com'],
enrollmentDate: '2024-08-15T00:00:00Z',
currentGPA: 3.2,
attendanceRate: 0.85,
};
}
async function getRecentSubmissions(
studentId: string,
days: number = 30
): Promise<Submission[]> {
console.log(
`📚 Fetching recent submissions for student ${studentId} (last ${days} days)`
);
// Mock submission data with realistic patterns
const submissions: Submission[] = [];
const subjects = ['Math', 'English', 'Science', 'History', 'Art'];
const assignmentTypes = [
'homework',
'quiz',
'test',
'project',
'participation',
] as const;
for (let i = 0; i < 15; i++) {
const daysAgo = Math.floor(Math.random() * days);
const subject = subjects[Math.floor(Math.random() * subjects.length)];
const type =
assignmentTypes[Math.floor(Math.random() * assignmentTypes.length)];
// Simulate performance patterns based on subject and type
let baseScore = 0.7; // 70% base performance
if (subject === 'Math') baseScore = 0.6; // Struggling with math
if (subject === 'Art') baseScore = 0.9; // Strong in art
if (type === 'test') baseScore -= 0.1; // Tests are harder
const randomVariation = (Math.random() - 0.5) * 0.3;
const scorePercentage = Math.max(
0.3,
Math.min(1.0, baseScore + randomVariation)
);
submissions.push({
id: `sub_${i}`,
studentId,
assignmentId: `assign_${subject}_${i}`,
submittedAt: new Date(
Date.now() - daysAgo * 24 * 60 * 60 * 1000
).toISOString(),
score: Math.round(scorePercentage * 100),
maxScore: 100,
timeSpent: Math.floor(Math.random() * 120) + 30, // 30-150 minutes
attemptCount: Math.floor(Math.random() * 3) + 1,
feedback:
scorePercentage < 0.7
? 'Needs improvement in key concepts'
: 'Good work!',
rubricScores: {
Understanding: Math.round(scorePercentage * 100),
Application: Math.round(
(scorePercentage + (Math.random() - 0.5) * 0.2) * 100
),
Communication: Math.round(
(scorePercentage + (Math.random() - 0.5) * 0.15) * 100
),
},
});
}
return submissions.sort(
(a, b) =>
new Date(b.submittedAt).getTime() - new Date(a.submittedAt).getTime()
);
}
async function analyzeLearningPatterns(
student: Student,
submissions: Submission[]
): Promise<LearningAnalytics> {
console.log('🔍 Analyzing learning patterns and performance trends...');
// Group submissions by subject
const subjectGroups = submissions.reduce(
(groups, sub) => {
const subject = sub.assignmentId.split('_')[1]; // Extract subject from assignment ID
if (!groups[subject]) groups[subject] = [];
groups[subject].push(sub);
return groups;
},
{} as Record<string, Submission[]>
);
const analytics: Record<string, LearningAnalytics> = {};
for (const [subject, subs] of Object.entries(subjectGroups)) {
const avgScore =
subs.reduce((sum, s) => sum + s.score / s.maxScore, 0) / subs.length;
const recentScores = subs.slice(0, 5).map(s => s.score / s.maxScore);
const earlierScores = subs.slice(-5).map(s => s.score / s.maxScore);
// Calculate learning velocity (improvement over time)
const recentAvg =
recentScores.reduce((sum, s) => sum + s, 0) / recentScores.length;
const earlierAvg =
earlierScores.reduce((sum, s) => sum + s, 0) / earlierScores.length;
const learningVelocity = (recentAvg - earlierAvg) * 100; // percentage change
// Identify struggling and strength areas
const conceptScores = subs.reduce(
(concepts, sub) => {
if (sub.rubricScores) {
Object.entries(sub.rubricScores).forEach(([concept, score]) => {
if (!concepts[concept]) concepts[concept] = [];
concepts[concept].push(score / 100);
});
}
return concepts;
},
{} as Record<string, number[]>
);
const conceptMastery = Object.entries(conceptScores).reduce(
(mastery, [concept, scores]) => {
mastery[concept] =
(scores.reduce((sum, s) => sum + s, 0) / scores.length) * 100;
return mastery;
},
{} as Record<string, number>
);
const strugglingAreas = Object.entries(conceptMastery)
.filter(([_, score]) => score < 70)
.map(([concept, _]) => concept);
const strengthAreas = Object.entries(conceptMastery)
.filter(([_, score]) => score > 85)
.map(([concept, _]) => concept);
// Calculate engagement level based on time spent and attempt patterns
const avgTimeSpent =
subs.filter(s => s.timeSpent).reduce((sum, s) => sum + s.timeSpent!, 0) /
subs.filter(s => s.timeSpent).length;
const avgAttempts =
subs.reduce((sum, s) => sum + s.attemptCount, 0) / subs.length;
const engagementLevel = Math.min(
1,
(avgTimeSpent / 60) * (avgAttempts / 2) * avgScore
); // Normalized engagement
// Predict grade and risk level
let predictedGrade = 'C';
let riskLevel: 'low' | 'medium' | 'high' = 'medium';
if (avgScore > 0.9) {
predictedGrade = 'A';
riskLevel = 'low';
} else if (avgScore > 0.8) {
predictedGrade = 'B';
riskLevel = 'low';
} else if (avgScore > 0.7) {
predictedGrade = 'C';
riskLevel = 'medium';
} else if (avgScore > 0.6) {
predictedGrade = 'D';
riskLevel = 'high';
} else {
predictedGrade = 'F';
riskLevel = 'high';
}
// Generate intervention recommendations
const interventionRecommendations: string[] = [];
if (strugglingAreas.length > 0) {
interventionRecommendations.push(
`Focus on ${strugglingAreas.join(', ')} concepts`
);
}
if (learningVelocity < -5) {
interventionRecommendations.push(
'Consider additional tutoring or support'
);
}
if (engagementLevel < 0.5) {
interventionRecommendations.push(
'Increase engagement through interactive activities'
);
}
if (student.attendanceRate < 0.8) {
interventionRecommendations.push(
'Address attendance issues affecting performance'
);
}
analytics[subject] = {
studentId: student.id,
subject,
conceptMastery,
learningVelocity,
strugglingAreas,
strengthAreas,
engagementLevel,
predictedGrade,
riskLevel,
interventionRecommendations,
};
}
// Return analytics for the primary subject (Math for this example)
return analytics['Math'] || Object.values(analytics)[0];
}
async function generatePersonalizedPath(
student: Student,
analytics: LearningAnalytics
): Promise<PersonalizedPath> {
console.log('🎯 Generating personalized learning path...');
const recommendations: Array<{
type: 'review' | 'practice' | 'advanced' | 'remediation';
content: string;
estimatedTime: number;
priority: 'high' | 'medium' | 'low';
reason: string;
}> = [];
// Add remediation for struggling areas
analytics.strugglingAreas.forEach(area => {
recommendations.push({
type: 'remediation' as const,
content: `Review ${area} fundamentals with visual aids and practice problems`,
estimatedTime: 45,
priority: 'high' as const,
reason: `Identified weakness in ${area} (${analytics.conceptMastery[area]?.toFixed(1)}% mastery)`,
});
});
// Add practice for areas near mastery
Object.entries(analytics.conceptMastery).forEach(([concept, mastery]) => {
if (mastery >= 70 && mastery < 85) {
recommendations.push({
type: 'practice' as const,
content: `Practice ${concept} with intermediate-level problems`,
estimatedTime: 30,
priority: 'medium' as const,
reason: `Build confidence in ${concept} (${mastery.toFixed(1)}% mastery)`,
});
}
});
// Add advanced content for strength areas
analytics.strengthAreas.forEach(area => {
recommendations.push({
type: 'advanced' as const,
content: `Explore advanced ${area} concepts and real-world applications`,
estimatedTime: 60,
priority: 'low' as const,
reason: `Strength area ready for enrichment (${analytics.conceptMastery[area]?.toFixed(1)}% mastery)`,
});
});
// Adaptive strategies based on learning style and needs
const adaptiveStrategies: string[] = [];
if (student.learningStyle === 'visual') {
adaptiveStrategies.push('Use diagrams, charts, and visual representations');
adaptiveStrategies.push('Color-code different concepts and problem types');
} else if (student.learningStyle === 'auditory') {
adaptiveStrategies.push('Include video explanations and audio content');
adaptiveStrategies.push('Encourage study groups and verbal explanations');
} else if (student.learningStyle === 'kinesthetic') {
adaptiveStrategies.push('Include hands-on activities and manipulatives');
adaptiveStrategies.push('Break study into shorter, active sessions');
}
if (student.specialNeeds?.includes('ADHD')) {
adaptiveStrategies.push('Provide frequent breaks and varied activities');
adaptiveStrategies.push('Use timers and structured task lists');
}
// Preferred resources based on performance and engagement
const preferredResources = [
'Interactive practice problems',
'Video tutorials matching learning style',
'Peer collaboration opportunities',
'Gamified learning modules',
];
if (analytics.engagementLevel < 0.5) {
preferredResources.unshift(
'Engaging multimedia content',
'Short-format lessons'
);
}
return {
studentId: student.id,
subject: analytics.subject,
nextRecommendations: recommendations.slice(0, 5), // Top 5 recommendations
adaptiveStrategies,
preferredResources,
};
}
async function detectInterventionNeeds(
student: Student,
analytics: LearningAnalytics,
submissions: Submission[]
): Promise<InterventionAlert[]> {
console.log('🚨 Detecting intervention needs...');
const alerts: InterventionAlert[] = [];
// Academic performance alerts
if (analytics.riskLevel === 'high') {
alerts.push({
studentId: student.id,
alertType: 'academic',
severity: 'high',
description: `Student at risk of failing ${analytics.subject} (predicted grade: ${analytics.predictedGrade})`,
recommendedActions: [
'Schedule parent-teacher conference',
'Implement intensive tutoring program',
'Consider modified assignment schedule',
...analytics.interventionRecommendations,
],
stakeholders: ['teacher', 'counselor', 'parents'],
deadline: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000).toISOString(), // 1 week
});
}
// Attendance alerts
if (student.attendanceRate < 0.8) {
alerts.push({
studentId: student.id,
alertType: 'attendance',
severity: student.attendanceRate < 0.7 ? 'high' : 'medium',
description: `Poor attendance rate: ${(student.attendanceRate * 100).toFixed(1)}%`,
recommendedActions: [
'Contact parents about attendance concerns',
'Investigate barriers to attendance',
'Develop attendance improvement plan',
'Consider flexible scheduling if appropriate',
],
stakeholders: ['teacher', 'attendance_officer', 'parents'],
});
}
// Engagement alerts
if (analytics.engagementLevel < 0.3) {
alerts.push({
studentId: student.id,
alertType: 'engagement',
severity: 'medium',
description: `Low engagement in ${analytics.subject} (${(analytics.engagementLevel * 100).toFixed(1)}%)`,
recommendedActions: [
'Explore alternative teaching methods',
'Increase interactive activities',
'Connect content to student interests',
'Consider peer mentoring',
],
stakeholders: ['teacher', 'counselor'],
});
}
// Learning velocity alerts (declining performance)
if (analytics.learningVelocity < -10) {
alerts.push({
studentId: student.id,
alertType: 'academic',
severity: 'medium',
description: `Performance declining in ${analytics.subject} (${analytics.learningVelocity.toFixed(1)}% change)`,
recommendedActions: [
'Review recent teaching methods',
'Check for external factors affecting performance',
'Provide additional support in struggling areas',
'Monitor closely for continued decline',
],
stakeholders: ['teacher', 'counselor'],
});
}
return alerts;
}
async function sendNotifications(
type: string,
data: any,
recipients: string[]
): Promise<void> {
console.log(`📧 Sending ${type} notifications to:`, recipients);
console.log('Notification data:', JSON.stringify(data, null, 2));
// In real implementation, integrate with email/SMS services
// Could also integrate with school management systems, parent portals, etc.
}
async function updateStudentRecords(
studentId: string,
analytics: LearningAnalytics,
personalizedPath: PersonalizedPath
): Promise<void> {
console.log(`💾 Updating student records for ${studentId}`);
// In real implementation, update student information system
// Store analytics, learning paths, and intervention history
}
// Schema for education progress tracking
const progressTrackingSchema = z.object({
studentId: z.string().min(1),
submissionData: z
.object({
assignmentId: z.string(),
score: z.number().min(0),
maxScore: z.number().positive(),
timeSpent: z.number().positive().optional(),
submittedAt: z.string().datetime().optional(),
feedback: z.string().optional(),
})
.optional(),
forceAnalysis: z.boolean().default(false),
analysisWindow: z.number().positive().default(30), // days
notifyParents: z.boolean().default(true),
generateReport: z.boolean().default(true),
});
// Define the educational progress tracking workflow
const educationTrackingWorkflow = cronflow.define({
id: 'education-progress-tracking',
name: 'Intelligent Educational Progress Tracking System',
description:
'AI-powered learning analytics with predictive intervention and personalized learning paths',
hooks: {
onSuccess: (ctx, stepId) => {
if (!stepId) {
console.log('🎉 Educational progress analysis completed successfully!');
console.log(
'📊 Analysis results:',
JSON.stringify(ctx.last.summary, null, 2)
);
}
},
onFailure: (ctx, stepId) => {
console.log(`❌ Educational progress tracking failed at step: ${stepId}`);
console.log('Error:', ctx.step_error || ctx.error);
},
},
});
educationTrackingWorkflow
// Step 1: Load student profile and recent submissions
.step('load-student-data', async ctx => {
console.log('📋 Loading student profile and academic history...');
const student = await getStudentProfile(ctx.payload.studentId);
const submissions = await getRecentSubmissions(
ctx.payload.studentId,
ctx.payload.analysisWindow
);
// If new submission data provided, add it to the analysis
if (ctx.payload.submissionData) {
const newSubmission: Submission = {
id: `sub_${Date.now()}`,
studentId: ctx.payload.studentId,
assignmentId: ctx.payload.submissionData.assignmentId,
submittedAt:
ctx.payload.submissionData.submittedAt || new Date().toISOString(),
score: ctx.payload.submissionData.score,
maxScore: ctx.payload.submissionData.maxScore,
timeSpent: ctx.payload.submissionData.timeSpent,
attemptCount: 1,
feedback: ctx.payload.submissionData.feedback,
};
submissions.unshift(newSubmission);
console.log(
`📝 Processing new submission: ${newSubmission.score}/${newSubmission.maxScore} points`
);
}
console.log(`👨🎓 Student: ${student.name} (Grade ${student.grade})`);
console.log(`📚 Analyzing ${submissions.length} recent submissions`);
console.log(
`📈 Current GPA: ${student.currentGPA}, Attendance: ${(student.attendanceRate * 100).toFixed(1)}%`
);
return { student, submissions };
})
// Step 2: Perform learning analytics
.step('analyze-learning-patterns', async ctx => {
console.log('🔍 Analyzing learning patterns and performance trends...');
const analytics = await analyzeLearningPatterns(
ctx.last.student,
ctx.last.submissions
);
console.log(`📊 Subject: ${analytics.subject}`);
console.log(`🎯 Predicted Grade: ${analytics.predictedGrade}`);
console.log(`⚠️ Risk Level: ${analytics.riskLevel}`);
console.log(
`📈 Learning Velocity: ${analytics.learningVelocity.toFixed(1)}%`
);
console.log(
`💡 Engagement Level: ${(analytics.engagementLevel * 100).toFixed(1)}%`
);
if (analytics.strugglingAreas.length > 0) {
console.log(
`🔍 Struggling Areas: ${analytics.strugglingAreas.join(', ')}`
);
}
if (analytics.strengthAreas.length > 0) {
console.log(`💪 Strength Areas: ${analytics.strengthAreas.join(', ')}`);
}
return {
student: ctx.last.student,
submissions: ctx.last.submissions,
analytics,
};
})
// Step 3: Generate personalized learning path
.step('generate-personalized-path', async ctx => {
console.log('🎯 Generating personalized learning path...');
const personalizedPath = await generatePersonalizedPath(
ctx.last.student,
ctx.last.analytics
);
console.log(
`📚 Generated ${personalizedPath.nextRecommendations.length} learning recommendations`
);
console.log(
`🔧 Adaptive strategies: ${personalizedPath.adaptiveStrategies.length} strategies`
);
personalizedPath.nextRecommendations.forEach((rec, index) => {
console.log(
` ${index + 1}. [${rec.priority.toUpperCase()}] ${rec.content} (${rec.estimatedTime}min)`
);
console.log(` Reason: ${rec.reason}`);
});
return {
student: ctx.last.student,
submissions: ctx.last.submissions,
analytics: ctx.last.analytics,
personalizedPath,
};
})
// Step 4: Detect intervention needs
.step('detect-interventions', async ctx => {
console.log('🚨 Detecting intervention needs...');
const interventionAlerts = await detectInterventionNeeds(
ctx.last.student,
ctx.last.analytics,
ctx.last.submissions
);
if (interventionAlerts.length > 0) {
console.log(
`⚠️ Generated ${interventionAlerts.length} intervention alerts:`
);
interventionAlerts.forEach((alert, index) => {
console.log(
` ${index + 1}. [${alert.severity.toUpperCase()}] ${alert.alertType}: ${alert.description}`
);
console.log(` Stakeholders: ${alert.stakeholders.join(', ')}`);
if (alert.deadline) {
console.log(
` Deadline: ${new Date(alert.deadline).toLocaleDateString()}`
);
}
});
} else {
console.log('✅ No immediate interventions needed');
}
return {
student: ctx.last.student,
submissions: ctx.last.submissions,
analytics: ctx.last.analytics,
personalizedPath: ctx.last.personalizedPath,
interventionAlerts,
};
})
// Step 5: Update student records
.step('update-records', async ctx => {
console.log('💾 Updating student academic records...');
await updateStudentRecords(
ctx.last.student.id,
ctx.last.analytics,
ctx.last.personalizedPath
);
console.log('✅ Student records updated successfully');
return {
student: ctx.last.student,
analytics: ctx.last.analytics,
personalizedPath: ctx.last.personalizedPath,
interventionAlerts: ctx.last.interventionAlerts,
recordsUpdated: true,
};
})
// Conditional: Send notifications if interventions are needed or parents should be notified
.if(
'needs-notifications',
ctx =>
ctx.payload.notifyParents ||
ctx.last.interventionAlerts.length > 0 ||
ctx.last.analytics.riskLevel === 'high'
)
// Parallel notification sending
.parallel([
// Notify parents
async ctx => {
if (ctx.payload.notifyParents) {
console.log('👨👩👧👦 Sending parent notifications...');
const parentNotification = {
studentName: ctx.last.student.name,
subject: ctx.last.analytics.subject,
predictedGrade: ctx.last.analytics.predictedGrade,
engagementLevel: ctx.last.analytics.engagementLevel,
recommendations: ctx.last.personalizedPath.nextRecommendations.slice(
0,
3
),
interventions: ctx.last.interventionAlerts.filter(a =>
a.stakeholders.includes('parents')
),
};
await sendNotifications(
'parent_update',
parentNotification,
ctx.last.student.parentEmails
);
return { parentNotificationSent: true };
}
return { parentNotificationSent: false };
},
// Notify teachers and counselors
async ctx => {
const teacherAlerts = ctx.last.interventionAlerts.filter(
a =>
a.stakeholders.includes('teacher') ||
a.stakeholders.includes('counselor')
);
if (teacherAlerts.length > 0) {
console.log('👩🏫 Sending teacher/counselor alerts...');
const teacherNotification = {
studentName: ctx.last.student.name,
alerts: teacherAlerts,
analytics: ctx.last.analytics,
recommendations: ctx.last.personalizedPath.nextRecommendations,
};
await sendNotifications('teacher_alert', teacherNotification, [
'teacher@school.edu',
'counselor@school.edu',
]);
return { teacherNotificationSent: true };
}
return { teacherNotificationSent: false };
},
// Update learning management system
async ctx => {
console.log('🖥️ Updating Learning Management System...');
// Simulate LMS integration
const lmsUpdate = {
studentId: ctx.last.student.id,
personalizedPath: ctx.last.personalizedPath,
analytics: ctx.last.analytics,
timestamp: new Date().toISOString(),
};
// In real implementation, integrate with Canvas, Blackboard, Google Classroom, etc.
console.log('📱 LMS updated with personalized learning path');
return { lmsUpdated: true };
},
])
.endIf()
// Step 6: Generate comprehensive progress report
.step('generate-report', async ctx => {
if (!ctx.payload.generateReport) {
return { reportGenerated: false };
}
console.log('📊 Generating comprehensive progress report...');
const report = {
studentProfile: {
id: ctx.last.student.id,
name: ctx.last.student.name,
grade: ctx.last.student.grade,
learningStyle: ctx.last.student.learningStyle,
specialNeeds: ctx.last.student.specialNeeds,
},
academicPerformance: {
currentGPA: ctx.last.student.currentGPA,
attendanceRate: ctx.last.student.attendanceRate,
subject: ctx.last.analytics.subject,
predictedGrade: ctx.last.analytics.predictedGrade,
riskLevel: ctx.last.analytics.riskLevel,
learningVelocity: ctx.last.analytics.learningVelocity,
engagementLevel: ctx.last.analytics.engagementLevel,
},
learningAnalysis: {
conceptMastery: ctx.last.analytics.conceptMastery,
strugglingAreas: ctx.last.analytics.strugglingAreas,
strengthAreas: ctx.last.analytics.strengthAreas,
interventionRecommendations:
ctx.last.analytics.interventionRecommendations,
},
personalizedPath: {
nextRecommendations: ctx.last.personalizedPath.nextRecommendations,
adaptiveStrategies: ctx.last.personalizedPath.adaptiveStrategies,
preferredResources: ctx.last.personalizedPath.preferredResources,
},
interventions: ctx.last.interventionAlerts,
actionItems: [
...ctx.last.interventionAlerts.map(alert => ({
type: 'intervention',
description: alert.description,
priority: alert.severity,
deadline: alert.deadline,
stakeholders: alert.stakeholders,
})),
...ctx.last.personalizedPath.nextRecommendations.map(rec => ({
type: 'learning',
description: rec.content,
priority: rec.priority,
estimatedTime: `${rec.estimatedTime} minutes`,
})),
],
generatedAt: new Date().toISOString(),
analysisWindow: ctx.payload.analysisWindow,
totalSubmissions: ctx.last.submissions.length,
};
return { report, reportGenerated: true };
})
// Step 7: Create summary and final results
.step('create-summary', async ctx => {
console.log('📋 Creating final analysis summary...');
const summary = {
studentId: ctx.last.student.id,
studentName: ctx.last.student.name,
analysisComplete: true,
riskLevel: ctx.last.analytics.riskLevel,
interventionsTriggered: ctx.last.interventionAlerts.length,
personalizedRecommendations:
ctx.last.personalizedPath.nextRecommendations.length,
notificationsSent: {
parents: ctx.last.parentNotificationSent || false,
teachers: ctx.last.teacherNotificationSent || false,
lmsUpdated: ctx.last.lmsUpdated || false,
},
reportGenerated: ctx.last.reportGenerated,
keyInsights: [
`Student predicted to earn ${ctx.last.analytics.predictedGrade} in ${ctx.last.analytics.subject}`,
`Learning velocity: ${ctx.last.analytics.learningVelocity > 0 ? 'improving' : 'declining'} (${ctx.last.analytics.learningVelocity.toFixed(1)}%)`,
`Engagement level: ${ctx.last.analytics.engagementLevel > 0.7 ? 'high' : ctx.last.analytics.engagementLevel > 0.4 ? 'moderate' : 'low'}`,
...(ctx.last.analytics.strugglingAreas.length > 0
? [
`Needs support in: ${ctx.last.analytics.strugglingAreas.join(', ')}`,
]
: []),
...(ctx.last.analytics.strengthAreas.length > 0
? [`Excelling in: ${ctx.last.analytics.strengthAreas.join(', ')}`]
: []),
],
nextSteps: ctx.last.personalizedPath.nextRecommendations
.slice(0, 3)
.map(rec => rec.content),
timestamp: new Date().toISOString(),
};
return { summary, success: true };
})
// Background action: Log analytics for institutional insights
.action('log-institutional-analytics', async ctx => {
console.log('📈 Logging institutional analytics...');
// Aggregate data for school-wide insights
const institutionalData = {
gradeLevel: ctx.last.student.grade,
subject: ctx.last.analytics.subject,
riskLevel: ctx.last.analytics.riskLevel,
learningStyle: ctx.last.student.learningStyle,
interventionsNeeded: ctx.last.interventionAlerts.length,
engagementLevel: ctx.last.analytics.engagementLevel,
timestamp: new Date().toISOString(),
};
// In real implementation, this would feed into school analytics dashboard
console.log('📊 Institutional analytics logged for trend analysis');
});
// Route to trigger educational progress tracking
app.post('/api/education/track-progress', async (req, res) => {
try {
console.log('🚀 Triggering educational progress tracking workflow...');
const validatedRequest = progressTrackingSchema.parse(req.body);
const runId = await cronflow.trigger(
'education-progress-tracking',
validatedRequest
);
res.json({
success: true,
message: 'Educational progress tracking initiated',
runId,
studentId: validatedRequest.studentId,
analysisWindow: validatedRequest.analysisWindow,
timestamp: new Date().toISOString(),
});
} catch (error) {
console.error('Progress tracking trigger error:', error);
res.status(400).json({
success: false,
error: (error as Error).message || 'Failed to trigger progress tracking',
});
}
});
// Route to submit new assignment score
app.post('/api/education/submit-assignment', async (req, res) => {
try {
console.log('📝 Processing new assignment submission...');
const submissionSchema = z.object({
studentId: z.string().min(1),
assignmentId: z.string().min(1),
score: z.number().min(0),
maxScore: z.number().positive(),
timeSpent: z.number().positive().optional(),
feedback: z.string().optional(),
autoAnalyze: z.boolean().default(true),
});
const submission = submissionSchema.parse(req.body);
if (submission.autoAnalyze) {
// Automatically trigger progress tracking for new submissions
const runId = await cronflow.trigger('education-progress-tracking', {
studentId: submission.studentId,
submissionData: {
assignmentId: submission.assignmentId,
score: submission.score,
maxScore: submission.maxScore,
timeSpent: submission.timeSpent,
feedback: submission.feedback,
},
notifyParents: submission.score / submission.maxScore < 0.7, // Notify parents for low scores
generateReport: true,
});
res.json({
success: true,
message: 'Assignment submitted and analysis triggered',
submissionId: `sub_${Date.now()}`,
score: `${submission.score}/${submission.maxScore}`,
percentage: ((submission.score / submission.maxScore) * 100).toFixed(1),
analysisRunId: runId,
autoAnalyzed: true,
});
} else {
res.json({
success: true,
message: 'Assignment submitted',
submissionId: `sub_${Date.now()}`,
score: `${submission.score}/${submission.maxScore}`,
percentage: ((submission.score / submission.maxScore) * 100).toFixed(1),
autoAnalyzed: false,
});
}
} catch (error) {
console.error('Assignment submission error:', error);
res.status(400).json({
success: false,
error: (error as Error).message || 'Failed to submit assignment',
});
}
});
// Route to get student analytics dashboard
app.get('/api/education/student/:studentId/dashboard', async (req, res) => {
try {
const { studentId } = req.params;
const days = parseInt(req.query.days as string) || 30;
console.log(`📊 Generating dashboard for student ${studentId}...`);
const student = await getStudentProfile(studentId);
const submissions = await getRecentSubmissions(studentId, days);
const analytics = await analyzeLearningPatterns(student, submissions);
const personalizedPath = await generatePersonalizedPath(student, analytics);
const interventionAlerts = await detectInterventionNeeds(
student,
analytics,
submissions
);
const dashboard = {
student: {
name: student.name,
grade: student.grade,
currentGPA: student.currentGPA,
attendanceRate: student.attendanceRate,
learningStyle: student.learningStyle,
},
performance: {
predictedGrade: analytics.predictedGrade,
riskLevel: analytics.riskLevel,
learningVelocity: analytics.learningVelocity,
engagementLevel: analytics.engagementLevel,
conceptMastery: analytics.conceptMastery,
},
insights: {
strugglingAreas: analytics.strugglingAreas,
strengthAreas: analytics.strengthAreas,
recommendedActions: analytics.interventionRecommendations,
},
personalizedPath: {
nextRecommendations: personalizedPath.nextRecommendations.slice(0, 5),
adaptiveStrategies: personalizedPath.adaptiveStrategies,
},
alerts: interventionAlerts,
recentActivity: {
submissionCount: submissions.length,
averageScore:
(submissions.reduce((sum, s) => sum + s.score / s.maxScore, 0) /
submissions.length) *
100,
lastSubmission: submissions[0]?.submittedAt,
analysisWindow: days,
},
timestamp: new Date().toISOString(),
};
res.json({
success: true,
dashboard,
});
} catch (error) {
console.error('Dashboard generation error:', error);
res.status(500).json({
success: false,
error: 'Failed to generate student dashboard',
});
}
});
// Route to get class/teacher insights
app.get('/api/education/class/:classId/insights', async (req, res) => {
try {
const { classId } = req.params;
console.log(`👩🏫 Generating class insights for class ${classId}...`);
// Mock class-wide analytics
const classInsights = {
classId,
totalStudents: 28,
performance: {
averageGPA: 3.1,
averageAttendance: 0.87,
riskDistribution: {
low: 12,
medium: 11,
high: 5,
},
gradeDistribution: {
A: 6,
B: 8,
C: 9,
D: 3,
F: 2,
},
},
topConcerns: [
'Algebra fundamentals - 8 students struggling',
'Attendance issues - 5 students below 80%',
'Low engagement - 6 students below 40%',
],
interventionsActive: [
'Math tutoring program - 5 students enrolled',
'Parent conferences scheduled - 8 families',
'Peer mentoring - 3 students participating',
],
trends: {
performanceChange: 2.3, // 2.3% improvement
engagementChange: -1.1, // 1.1% decrease
attendanceChange: 0.8, // 0.8% improvement
},
recommendations: [
'Consider implementing more interactive math activities',
'Address engagement decline with varied teaching methods',
'Continue attendance improvement initiatives',
],
generatedAt: new Date().toISOString(),
};
res.json({
success: true,
insights: classInsights,
});
} catch (error) {
res.status(500).json({
success: false,
error: 'Failed to generate class insights',
});
}
});
// Route to get intervention recommendations
app.get('/api/education/interventions/:studentId', async (req, res) => {
try {
const { studentId } = req.params;
const student = await getStudentProfile(studentId);
const submissions = await getRecentSubmissions(studentId, 30);
const analytics = await analyzeLearningPatterns(student, submissions);
const interventions = await detectInterventionNeeds(
student,
analytics,
submissions
);
res.json({
success: true,
studentId,
interventions,
totalAlerts: interventions.length,
highPriorityCount: interventions.filter(
i => i.severity === 'high' || i.severity === 'critical'
).length,
generatedAt: new Date().toISOString(),
});
} catch (error) {
res.status(500).json({
success: false,
error: 'Failed to get intervention recommendations',
});
}
});
app.listen(3000, async () => {
console.log('\n🎓 Educational Progress Tracking System Starting...');
console.log('⚡ Server running on port 3000');
console.log('📍 Available endpoints:');
console.log(
' POST /api/education/track-progress - Trigger comprehensive progress analysis'
);
console.log(
' POST /api/education/submit-assignment - Submit new assignment with auto-analysis'
);
console.log(
' GET /api/education/student/:id/dashboard - Get student analytics dashboard'
);
console.log(
' GET /api/education/class/:id/insights - Get class-wide insights'
);
console.log(
' GET /api/education/interventions/:id - Get intervention recommendations'
);
await cronflow.start();
console.log('🚀 Educational tracking workflows ready!');
console.log('🧠 AI-powered learning analytics active');
console.log('📊 Predictive intervention system online');
});