wulf-pulse/docs/SYNC_PROGRESS_TRACKING.md
root 6eee14f8af Add comprehensive admin features and multi-system integration
- Add admin dashboard with sync controls and data browser
- Implement RMM, Auvik, and Addigy organization mappings
- Add chunked ticket sync with progress tracking
- Implement entity sync service with rate limiting
- Add analytics engine and performance optimizer
- Create data browser for all PSA entities
- Add navigation components and UI improvements
- Implement background processing and sync services
- Add comprehensive documentation and migration scripts
- Update configuration items with multi-system support
- Enhance contact management and purchase history
- Add issue type assignment and LLM analyzer
- Improve error handling and logging utilities
2025-11-19 14:18:16 -05:00

8.8 KiB
Raw Blame History

Sync Progress Tracking Implementation

Overview

Implemented real-time progress tracking for entity sync operations with persistent state that allows users to navigate away and return to see accurate progress.

Problem Solved

  1. 100-Page Limit Removed - Previously, syncs were capped at 50,000 records (100 pages × 500 records/page)
  2. No Progress Visibility - Users couldn't see sync progress or know when operations would complete
  3. Lost Progress on Navigation - Navigating away from the sync page lost all progress information

Solution Architecture

Backend Components

1. SyncProgressTracker (lib/services/sync-progress-tracker.ts)

Global singleton service that tracks sync progress in memory.

Features:

  • Tracks multiple concurrent syncs
  • Stores progress state with phases (fetching, mapping, upserting, deleting)
  • Persists across API calls (in-memory during app lifetime)
  • Auto-cleanup of old sync records (keeps last 10 per entity)

Key Methods:

startSync(syncId, entityType)           // Initialize tracking
updateProgress(syncId, updates)         // Update progress
completeSync(syncId, totalRecords)      // Mark complete
failSync(syncId, error)                 // Mark failed
getProgress(syncId)                     // Get specific sync
getLatestSync(entityType)               // Get latest for entity

2. Entity Sync Service Updates (lib/services/entity-sync.ts)

Integrated progress tracking at key phases:

async syncEntity(entity, isIncremental, yearsBack, syncId?) {
  const trackingId = syncId || `${entity}_${Date.now()}`;
  
  syncProgressTracker.startSync(trackingId, entity);
  
  // Phase 1: Fetching
  syncProgressTracker.updateProgress(trackingId, { phase: 'fetching' });
  
  // Phase 2: Mapping
  syncProgressTracker.updateProgress(trackingId, { 
    totalRecords: count,
    phase: 'mapping' 
  });
  
  // Phase 3: Upserting
  syncProgressTracker.updateProgress(trackingId, { phase: 'upserting' });
  
  // Phase 4: Deleting (full sync only)
  syncProgressTracker.updateProgress(trackingId, { phase: 'deleting' });
  
  // Complete
  syncProgressTracker.completeSync(trackingId, totalRecords);
}

3. Progress API Endpoint (app/api/sync/progress/route.ts)

RESTful endpoint for polling progress:

# Get specific sync
GET /api/sync/progress?syncId=time_entries_1730000000

# Get latest sync for entity
GET /api/sync/progress?entityType=time_entries

# Get all active syncs
GET /api/sync/progress

Response:

{
  "progress": {
    "syncId": "time_entries_1730000000",
    "entityType": "time_entries",
    "status": "running",
    "currentPage": 0,
    "totalRecords": 75000,
    "startTime": 1730000000000,
    "phase": "upserting"
  }
}

Frontend Components

1. EntitySyncProgress Component (components/admin/EntitySyncProgress.tsx)

Reusable progress display following shadcn/ui best practices.

Features:

  • Animated progress bar (smooth transitions)
  • Phase indicators with icons
  • Real-time polling (every 2 seconds)
  • Persistent across navigation (polls by syncId or entityType)
  • Dark mode support
  • Accessibility (ARIA labels)
  • Auto-cleanup on completion/failure

Usage:

<EntitySyncProgress
  entityType="time_entries"
  syncId="time_entries_1730000000"
  onComplete={() => console.log('Sync done!')}
  onError={(error) => console.error(error)}
/>

Visual States:

  • Running - Blue badge, spinning loader, animated progress
  • Completed - Green badge, checkmark, success message
  • Failed - Red badge, X icon, error message

Progress Calculation:

fetching   25%
mapping    50%
upserting  75%
deleting   90%
completed  100%

2. SyncControlPanel Integration (components/admin/SyncControlPanel.tsx)

Integrated progress tracking for entity-specific syncs.

Auto-tracking:

  • Detects single-entity syncs
  • Generates unique syncId
  • Shows progress component
  • Auto-hides on completion

Multi-entity syncs:

  • Still supported
  • No individual progress (would need separate implementation)

