My App
Admin App DocsAiRefactoring

Task 1 Repositories And Providers

SmartCrew Admin - Task 1 Repositories And Providers

Task 1: Repository Pattern Implementation and Provider Refactoring

Isolation Scope

This task is completely isolated and focuses ONLY on:

  • Creating repository layer for data access and caching
  • Refactoring network providers to delegate queries to repositories
  • Maintaining all existing provider APIs unchanged

Dependencies: None (can be implemented independently) Affected Files: Only providers and new repository files Not Included: Services and adapters (handled in separate tasks)

Goal

Implement the Repository pattern to separate data access logic from business logic while maintaining 100% backward compatibility with existing provider APIs.

Current State - Provider Analysis

NetworkDataProvider Structure

// Current: All data operations mixed in providers
class NetworkDataProvider with UsersProvider, ProjectProvider, EquipmentProvider, etc.

// Each mixin handles:
- Firestore CRUD operations ✅ (Keep)
- Data caching with SplayTreeSet/HashMap ❌ (Move to repositories)
- Complex queries and filtering ❌ (Move to repositories)
- Search and pattern matching ❌ (Move to repositories)

Files Currently Using Direct Data Structures

  • lib/providers/network_data_providers/users_provider.dart - Lines 20-23
  • lib/providers/network_data_providers/project_provider.dart - Lines 14-16
  • lib/providers/network_data_providers/equipment_provider.dart - Lines 14-15
  • lib/providers/network_data_providers/customers_provider.dart
  • lib/providers/network_data_providers/vendors_provider.dart
  • lib/providers/network_data_providers/materials_provider.dart
  • lib/providers/network_data_providers/activity_provider.dart

Implementation Steps

Step 1: Create Base Repository (Isolated)

File: lib/repositories/base_repository.dart

abstract class BaseRepository<T> {
  List<T> getAll();
  T? getById(String id);
  List<T> where(bool Function(T) predicate);
  void add(T item);
  void remove(T item);
  void clear();
  String getItemId(T item);
}

abstract class CachedRepository<T> implements BaseRepository<T> {
  final SplayTreeSet<T> _items;
  final HashMap<String, T> _itemMap;
  // Implementation with optimized data structures
}

Step 2: Create Domain Repositories (One by One)

2.1 Users Repository

File: lib/repositories/users_repository.dart Purpose: Handle user data queries and user logs aggregation

class UsersRepository extends CachedRepository<AppUser> {
  // User-specific optimized queries
  List<AppUser> searchByName(String pattern);
  List<AppUser> getActiveUsers();
  Map<String, List<DailyLog>> getUserLogs(); // Optimized log access
}

2.2 Equipment Repository

File: lib/repositories/equipment_repository.dart Purpose: Handle equipment queries and service record associations

class EquipmentRepository extends CachedRepository<Equipment> {
  List<Equipment> getByType(String type);
  List<Equipment> getAvailableEquipment();
}

Step 3: Refactor Each Provider (One by One)

3.1 Refactor UsersProvider

Before:

final SplayTreeSet<AppUser> _users = SplayTreeSet(...);
List<AppUser> getUserSuggestions(String pattern) {
  return _users.where(...).toList(); // Direct data structure access
}

After:

late final UsersRepository _usersRepository;
List<AppUser> getUserSuggestions(String pattern) {
  return _usersRepository.searchByName(pattern); // Delegate to repository
}

Step 4: Integration with NetworkDataProvider

File: lib/providers/network_data_providers/network_data_provider.dart

Future<void> init(AuthProvider auth) async {
  // Initialize repositories before data fetching
  _initializeRepositories();
  
  await Future.wait([
    fetchUsersFromFireStore(), // Now uses repository for caching
    // ... other fetch methods
  ]);
}

void _initializeRepositories() {
  // Initialize all repositories with proper comparators
}

Testing & Validation Metrics

Pre-Refactoring Baseline Tests

Run these tests BEFORE starting refactoring:

# 1. Functional Test - Capture current behavior
flutter test test/ --coverage
# Expected: All tests pass (establish baseline)

# 2. Performance Baseline
# Add this test method to capture current performance:
void testCurrentPerformance() {
  final stopwatch = Stopwatch()..start();
  
  // Test user search performance
  final users = provider.getUserSuggestions("john");
  stopwatch.stop();
  print('User search time: ${stopwatch.elapsedMilliseconds}ms');
  
  // Test project queries
  stopwatch.reset()..start();
  final projects = provider.getProjectSuggestions("demo");
  stopwatch.stop();
  print('Project search time: ${stopwatch.elapsedMilliseconds}ms');
  
  // Memory usage baseline
  // Run this in profiler to capture baseline memory
}

# 3. API Contract Test - Document current provider behavior
void testProviderAPIs() {
  // Document exact return types and behavior
  expect(provider.users, isA<List<AppUser>>());
  expect(provider.getUserSuggestions("test"), isA<List<AppUser>>());
  expect(provider.getByUserId("id"), isA<AppUser?>());
  // ... test all current APIs
}

