Skip to content
ndk123-webPublic

About

EduMitra — A unified native mobile app for students to manage education, career planning, learning resources, and opportunities in one place.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Repository files navigation

🎓 EduMitra - Unified Education & Career Companion

🏆 Hackathon Project Overview

EduMitra is a comprehensive mobile-first education and career companion app built during our first hackathon. This application addresses the problem of students managing academics, exams, and careers across multiple disconnected apps by providing a unified, personalized platform with offline functionality and smart features.


📋 Problem Statement Addressed

Challenge: Students manage academics, exams, and careers across multiple apps, often struggling with connectivity and lack of personalization.

Solution: Build a mobile-first education & career companion app with offline functionality, personalized dashboards, and smart nudges to guide students in academics and careers.


✨ Key Features Implemented

🔐 Authentication System

  • Secure user registration and login
  • JWT-based authentication
  • Form validation with error handling
  • Professional UI with modern design
  • Password encryption using bcryptjs

📚 Course Management

  • Browse and enroll in courses
  • Course progress tracking
  • Personal course dashboard
  • Course recommendations powered by AI
  • Real-time enrollment status

🎯 Goal Setting & Tracking

  • Create and manage learning goals
  • Progress tracking with visual indicators
  • Milestone management
  • Priority-based goal organization
  • Goal statistics and analytics

📝 Smart Notes System

  • Course-specific note taking
  • Organized note management
  • Search and filter capabilities
  • Sync across devices

🎤 AI-Powered Mock Interviews

  • Role-specific interview questions
  • Real-time answer submission
  • AI evaluation using Ollama & Mistral
  • Detailed feedback with scores
  • Interview history and analytics
  • Performance tracking

📄 Resume Builder

  • AI-powered resume generation
  • Multiple professional templates (Modern, Classic, Creative, Minimal)
  • Personal information management
  • Education and experience tracking
  • PDF generation and download
  • Resume analytics

🔍 Skill Mapping & Career Guidance

  • Company-specific skill requirements
  • Skill gap analysis
  • Personalized learning paths
  • Career advancement recommendations
  • Progress tracking

👥 Community Features

  • Peer group creation and management
  • Group chat functionality
  • Study groups and collaboration
  • Mentorship connections

📊 Dashboard & Analytics

  • Personalized student dashboard
  • Parent/Guardian dashboard
  • Recent activity tracking
  • Progress visualization
  • Performance insights

� Academic Tools

  • Attendance tracking
  • Exam preparation resources
  • Academic performance monitoring
  • Score tracking

💼 Career Development

  • Internship opportunities
  • Scholarship information
  • Application tracking
  • Career guidance

�🏗️ Technical Architecture

Frontend - React Native with Expo

Technology Stack:
- React Native 0.79.5
- Expo Router for navigation
- TypeScript for type safety
- Zustand for state management
- React Hook Form for validation
- AsyncStorage for offline data
- Axios for API communication

Backend - Node.js Express Server

Technology Stack:
- Node.js with Express.js
- MongoDB with Mongoose ODM
- JWT authentication
- bcryptjs for password hashing
- CORS for cross-origin requests
- Ollama + Mistral for AI features
- Puppeteer for PDF generation

AI Integration

AI-Powered Features:
- Ollama with Mistral model for:
  ✓ Course recommendations
  ✓ Resume content generation
  ✓ Mock interview evaluation
  ✓ Skill gap analysis
  ✓ Career guidance

📱 Project Structure & Navigation

Frontend Structure

