Skip to main content

Data Export

Sunschool provides a simple data export feature that allows parents to download complete learner information as JSON files. This supports data portability, backup, and offline analysis.

What is Data Export?

Data export generates a comprehensive JSON file containing all data for a specific learner:
  • Learner account information
  • Profile including grade level and settings
  • Complete lesson history with scores and timestamps
  • All achievements earned
  • Export metadata (date, exported by)

Access and Permissions

Data export is available to PARENT and ADMIN role users. Parents can export data for their own children; admins can export for any learner.
From server/routes.ts:1360-1408:
app.get("/api/export", hasRole(["PARENT", "ADMIN"]), asyncHandler(async (req: AuthRequest, res) => {
  if (!req.user) {
    return res.status(401).json({ error: "Unauthorized" });
  }

  if (!req.query.learnerId) {
    return res.status(400).json({ error: "learnerId is required" });
  }

  const learnerId = req.query.learnerId as string;

  // Verify parent has access to this learner
  if (req.user.role === "PARENT") {
    const children = await storage.getUsersByParentId(req.user.id);
    if (!children.some(child => child.id.toString() === learnerId.toString())) {
      return res.status(403).json({ error: "Forbidden" });
    }
  }

  // Get all the learner data
  const [learner, profile, lessons, achievements] = await Promise.all([
    storage.getUser(learnerId),
    storage.getLearnerProfile(learnerId),
    storage.getLessonHistory(learnerId, 1000), // Get a large number of lessons
    storage.getAchievements(learnerId)
  ]);

  if (!learner) {
    res.status(404).json({ error: "Learner not found" });
  }

  // Remove sensitive information
  const { password: _, ...learnerData } = learner;

  // Set filename for download
  const filename = `learner-data-${learnerId}-${new Date().toISOString().split('T')[0]}.json`;
  res.setHeader('Content-Disposition', `attachment; filename="${filename}"`);
  res.setHeader('Content-Type', 'application/json');

  // Return combined data
  res.json({
    learner: learnerData,
    profile,
    lessons,
    achievements,
    exportDate: new Date().toISOString(),
    exportedBy: req.user.id
  });
}));

How to Export Data

From the Parent Dashboard

From parent-dashboard.tsx:228-236:
<TouchableOpacity
  style={[styles.actionButton, styles.exportButton]}
  onPress={() => {
    // Open export endpoint in new window for download
    window.open(`/api/export?learnerId=${item.id}`, '_blank');
  }}
>
  <Download size={16} color={colors.onPrimary} />
  <Text style={styles.actionButtonText}>Export</Text>
</TouchableOpacity>

From the Reports Page

From reports-page.tsx:70-73:
const handleDownloadReport = () => {
  if (!selectedLearnerId) return;
  window.open(`/api/export?learnerId=${selectedLearnerId}`, '_blank');
};
And in the UI (lines 156-162):
<TouchableOpacity 
  style={styles.downloadButton}
  onPress={handleDownloadReport}
>
  <Download size={16} color={colors.onPrimary} />
  <Text style={styles.downloadButtonText}>Download Full Report</Text>
</TouchableOpacity>
1

Navigate to Learner

Go to the parent dashboard or learners page and locate the child whose data you want to export.
2

Click Export Button

Click the “Export” button (with download icon) on the learner’s card.
3

Download Begins

A JSON file downloads automatically with the naming format:
learner-data-{learnerId}-{YYYY-MM-DD}.json
Example: learner-data-123-2026-03-12.json

Export File Format

The exported JSON file has this structure:
{
  "learner": {
    "id": 123,
    "username": "child_username",
    "email": "child@example.com",
    "name": "Child Name",
    "role": "LEARNER",
    "parentId": 456,
    "createdAt": "2026-01-15T10:30:00.000Z",
    "updatedAt": "2026-03-12T14:22:00.000Z"
  },
  "profile": {
    "userId": 123,
    "gradeLevel": 5,
    "subjects": ["Math", "Reading", "Science"],
    "recommendedSubjects": ["History"],
    "strugglingAreas": [],
    "graph": {
      "nodes": [
        { "id": "math", "label": "Mathematics" },
        { "id": "algebra", "label": "Algebra" }
      ],
      "edges": [
        { "source": "math", "target": "algebra" }
      ]
    },
    "preferences": {},
    "createdAt": "2026-01-15T10:30:00.000Z",
    "updatedAt": "2026-03-10T09:15:00.000Z"
  },
  "lessons": [
    {
      "id": "lesson-789",
      "userId": 123,
      "subject": "Math",
      "topic": "Fractions",
      "gradeLevel": 5,
      "status": "DONE",
      "score": 85,
      "spec": {
        "title": "Introduction to Fractions",
        "sections": [...]
      },
      "createdAt": "2026-03-10T15:00:00.000Z",
      "completedAt": "2026-03-10T15:45:00.000Z"
    }
  ],
  "achievements": [
    {
      "id": "achievement-101",
      "userId": 123,
      "type": "first_lesson_complete",
      "payload": {
        "title": "First Lesson Complete!",
        "description": "You finished your first lesson"
      },
      "awardedAt": "2026-03-10T15:45:00.000Z"
    }
  ],
  "exportDate": "2026-03-12T16:30:00.000Z",
  "exportedBy": 456
}

What Data is Included

Learner Information

From the learner object:

Account Details

  • User ID
  • Username
  • Email address
  • Display name
  • Role (always LEARNER)
  • Parent ID

Timestamps

  • Account created date
  • Last updated date
Passwords are never included in exports for security.

Profile Data

From the profile object:
  • Grade Level - Current grade (0 for K, 1-12)
  • Subjects - Active learning subjects
  • Recommended Subjects - AI-suggested topics
  • Struggling Areas - Topics needing attention
  • Knowledge Graph - Visual representation of learned concepts
  • Preferences - Custom settings and configurations