Post-Refactoring Validation Metrics

Metric 1: Zero Breaking Changes

# All existing tests MUST pass without modification
flutter test test/
# SUCCESS CRITERIA: 100% test pass rate (same as baseline)

Metric 2: Performance Improvement

# Run performance comparison test
void testPerformanceImprovement() {
  // User search should be 30% faster
  final userSearchTime = measureUserSearch();
  expect(userSearchTime, lessThan(baselineUserSearchTime * 0.7));
  
  // Project queries should be 40% faster  
  final projectSearchTime = measureProjectSearch();
  expect(projectSearchTime, lessThan(baselineProjectSearchTime * 0.6));
  
  // Memory usage should be 20% lower
  final memoryUsage = measureMemoryUsage();
  expect(memoryUsage, lessThan(baselineMemoryUsage * 0.8));
}

Metric 3: API Compatibility

# All provider methods must return identical results
void testAPICompatibility() {
  // Before/after comparison for each method
  final beforeUsers = captureBeforeResults();
  final afterUsers = captureAfterResults();
  expect(afterUsers, equals(beforeUsers)); // Exact same data
  
  // Response time should be better or equal
  final beforeTime = measureBeforeResponseTime();
  final afterTime = measureAfterResponseTime();
  expect(afterTime, lessThanOrEqualTo(beforeTime));
}

Metric 4: Repository Integration

# Verify repositories are working correctly
void testRepositoryIntegration() {
  // Repository should contain same data as before
  expect(usersRepository.getAll().length, equals(provider.users.length));
  
  // Repository queries should return correct data
  final repoSearch = usersRepository.searchByName("john");
  final providerSearch = provider.getUserSuggestions("john");
  expect(repoSearch, equals(providerSearch));
  
  // Cache should be properly synchronized
  provider.addUser(testUser);
  expect(usersRepository.getById(testUser.firebaseUid), equals(testUser));
}

Metric 5: Data Consistency

# Verify data integrity maintained
void testDataConsistency() {
  // Add user through provider
  provider.addUser(testUser);
  expect(provider.getByUserId(testUser.firebaseUid), equals(testUser));
  expect(usersRepository.getById(testUser.firebaseUid), equals(testUser));
  
  // Update user through provider  
  provider.updateUser(updatedUser);
  expect(provider.getByUserId(testUser.firebaseUid), equals(updatedUser));
  expect(usersRepository.getById(testUser.firebaseUid), equals(updatedUser));
  
  // Delete user through provider
  provider.removeUser(testUser);
  expect(provider.getByUserId(testUser.firebaseUid), isNull);
  expect(usersRepository.getById(testUser.firebaseUid), isNull);
}

Success Validation Checklist

Functional Validation

  • All existing unit tests pass unchanged
  • All provider APIs return identical results
  • No UI behavior changes
  • App startup works correctly
  • Data loading works correctly

Performance Validation

  • User search queries are 30% faster
  • Project queries are 40% faster
  • Memory usage reduced by 20%
  • No performance regression in any operation
  • App initialization time improved by 15%

Integration Validation

  • Repositories properly initialized
  • Provider-repository data sync works
  • Concurrent access handled correctly
  • Memory leaks prevented
  • Error handling maintained

Compatibility Validation

  • No changes to provider public APIs
  • All existing method signatures unchanged
  • Return types identical to before
  • Error cases handled identically
  • Null handling behavior preserved

Rollback Strategy

If any metric fails:

  1. Immediate Rollback: Revert to direct data structure usage in providers
  2. Feature Flag: Implement repository toggle for gradual testing
  3. Partial Rollback: Rollback individual providers independently
  4. Data Validation: Ensure no data corruption during rollback

Files Modified (Complete List)

New Files Created

  • lib/repositories/base_repository.dart
  • lib/repositories/users_repository.dart
  • lib/repositories/project_repository.dart
  • lib/repositories/equipment_repository.dart
  • lib/repositories/materials_repository.dart
  • lib/repositories/customers_repository.dart
  • lib/repositories/vendors_repository.dart
  • lib/repositories/activity_repository.dart

Existing Files Modified

  • lib/providers/network_data_providers/network_data_provider.dart
  • lib/providers/network_data_providers/users_provider.dart
  • lib/providers/network_data_providers/project_provider.dart
  • lib/providers/network_data_providers/equipment_provider.dart
  • lib/providers/network_data_providers/materials_provider.dart
  • lib/providers/network_data_providers/customers_provider.dart
  • lib/providers/network_data_providers/vendors_provider.dart
  • lib/providers/network_data_providers/activity_provider.dart

Total Files: 16 (8 new, 8 modified) Scope: Only providers and repositories - no services or adapters touched

On this page