frontend/
├── app/                          # Expo Router app directory
│   ├── _layout.tsx              # Root layout with navigation setup
│   ├── index.tsx                # Entry point - redirects to auth
│   ├── (auth)/                  # Authentication group
│   │   ├── _layout.tsx          # Auth layout (stack navigation)
│   │   ├── signin.tsx           # Sign In screen
│   │   └── signup.tsx           # Sign Up screen
│   ├── (tabs)/                  # Main app tabs (after authentication)
│   │   ├── _layout.tsx          # Tab navigation layout
│   │   ├── index.tsx            # Home dashboard
│   │   ├── ndk.tsx             # Learning/courses tab
│   │   └── explore.tsx          # Discovery tab
│   ├── (main)/                  # Feature screens (30+ screens)
│   │   ├── dashboard.tsx        # Personal dashboard
│   │   ├── courses.tsx          # Course management
│   │   ├── goals.tsx            # Goal tracking
│   │   ├── notes.tsx            # Note taking
│   │   ├── mock-tests.tsx       # Interview practice
│   │   ├── resume.tsx           # Resume builder
│   │   ├── skills.tsx           # Skill mapping
│   │   ├── peer-groups.tsx      # Community
│   │   ├── academics.tsx        # Academic tracking
│   │   ├── exam-prep.tsx        # Exam preparation
│   │   ├── internships.tsx      # Internship portal
│   │   ├── scholarships.tsx     # Scholarship info
│   │   └── parent-dashboard.tsx # Parent view
│   └── +not-found.tsx           # 404 screen
├── components/
│   ├── common/                  # Reusable UI components
│   │   ├── Input.tsx            # Custom input with validation
│   │   ├── Button.tsx           # Multi-variant button component
│   │   ├── Logo.tsx             # App logo component
│   │   └── RecentActivities.tsx # Activity tracking
│   ├── navigation/              # Navigation components
│   │   └── Sidebar.tsx          # App sidebar
│   ├── ui/                      # UI elements
│   │   └── IconSymbol.tsx       # Icon components
│   └── auth/                    # Auth-specific components
├── api/                         # API integration files
│   ├── SignInApi.ts             # Authentication APIs
│   ├── GetCoursesApi.ts         # Course APIs
│   ├── GoalsApi.ts              # Goals APIs
│   ├── ResumeApi.ts             # Resume APIs
│   ├── MockInterviewApi.ts      # Interview APIs
│   └── SkillMappingApi.ts       # Skill mapping APIs
├── store/                       # State management
│   ├── authStore.ts             # Authentication state
│   ├── coursesStore.ts          # Courses state
│   ├── goalsStore.ts            # Goals state
│   └── resumeStore.ts           # Resume state
├── styles/
│   ├── theme.ts                 # Design system & colors
│   ├── globalStyles.ts          # Global styles & auth styles
│   └── responsive.ts            # Responsive design utilities
└── constants/
    └── Colors.ts                # Theme colors

Backend Structure

backend/auth-service/
├── controllers/                 # Business logic
│   ├── authController.js        # Authentication
│   ├── courseController.js      # Course management
│   ├── goalsController.js       # Goal tracking
│   ├── notesController.js       # Notes system
│   ├── resumeController.js      # Resume builder
│   ├── mockInterviewController.js # Interview system
│   ├── skillMappingController.js # Skill mapping
│   ├── groupController.js       # Community features
│   ├── recommendationsController.js # AI recommendations
│   ├── recentActivityController.js # Activity tracking
│   └── parentDashboardController.js # Parent features
├── models/                      # Database schemas
│   ├── User.models.js           # User data
│   ├── Course.models.js         # Course information
│   ├── Goals.models.js          # Learning goals
│   ├── Notes.models.js          # User notes
│   ├── Resume.models.js         # Resume data
│   ├── MockInterview.models.js  # Interview templates
│   ├── HistoryUserMockInterview.models.js # Interview history
│   ├── SkillMapping.models.js   # Skill requirements
│   ├── Group.models.js          # Study groups
│   ├── Enrollment.models.js     # Course enrollments
│   └── RecentActivity.models.js # Activity logs
├── routes/                      # API endpoints
│   ├── authRoutes.js            # Authentication routes
│   ├── courseRoutes.js          # Course routes
│   ├── goalsRoutes.js           # Goals routes
│   ├── notesRoutes.js           # Notes routes
│   ├── resumeRoutes.js          # Resume routes
│   ├── mockInterviewRoutes.js   # Interview routes
│   └── skillMappingRoutes.js    # Skill mapping routes
├── middleware/
│   └── authMiddleware.js        # JWT verification
├── utils/
│   └── resumeUtils.js           # Resume generation utilities
├── config/
│   └── db.js                    # Database connection
└── scripts/                     # Database setup scripts
    ├── importCourses.js         # Course data import
    └── populateInterviews.js    # Interview templates

� Implemented API Endpoints

Authentication APIs

POST /api/v1/auth/register    # User registration
POST /api/v1/auth/login       # User login
GET  /api/v1/auth/profile     # Get user profile

Course Management APIs