shadcn/ui Best Practices Applied

1. Component Composition

<Card>
  <CardHeader>
    <CardTitle>Entity Sync</CardTitle>
    <CardDescription>Phase description</CardDescription>
  </CardHeader>
  <CardContent>
    <Progress value={animatedProgress} />
  </CardContent>
</Card>

2. Smooth Animations

// Gradual progress updates
const step = (targetProgress - animatedProgress) / 10;
const interval = setInterval(() => {
  setAnimatedProgress(prev => prev + step);
}, 50);

3. Dark Mode Support

className="dark:bg-gray-700 dark:border-gray-700"

4. Accessibility

<Progress 
  value={progress} 
  aria-label={`Sync progress: ${Math.round(progress)}%`}
/>

5. Loading States

{status === 'running' && (
  <Loader2 className="h-5 w-5 animate-spin text-blue-500" />
)}

6. Responsive Design

<div className="grid grid-cols-2 gap-4">
  {/* Stats */}
</div>

Usage Examples

1. Sync Time Entries with Progress

// From UI
1. Navigate to /admin/sync
2. Select "Time Entries" entity
3. Click "Sync Selected Entities"
4. Watch real-time progress
5. Navigate away (progress persists)
6. Return to see updated progress

2. Programmatic Sync with Tracking

import { syncProgressTracker } from '@/lib/services/sync-progress-tracker';

const syncId = `time_entries_${Date.now()}`;

// Start sync with tracking
await entitySyncService.syncEntity(
  EntityType.TIME_ENTRIES,
  false,
  1,
  syncId
);

// Poll progress
const progress = syncProgressTracker.getProgress(syncId);
console.log(progress.phase, progress.totalRecords);

3. Monitor from API

# Start sync
curl -X POST http://localhost:3000/api/sync/entity \
  -H "Content-Type: application/json" \
  -d '{"entities": ["time_entries"], "yearsBack": 1}'

# Poll progress
while true; do
  curl http://localhost:3000/api/sync/progress?entityType=time_entries
  sleep 2
done

Key Improvements

Before

  • 50,000 record limit
  • No progress visibility
  • Lost progress on navigation
  • No phase information
  • No error details

After

  • Unlimited records (removed page limit)
  • Real-time progress tracking
  • Persistent across navigation
  • Detailed phase indicators
  • Comprehensive error reporting
  • Animated progress bar
  • Dark mode support
  • Accessibility compliant

Performance Considerations

Polling Frequency

  • 2 seconds - Good balance between responsiveness and server load
  • Stops polling when sync completes/fails
  • Cleanup interval prevents memory leaks

Memory Management

  • Keeps last 10 syncs per entity type
  • Auto-cleanup on completion
  • In-memory storage (resets on app restart)

Future Enhancements

  • WebSocket support - Real-time push instead of polling
  • Persistent storage - Redis/database for cross-instance tracking
  • Page-level progress - Track individual API pages during fetch
  • Estimated time remaining - Calculate based on current rate

Testing

Manual Test

# 1. Start a time entries sync (1 year)
# 2. Observe progress phases:
#    - Fetching (0-25%)
#    - Mapping (25-50%)
#    - Upserting (50-75%)
#    - Deleting (75-90%)
#    - Completed (100%)
# 3. Navigate to another page
# 4. Return to sync page
# 5. Verify progress is still visible and accurate

API Test

# Terminal 1: Start sync
curl -X POST http://localhost:3000/api/sync/entity \
  -H "Content-Type: application/json" \
  -d '{"entities": ["time_entries"], "yearsBack": 1}'

# Terminal 2: Monitor progress
watch -n 2 'curl -s http://localhost:3000/api/sync/progress?entityType=time_entries | jq'

Files Modified

Backend

  • /lib/services/autotask-client.ts - Removed 100-page limit
  • /lib/services/entity-sync.ts - Added progress tracking
  • /lib/services/sync-progress-tracker.ts - New progress tracker service
  • /app/api/sync/progress/route.ts - New progress API endpoint

Frontend

  • /components/admin/EntitySyncProgress.tsx - New progress component
  • /components/admin/SyncControlPanel.tsx - Integrated progress tracking

Documentation

  • /docs/SYNC_PROGRESS_TRACKING.md - This file
  • /docs/TIME_ENTRY_FIELD_MAPPING.md - Field mapping analysis
  • /docs/TIME_ENTRIES_SORTING_FIX.md - Sorting implementation

Conclusion

The sync progress tracking system provides:

  1. Visibility - Users see exactly what's happening
  2. Persistence - Progress survives navigation
  3. Scalability - No record limits
  4. UX - Beautiful, accessible, responsive UI
  5. Reliability - Error handling and recovery

This implementation follows shadcn/ui best practices and provides a production-ready solution for long-running sync operations.