Skip to the content.

Gym Check-In Reports & Analytics

Overview

The gym check-in reporting system provides detailed attendance analytics and historical tracking. The system archives older check-in data to maintain performance while keeping complete historical records accessible.

Key Benefits:

How the System Works

Two Types of Data Storage:

  1. Recent Check-Ins (Visible to Athletes)
    • Each athlete can see their last 8 check-ins on their check-in screen
    • Additionally, all check-ins from the last 60 days are kept as detailed records
    • Used for recent activity and athlete tracking
    • Faster queries for current statistics
  2. Archived Summaries (Older than 60 days AND beyond user’s 8 most recent)
    • Daily summary records for historical periods
    • Preserves statistics without storing every individual check-in
    • Saves storage space while keeping historical data
    • Combined with recent data for complete totals
    • Important: Each user always keeps their 8 most recent check-ins visible, even if older than the archive cutoff

Example:

Viewing Check-In Reports

Accessing Reports

From Admin Dashboard:

  1. Open Admin Dashboard (hamburger menu in top-left)
  2. Statistics are visible on the main dashboard screen
  3. For detailed reports, go to User Management → Manage Users
  4. View check-in statistics section

From User Management:

  1. Open Admin Dashboard (hamburger menu)
  2. Tap User Management → Manage Users
  3. Scroll to “Gym Check-In Statistics” section
  4. View reports and archive options

Statistics Available

Dashboard Quick Stats:

Individual Athlete Stats:

Date Range Reports:

Recommended Usage:

Firestore Rules

match /gym_checkin_aggregates/{dateId} {
  // All authenticated users can read aggregates
  allow read: if request.auth != null;
  // Only admins can create/update aggregates (via archive process)
  allow create, update: if isAdminUser();
  // Only admins can delete aggregates
  allow delete: if isAdminUser();
}

Performance Benefits

Before Aggregates

After Aggregates

Example Savings

With 2,000 check-ins over 6 months:

If deleting after archive:

Best Practices

Archive Frequency

Recommended schedule:

Important: Regardless of the archive cutoff date, each user will always retain their 8 most recent check-ins. This ensures athletes can always see their recent check-in history on their check-in screen.

Cutoff Date Selection

Safe approach:

  1. Keep last 60 days as individual records (for detailed queries)
  2. Archive everything older into aggregates
  3. Delete old individual records to save storage
  4. Automatic preservation: System keeps each user’s 8 most recent check-ins regardless of date

Example workflow:

// Archive everything before 60 days ago
final cutoffDate = DateTime.now().subtract(Duration(days: 60));
await LocationService.archiveGymCheckIns(
  cutoffDate: cutoffDate,
  deleteAfterArchive: true,  // Save storage, but auto-preserves 8/user
);

What gets preserved when deleting:

When NOT to Delete

Keep individual records if you need:

In these cases:

await LocationService.archiveGymCheckIns(
  cutoffDate: cutoffDate,
  deleteAfterArchive: false,  // Keep originals
);

Automated Archiving (Future Enhancement)

Consider adding a Cloud Function to run monthly:

// fcm_listener_function/src/index.ts
exports.monthlyArchive = functions.pubsub
  .schedule('0 0 1 * *')  // First day of each month
  .timeZone('America/New_York')
  .onRun(async (context) => {
    const cutoffDate = new Date();
    cutoffDate.setDate(cutoffDate.getDate() - 30);
    
    // Archive logic here
    return null;
  });

Troubleshooting

Archive Fails Partway

Symptoms: Some aggregates created, but error occurs Cause: Firestore batch size exceeded or network error Solution: Archive process uses 500-operation batches and commits incrementally. Partial progress is saved. Re-run the archive to complete.

Stats Don’t Match Expected Values

Symptoms: Dashboard shows different numbers after archiving Cause: Overlapping data (same day in both collections) Solution: Archive process creates aggregates for complete days only. getGymCheckInStats() handles overlaps correctly by checking dates.

Can’t Delete Aggregates

Symptoms: Delete operation denied Cause: Only admins can delete aggregates Solution: Ensure user has admin role in Firestore

Migration Path

For existing deployments with no aggregates:

  1. Deploy code (this update)
  2. Test with small archive (last 2-3 days, no delete)
  3. Verify stats match before/after
  4. Full archive (30+ days ago, with delete)
  5. Monitor performance improvement
  6. Schedule monthly archives going forward

Testing

Manual Test Checklist

Test Data Setup

// Create test check-ins across multiple dates
for (int i = 0; i < 60; i++) {
  await FirebaseFirestore.instance.collection('gym_checkins').add({
    'userId': 'test_user_$i',
    'userEmail': 'test$i@example.com',
    'userName': 'Test User $i',
    'timestamp': Timestamp.fromDate(
      DateTime.now().subtract(Duration(days: i)),
    ),
    'distanceFromGym': 10.0,
    'location': {'latitude': 0.0, 'longitude': 0.0},
  });
}