GET  /api/v1/courses/get-courses              # Get all courses
GET  /api/v1/courses/get-enrollments-courses  # Get user enrollments
POST /api/v1/courses/enroll-course            # Enroll in course

Goals Management APIs

POST /api/v1/goals/           # Create new goal
GET  /api/v1/goals/           # Get user goals
GET  /api/v1/goals/stats      # Get goal statistics
PUT  /api/v1/goals/:goalId    # Update goal
PATCH /api/v1/goals/:goalId/progress # Update progress
DELETE /api/v1/goals/:goalId  # Delete goal

Resume Builder APIs

POST /api/v1/resume/generate         # Generate AI-powered resume
GET  /api/v1/resume/list            # Get user resumes
GET  /api/v1/resume/:resumeId       # Get specific resume
GET  /api/v1/resume/:resumeId/download # Download PDF
PUT  /api/v1/resume/:resumeId       # Update resume
DELETE /api/v1/resume/:resumeId     # Delete resume

Mock Interview APIs

GET  /api/v1/mock-interviews/               # Get available interviews
POST /api/v1/mock-interviews/start/:interviewId # Start interview
POST /api/v1/mock-interviews/answer/:interviewId # Submit answer
POST /api/v1/mock-interviews/complete/:interviewId # Complete interview
GET  /api/v1/mock-interviews/history        # Get interview history
GET  /api/v1/mock-interviews/result/:historyId # Get result details

Skill Mapping APIs

GET  /api/v1/skill-mapping/companies        # Get companies
GET  /api/v1/skill-mapping/roles/:company   # Get roles by company
GET  /api/v1/skill-mapping/mappings         # Get skill mappings
POST /api/v1/skill-mapping/recommendations  # Get AI recommendations
PUT  /api/v1/skill-mapping/user/skills      # Update user skills

Notes Management APIs

GET  /api/v1/notes/get-notes    # Get course notes
POST /api/v1/notes/add-notes    # Add new note
PUT  /api/v1/notes/update-note  # Update existing note
DELETE /api/v1/notes/delete-note # Delete note

Community & Groups APIs

GET  /api/v1/groups/get-groups     # Get available groups
GET  /api/v1/groups/joined-groups  # Get user's groups
POST /api/v1/groups/create-group   # Create new group
POST /api/v1/groups/join-group     # Join existing group
POST /api/v1/groups/send-chat      # Send group message
GET  /api/v1/groups/get-chat       # Get group chats

Recommendations & Analytics APIs

POST /api/v1/recommendations/generate        # Get AI course recommendations
GET  /api/v1/recent-activities/user-activities # Get user activities
GET  /api/v1/parent-dashboard/overview       # Parent dashboard data

🛠️ Database Schema Design

User Management

  • User.models.js - User authentication and profile data
  • Parents.models.js - Parent/guardian access control

Learning Management

  • Course.models.js - Course catalog and metadata
  • Enrollment.models.js - User course enrollments
  • Goals.models.js - Learning goals and progress tracking
  • Notes.models.js - Course-specific user notes

Career Development

  • Resume.models.js - Resume data and versions
  • MockInterview.models.js - Interview question templates
  • HistoryUserMockInterview.models.js - Interview attempt history
  • SkillMapping.models.js - Company skill requirements

Community & Collaboration

  • Group.models.js - Study group information
  • GroupChats.models.js - Group messaging system
  • Members.models.js - Group membership data

Analytics & Tracking

  • RecentActivity.models.js - User activity logging
  • Quizzes.models.js - Assessment and quiz data

🎨 Design System & UI Components

Theme Structure (styles/theme.ts)

theme = {
  colors: {
    primary: '#4F46E5',        // Indigo for buttons/links
    background: '#FFFFFF',     // White background
    surface: '#F9FAFB',       // Light gray for inputs
    text: '#111827',          // Dark text
    error: '#EF4444',         // Red for errors
  },
  spacing: {
    xs: 4, sm: 8, md: 16, lg: 24, xl: 32
  },
  borderRadius: {
    sm: 4, md: 8, lg: 12, xl: 16
  },
  shadows: {
    sm: { shadowOffset: { width: 0, height: 1 }, shadowOpacity: 0.1 },
    md: { shadowOffset: { width: 0, height: 4 }, shadowOpacity: 0.15 }
  }
}