Lesson History

From the lessons array (up to 1000 most recent):
storage.getLessonHistory(learnerId, 1000)
Each lesson includes:
  • Lesson ID and timestamps
  • Subject and topic
  • Grade level
  • Completion status (ACTIVE, DONE, ABANDONED)
  • Score (percentage)
  • Full lesson specification:
    • Title and description
    • Learning objectives
    • Content sections
    • Quiz questions and answers
    • Images and media
The export fetches the 1000 most recent lessons. For learners with more lessons, consider using the database sync feature for complete history.

Achievements

From the achievements array:
  • Achievement ID and type
  • Award date and time
  • Payload containing:
    • Title
    • Description
    • Additional metadata

Export Metadata

  • exportDate - When the export was generated (ISO 8601 timestamp)
  • exportedBy - User ID of the parent who requested the export

Using Exported Data

Backup and Archival

1

Regular Exports

Export data monthly or quarterly to maintain backups.
2

Organize Files

Store exports in a structured folder:
backups/
  2026-01/
    learner-data-123-2026-01-31.json
  2026-02/
    learner-data-123-2026-02-28.json
  2026-03/
    learner-data-123-2026-03-31.json
3

Version Control

The filename includes the date, making it easy to track when data was exported.

Analysis and Reporting

You can process the JSON data with:

Python Example

import json
import pandas as pd

# Load export file
with open('learner-data-123-2026-03-12.json', 'r') as f:
    data = json.load(f)

# Convert lessons to DataFrame
lessons_df = pd.DataFrame(data['lessons'])

# Analyze performance
avg_score = lessons_df['score'].mean()
subject_performance = lessons_df.groupby('subject')['score'].mean()

print(f"Average Score: {avg_score:.1f}%")
print("\nPerformance by Subject:")
print(subject_performance)

JavaScript Example

// Read export file (Node.js)
const fs = require('fs');
const data = JSON.parse(fs.readFileSync('learner-data-123-2026-03-12.json', 'utf8'));

// Calculate statistics
const lessons = data.lessons;
const completedLessons = lessons.filter(l => l.status === 'DONE');
const avgScore = completedLessons.reduce((sum, l) => sum + l.score, 0) / completedLessons.length;

console.log(`Completed Lessons: ${completedLessons.length}`);
console.log(`Average Score: ${avgScore.toFixed(1)}%`);

// Group by subject
const bySubject = completedLessons.reduce((acc, lesson) => {
  if (!acc[lesson.subject]) acc[lesson.subject] = [];
  acc[lesson.subject].push(lesson.score);
  return acc;
}, {});

for (const [subject, scores] of Object.entries(bySubject)) {
  const avg = scores.reduce((a, b) => a + b, 0) / scores.length;
  console.log(`${subject}: ${avg.toFixed(1)}% (${scores.length} lessons)`);
}

Data Portability

The JSON format is:
  • Universal - Works with any programming language
  • Human-readable - Can be opened in text editors
  • Machine-parseable - Easy to process programmatically
  • Structured - Clear organization of related data
You can:
  • Import into spreadsheet applications
  • Load into databases
  • Process with analytics tools
  • Share with schools or tutors
  • Archive for long-term storage

Privacy and Data Ownership

Important Privacy Information:
  1. You own this data - Sunschool provides exports to ensure you maintain ownership
  2. No passwords - Sensitive authentication data is never exported
  3. Secure storage - Store exported files securely as they contain personal information
  4. Parent control - Only parents can export their children’s data
  5. Complete data - You get all non-sensitive information

GDPR and Data Rights

Data export supports:
  • Right to access - View all data Sunschool has about a learner
  • Right to portability - Take data to another platform
  • Right to erasure - Export before account deletion
  • Transparency - See exactly what information exists

Comparison: Export vs. Database Sync

Best for:
  • Quick backups
  • One-time data retrieval
  • Sharing with third parties
  • Simple analysis
  • No infrastructure required
Characteristics:
  • Manual download
  • JSON file format
  • Point-in-time snapshot
  • Limited to 1000 lessons
  • Immediate availability

Limitations

Exports include up to 1000 most recent lessons. For complete history:
  • Use multiple exports over time
  • Or use database sync feature
  • Or contact support for custom exports
Exports are manual. To automate:
  • Use the database sync feature
  • Or build custom API integration
  • Or use a scheduled script to trigger exports
Large lesson histories can result in big files:
  • 1000 lessons ≈ 5-10 MB typically
  • Includes full lesson specs and quiz data
  • May take a moment to generate

Best Practices

Regular Exports

Export data monthly to maintain backup history and track long-term progress.

Secure Storage

Store exports in encrypted or password-protected locations. They contain personal information.

Meaningful Filenames

Keep the auto-generated filenames - they include date and learner ID for easy organization.

Verify Downloads

After exporting, open the file to verify it contains expected data before relying on it.

Troubleshooting

Check:
  1. You’re logged in as a PARENT or ADMIN
  2. You have permission to view this learner’s data
  3. The learner ID is valid
  4. Your browser allows pop-up windows (export opens in new tab)
The export is a JSON file:
  1. Open with a text editor (VS Code, Notepad++, etc.)
  2. Or use online JSON viewers
  3. Or process with programming languages
  4. Check file wasn’t corrupted during download
Verify:
  1. The learner actually has data (check dashboard)
  2. You exported the correct learner
  3. Data wasn’t recently added (try refreshing and re-exporting)
  4. No errors occurred during export (check browser console)
This means:
  1. You don’t have permission for this learner
  2. The learner isn’t one of your children (for parents)
  3. Session expired - try logging out and back in

Next Steps