Reusable Components

  • Button Component - Multiple variants (primary, secondary, outline, ghost)
  • Input Component - With validation, icons, and error states
  • Logo Component - Scalable app branding
  • Sidebar Component - Navigation drawer
  • RecentActivities Component - Activity feed display

Responsive Design

  • responsive.ts - Screen size utilities and responsive helpers
  • Grid layouts that adapt to different screen sizes
  • Scalable fonts and spacing for various devices

🤖 AI Integration Details

Ollama + Mistral Setup

// AI Model Configuration
Model: Mistral (7B parameters)
Host: http://localhost:11434
Features:
- Course recommendations based on user goals
- Resume content generation and enhancement
- Mock interview evaluation with detailed feedback
- Skill gap analysis and learning path suggestions
- Career guidance and advice generation

AI-Powered Features Implementation

1. Smart Course Recommendations

// Analyzes user goals, progress, and preferences
// Returns personalized course suggestions with reasoning
const recommendations = await generateRecommendations({
  userGoals: userGoalData,
  availableCourses: courseDatabase,
  userPreferences: userProfile
});

2. Resume Content Enhancement

// Transforms basic user input into professional resume content
const enhancedResume = await generateResumeContent({
  personalInfo: userData,
  experience: workHistory,
  education: educationData,
  template: selectedTemplate
});

3. Mock Interview Evaluation

// Provides detailed feedback on interview performance
const evaluation = await evaluateInterview({
  role: targetRole,
  questions: interviewQuestions,
  answers: userAnswers
});
// Returns: technical_score, communication_score, feedback, strengths, weaknesses

4. Skill Gap Analysis

// Analyzes skill gaps for target roles
const skillAnalysis = await analyzeSkillGap({
  targetRole: desiredPosition,
  company: targetCompany,
  currentSkills: userSkills,
  requiredSkills: jobRequirements
});

� Offline/Online Sync Architecture

📱 Sync Strategy Overview

Our app implements a sophisticated offline-first architecture with intelligent sync mechanisms using AsyncStorage and Zustand state management. Here's how we handle data persistence and synchronization:

🏗️ Core Sync Logic

1. Three-Layer Data Management

📱 Local Storage (AsyncStorage) 
    ↕️ Bidirectional Sync
🧠 App State (Zustand Stores)
    ↕️ API Calls
☁️ Backend Server (MongoDB)

2. Offline-First Approach

  • All data is stored locally first using AsyncStorage
  • User actions work immediately even without internet
  • Background sync happens when network is available
  • Conflict resolution prioritizes user's local changes

📊 Zustand Stores & Sync Variables

1. Authentication Store (authStore.ts)

type AuthState = {
  // Core auth data (persisted)
  isAuth: boolean;
  userData: UserData | null;
  token: string | null;
  isLoading: boolean;

  // Sync methods
  login: (user: UserData, token: string) => void;
  logout: () => void; // Clears all stores
  updateUser: (patch: Partial<UserData>) => void;
}

// Persisted to AsyncStorage: isAuth, userData, token

2. Courses Store (coursesStore.ts)

type CoursesState = {
  // Core data (persisted)
  courses: Course[];
  enrolledCourses: string[];
  
  // Offline sync variables
  pendingEnrollments: PendingEnrollment[]; // 🔄 Enrollments waiting for sync
  isSyncing: boolean;                      // 📡 Currently syncing status
  isEnrolling: boolean;                    // ⏳ Currently enrolling status
  isOnline: boolean;                       // 📶 Network connectivity status
  lastSyncedAt: string | null;            // 🕐 Last successful sync timestamp

  // Sync methods
  fetchAndSync: () => Promise<void>;       // 🔄 Main sync function
  enrollCourse: () => Promise<{success, message}>; // 📝 Offline-capable enrollment
  syncPendingEnrollments: () => Promise<void>;     // 🚀 Sync pending items
  setOnlineStatus: (isOnline: boolean) => void;    // 📶 Network status updates
}

// Sync Logic Flow:
// 1. User enrolls → Add to pendingEnrollments if offline
// 2. UI updates immediately (optimistic updates)
// 3. When online → syncPendingEnrollments() syncs to server
// 4. Success → Move to enrolledCourses, remove from pending

3. Course Details Store (courseDetailStore.ts)

type CourseDetailState = {
  // Core data (persisted)
  notesByCourse: Record<string, Note[]>;
  quizzesByCourse: Record<string, Quiz[]>;
  progressByCourse: Record<string, CourseProgress>;
  
  // Offline sync variables
  pendingNotes: PendingNote[];             // 📝 Notes waiting for server sync
  pendingSync: {                           // 🔄 Generic pending sync data
    notes: Record<string, Note[]>;
    progress: Record<string, CourseProgress>;
  };
  isOnline: boolean;                       // 📶 Network status
  isSyncingNotes: boolean;                 // 📤 Notes sync in progress

  // Sync methods
  saveNoteToServer: () => Promise<{success, message}>; // 💾 Offline-capable note saving
  addPendingNote: (courseId, content) => void;         // 📝 Add to offline queue
  syncPendingNotes: () => Promise<void>;               // 🚀 Sync all pending notes
  addToPendingSync: () => void;                        // 🔄 Generic sync queue
}

// Notes Sync Logic:
// 1. User saves note → Try server first if online
// 2. If offline/error → Add to pendingNotes
// 3. UI shows note immediately with "syncing" indicator
// 4. When online → syncPendingNotes() uploads all pending
// 5. Success → Remove from pendingNotes

4. Goals Store (goalsStore.ts)

type GoalsState = {
  // Core data (persisted)
  goals: Goal[];
  goalStats: GoalStats | null;
  
  // UI state (persisted)
  statusFilter: string | null;            // 🔍 Filter persistence
  priorityFilter: string | null;          // 🔍 Filter persistence
  
  // Loading states
  isLoading: boolean;
  error: string | null;

  // Computed getters (no network dependency)
  getFilteredGoals: () => Goal[];         // 📊 Local filtering
  getGoalsByStatus: (status) => Goal[];   // 📊 Local queries
  getOverdueGoals: () => Goal[];          // 📊 Local calculations
}

// Goals work offline with local state management
// Server sync happens via API calls, local state updates immediately

5. Resume Store (resumeStore.ts)

type ResumeState = {
  // Complete resume data (persisted)
  resumeData: ResumeData;                 // 📄 All resume information
  isGenerating: boolean;                  // 🤖 AI generation status
  lastGenerated: string;                  // 🕐 Last generation timestamp

  // Rich data structures
  education: Education[];                 // 🎓 Education history
  experience: Experience[];               // 💼 Work experience
  projects: Project[];                    // 🚀 Personal projects
  achievements: Achievement[];            // 🏆 Accomplishments

  // Local operations (work offline)
  getFormProgress: () => number;          // 📊 Completion percentage
  isFormValid: () => boolean;             // ✅ Validation check
}

// Resume builder works completely offline
// Only PDF generation requires server (with local fallback)

🔄 Sync Mechanisms Explained

1. Optimistic Updates

// Example: Course Enrollment
const enrollCourse = async (courseId: string) => {
  // 1. Update UI immediately (optimistic)
  const updatedCourses = courses.map(course => 
    course.id === courseId ? { ...course, enrolled: true } : course
  );
  setCourses(updatedCourses);

  // 2. Try server sync
  if (isOnline && token) {
    try {
      await EnrollCourseApi(token, courseId);
      // Success - already updated UI
    } catch (error) {
      // Error - add to pending queue
      addPendingEnrollment(courseId);
    }
  } else {
    // Offline - add to pending queue
    addPendingEnrollment(courseId);
  }
};

2. Pending Queue System

// Pending items structure
type PendingEnrollment = {
  courseId: string;
  timestamp: string;        // For conflict resolution
};

type PendingNote = {
  courseId: string;
  content: string;
  timestamp: string;
};

// Auto-sync when network returns
const setOnlineStatus = (isOnline: boolean) => {
  setIsOnline(isOnline);
  
  if (isOnline && token) {
    // Auto-trigger sync for all pending items
    syncPendingEnrollments(token);
    syncPendingNotes(token);
  }
};

3. Data Persistence Strategy

// What gets persisted to AsyncStorage:
const persistConfig = {
  name: 'store-name',
  storage: createJSONStorage(() => AsyncStorage),
  partialize: (state) => ({
    // Core data - always persisted
    courses: state.courses,
    enrolledCourses: state.enrolledCourses,
    goals: state.goals,
    
    // Sync state - persisted for offline resilience
    pendingEnrollments: state.pendingEnrollments,
    pendingNotes: state.pendingNotes,
    lastSyncedAt: state.lastSyncedAt,
    
    // UI state - persisted for UX
    statusFilter: state.statusFilter,
    priorityFilter: state.priorityFilter,
  }),
};

📡 Network Status Monitoring & Polling

1. Smart Network Detection System

// Multi-layer network checking approach
const checkNetworkStatus = async () => {
  // Layer 1: Browser network status
  const browserOnline = navigator.onLine ?? true;
  if (!browserOnline) {
    console.log('Browser says offline');
    setOnlineStatus(false);
    return;
  }

  // Layer 2: Backend API verification
  try {
    const controller = new AbortController();
    const timeoutId = setTimeout(() => controller.abort(), 3000); // 3s timeout
    
    const apiResponse = await fetch('http://192.168.0.102:5000/', { 
      method: 'GET', 
      headers: { 'Content-Type': 'application/json' },
      signal: controller.signal
    });
    
    clearTimeout(timeoutId);
    
    if (apiResponse?.status === 200 || apiResponse?.status === 201) {
      console.log('Backend API check: Online ✅');
      setOnlineStatus(true);
    } else {
      console.log('Backend API check: Failed ❌');
      setOnlineStatus(false);
    }
  } catch (error) {
    // Network error or timeout - consider offline
    if (error.name === 'AbortError') {
      console.warn('Backend API check: Timeout ⏰');
    } else {
      console.warn('Backend API check: Network error 🔌');
    }
    setOnlineStatus(false);
  }
};

2. Automatic Polling System

useEffect(() => {
  // Initial network status check
  checkNetworkStatus();
  
  // Browser event listeners for immediate response
  const handleOnline = () => {
    console.log('🔔 Browser detected online - rechecking backend');
    checkNetworkStatus(); // Verify with backend
  };
  
  const handleOffline = () => {
    console.log('🔔 Browser detected offline');
    setOnlineStatus(false);
  };
  
  // Add event listeners
  window.addEventListener?.('online', handleOnline);
  window.addEventListener?.('offline', handleOffline);
  
  // 🔄 Periodic polling every 30 seconds
  const intervalId = setInterval(() => {
    console.log('⏰ 30-second network check triggered');
    checkNetworkStatus();
  }, 30000);
  
  // Cleanup on component unmount
  return () => {
    window.removeEventListener?.('online', handleOnline);
    window.removeEventListener?.('offline', handleOffline);
    clearInterval(intervalId);
  };
}, [setOnlineStatus]);

3. Intelligent Sync Triggers

Immediate Triggers:

// 1. Browser online/offline events (instant response)
window.addEventListener('online', () => {
  console.log('📶 Network restored - immediate sync check');
  checkNetworkStatus();
});

// 2. App foreground detection
useEffect(() => {
  const subscription = AppState.addEventListener('change', (nextAppState) => {
    if (nextAppState === 'active' && isOnline && token) {
      console.log('📱 App foregrounded - checking for sync');
      const lastSync = coursesStore.lastSyncedAt;
      const timeSinceSync = Date.now() - new Date(lastSync).getTime();
      
      // Sync if more than 5 minutes since last sync
      if (timeSinceSync > 5 * 60 * 1000) {
        console.log('🔄 Auto-syncing after 5+ minutes');
        coursesStore.fetchAndSync(token);
      }
    }
  });
  
  return subscription.remove;
}, []);

Scheduled Triggers:

// 30-second polling for network status
setInterval(checkNetworkStatus, 30000);

// Smart sync scheduling based on app usage
useEffect(() => {
  if (isOnline && token) {
    // Schedule background sync every 2 minutes when app is active
    const syncInterval = setInterval(() => {
      console.log('📡 Scheduled background sync');
      
      // Only sync if there are pending changes
      const pendingItems = getPendingItemsCount();
      if (pendingItems > 0) {
        console.log(`🔄 Syncing ${pendingItems} pending items`);
        syncAllPendingData(token);
      }
    }, 2 * 60 * 1000); // 2 minutes
    
    return () => clearInterval(syncInterval);
  }
}, [isOnline, token]);

4. Adaptive Polling Frequency

// Dynamic polling based on network reliability
let pollInterval = 30000; // Default 30 seconds
let consecutiveFailures = 0;

const adaptivePoll = () => {
  checkNetworkStatus()
    .then((isOnline) => {
      if (isOnline) {
        // Network is stable - reset to normal polling
        consecutiveFailures = 0;
        pollInterval = 30000; // 30 seconds
        console.log('📶 Network stable - normal polling (30s)');
      } else {
        // Network issues - increase polling frequency temporarily
        consecutiveFailures++;
        if (consecutiveFailures > 3) {
          pollInterval = 60000; // 1 minute if persistently offline
          console.log('⚠️ Persistent offline - reduced polling (60s)');
        } else {
          pollInterval = 15000; // 15 seconds for quick recovery
          console.log('🔄 Network issues - fast polling (15s)');
        }
      }
    });
};

// Use adaptive polling
setInterval(adaptivePoll, pollInterval);

5. Battery & Performance Optimization

// Optimize polling based on device state
const getOptimalPollInterval = () => {
  // Check if app is in background (React Native)
  if (AppState.currentState === 'background') {
    return 5 * 60 * 1000; // 5 minutes in background
  }
  
  // Check battery level (if available)
  if (getBatteryLevel && getBatteryLevel() < 0.2) {
    return 2 * 60 * 1000; // 2 minutes on low battery
  }
  
  // Check if device is charging
  if (getBatteryCharging && getBatteryCharging()) {
    return 15 * 1000; // 15 seconds when charging
  }
  
  return 30 * 1000; // Default 30 seconds
};

// Dynamic interval adjustment
let currentInterval = getOptimalPollInterval();
setInterval(() => {
  const newInterval = getOptimalPollInterval();
  if (newInterval !== currentInterval) {
    console.log(`🔄 Adjusting poll interval: ${currentInterval}ms → ${newInterval}ms`);
    currentInterval = newInterval;
    // Restart interval with new timing
  }
}, currentInterval);

6. Network Quality Assessment

// Measure network quality for better sync decisions
const assessNetworkQuality = async () => {
  const startTime = Date.now();
  
  try {
    // Small test request to measure latency
    await fetch('http://192.168.0.102:5000/api/v1/health', {
      method: 'HEAD',
      timeout: 2000
    });
    
    const latency = Date.now() - startTime;
    
    if (latency < 500) {
      console.log('🚀 Excellent network (< 500ms)');
      return 'excellent';
    } else if (latency < 1500) {
      console.log('⚡ Good network (500-1500ms)');
      return 'good';
    } else {
      console.log('🐌 Slow network (> 1500ms)');
      return 'slow';
    }
  } catch (error) {
    console.log('❌ Poor/No network');
    return 'poor';
  }
};

// Adjust sync behavior based on network quality
const smartSync = async () => {
  const quality = await assessNetworkQuality();
  
  switch (quality) {
    case 'excellent':
      // Sync everything immediately
      await syncAllData();
      break;
    case 'good':
      // Prioritize important data
      await syncPriorityData();
      setTimeout(syncRemainingData, 1000);
      break;
    case 'slow':
      // Sync only critical data
      await syncCriticalData();
      break;
    case 'poor':
      // Queue for later
      console.log('📦 Queuing data for better network');
      break;
  }
};

7. User Feedback & Indicators

// Visual network status indicators
const NetworkStatusIndicator = () => {
  const isOnline = useCoursesStore(s => s.isOnline);
  const isSyncing = useCoursesStore(s => s.isSyncing);
  const lastSyncedAt = useCoursesStore(s => s.lastSyncedAt);
  
  return (
    <View style={styles.networkIndicator}>
      {isSyncing ? (
        <Text style={[styles.statusText, { color: colors.warning }]}>
          🔄 Syncing...
        </Text>
      ) : isOnline ? (
        <Text style={[styles.statusText, { color: colors.success }]}>
          ✅ Online {lastSyncedAt && `• Last sync: ${formatTime(lastSyncedAt)}`}
        </Text>
      ) : (
        <Text style={[styles.statusText, { color: colors.error }]}>
          ⚠️ Offline • Changes saved locally
        </Text>
      )}
    </View>
  );
};

8. Sync Success Metrics

// Track sync performance for optimization
const syncMetrics = {
  totalSyncAttempts: 0,
  successfulSyncs: 0,
  failedSyncs: 0,
  averageLatency: 0,
  lastSyncTime: null,
  
  recordSyncAttempt: (success: boolean, latency: number) => {
    syncMetrics.totalSyncAttempts++;
    if (success) {
      syncMetrics.successfulSyncs++;
      syncMetrics.lastSyncTime = Date.now();
    } else {
      syncMetrics.failedSyncs++;
    }
    
    // Update average latency
    syncMetrics.averageLatency = 
      (syncMetrics.averageLatency * (syncMetrics.totalSyncAttempts - 1) + latency) / 
      syncMetrics.totalSyncAttempts;
  },
  
  getSyncHealth: () => {
    const successRate = (syncMetrics.successfulSyncs / syncMetrics.totalSyncAttempts) * 100;
    console.log(`📊 Sync Health: ${successRate.toFixed(1)}% success rate, ${syncMetrics.averageLatency.toFixed(0)}ms avg latency`);
    return { successRate, averageLatency: syncMetrics.averageLatency };
  }
};

This sophisticated polling and sync system ensures reliable offline/online detection with:

✅ 30-second automatic polling for network status
✅ Immediate browser event detection for instant response
✅ Backend API verification beyond just browser status
✅ Adaptive polling frequency based on network reliability
✅ Battery and performance optimization
✅ Network quality assessment for smart sync decisions
✅ Visual feedback to users about connection status
✅ Comprehensive error handling with fallback strategies


📡 Network State Management

1. Connection Detection

// Each store tracks online status
isOnline: boolean; // 📶 Current network state

// Auto-sync triggers
const setOnlineStatus = (isOnline: boolean) => {
  set({ isOnline });
  
  if (isOnline) {
    // Coming online - trigger sync
    const { pendingItems } = get();
    if (pendingItems.length > 0) {
      console.log('📶 Network restored - syncing pending items');
      syncPendingItems();
    }
  }
};

2. Sync Indicators

// Loading states for user feedback
isSyncing: boolean;         // 🔄 General sync in progress
isSyncingNotes: boolean;    // 📝 Notes sync in progress
isEnrolling: boolean;       // 📚 Enrollment in progress

// UI shows appropriate indicators:
// - "Syncing..." badge
// - Progress spinners
// - "Saved offline" messages

🚀 Auto-Sync Triggers

1. App Launch Sync

// On app startup
useEffect(() => {
  if (token) {
    // Sync all stores
    coursesStore.fetchAndSync(token);
    courseDetailStore.syncPendingNotes(token);
    // ... other stores
  }
}, [token]);

2. Network Status Change

// Network state listener
useEffect(() => {
  const networkListener = NetInfo.addEventListener(state => {
    const isOnline = state.isConnected && state.isInternetReachable;
    
    // Update all stores
    coursesStore.setOnlineStatus(isOnline);
    courseDetailStore.setOnlineStatus(isOnline);
  });
  
  return networkListener;
}, []);

3. Foreground/Background Sync

// App state change listener
useEffect(() => {
  const subscription = AppState.addEventListener('change', nextAppState => {
    if (nextAppState === 'active' && isOnline && token) {
      // App came to foreground - sync if needed
      const lastSync = coursesStore.lastSyncedAt;
      const timeSinceSync = Date.now() - new Date(lastSync).getTime();
      
      if (timeSinceSync > 5 * 60 * 1000) { // 5 minutes
        console.log('🔄 App foregrounded - syncing data');
        coursesStore.fetchAndSync(token);
      }
    }
  });
  
  return subscription.remove;
}, []);

🎯 Conflict Resolution

1. Timestamp-Based Resolution

// Resolve conflicts using timestamps
const resolveConflict = (localItem, serverItem) => {
  const localTime = new Date(localItem.updatedAt);
  const serverTime = new Date(serverItem.updatedAt);
  
  // Prioritize most recent change
  return localTime > serverTime ? localItem : serverItem;
};

2. User-Preference Priority

// For critical actions, always prioritize user's local changes
const mergeCourseProgress = (local, server) => {
  return {
    ...server,
    completedVideos: [
      ...new Set([...server.completedVideos, ...local.completedVideos])
    ],
    progressPercentage: Math.max(local.progressPercentage, server.progressPercentage),
    lastWatchedVideo: Math.max(local.lastWatchedVideo, server.lastWatchedVideo),
  };
};

This offline/online sync architecture ensures that users can always use the app regardless of network connectivity, with seamless data synchronization when the connection is restored.


About

EduMitra — A unified native mobile app for students to manage education, career planning, learning resources, and opportunities in one place.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages