This commit is contained in:
2025-10-16 17:22:27 +07:00
parent 3b1f198f2a
commit 7dc66d80fc
17 changed files with 222 additions and 217 deletions

View File

@@ -64,8 +64,8 @@ You have access to these expert subagents - USE THEM PROACTIVELY:
## Flutter Best Practices
- Use Flutter 3.x features and Material 3 design
- Implement clean architecture with Riverpod for state management
- Use Hive CE for local database and offline-first functionality
- Follow proper dependency injection with GetIt
- Use Hive CE for local database with **online-first** strategy (API first, cache fallback)
- Follow proper dependency injection with Riverpod providers
- Implement proper error handling and user feedback
- Follow platform-specific design guidelines
- Use proper localization for multi-language support
@@ -453,7 +453,7 @@ A comprehensive Flutter-based Point of Sale (POS) application designed for retai
- Supplier state
**Data Requirements**:
- Product list from Hive (offline-first)
- Product list from API (online-first with Hive cache fallback)
- Product images (cached with variants)
- Product search indexing
- Category relationships
@@ -969,45 +969,63 @@ GridView.builder(
- Debounce search queries
- Optimize cart calculations
## Offline-First Strategy
## Online-First Strategy
### Data Flow
1. **Read**: Always read from Hive first (instant UI)
2. **Sync**: Background sync with API when online
3. **Update**: Update Hive and UI when sync completes
4. **Conflict**: Handle conflicts with last-write-wins strategy
1. **Check Connection**: Check if device is online
2. **Try API First**: If online, fetch fresh data from API
3. **Update Cache**: Save API response to Hive for offline access
4. **Fallback to Cache**: If API fails or offline, load from Hive
5. **Show Data**: Display data to user (from API or cache)
### Sync Logic
### Implementation Pattern
```dart
@riverpod
class DataSync extends _$DataSync {
class Products extends _$Products {
@override
Future<SyncStatus> build() async {
return await _performSync();
Future<List<Product>> build() async {
// Online-first: Try to load from API first
final repository = ref.watch(productRepositoryProvider);
final networkInfo = ref.watch(networkInfoProvider);
// Check if online
final isConnected = await networkInfo.isConnected;
if (isConnected) {
// Try API first
try {
final syncResult = await repository.syncProducts();
return syncResult.fold(
(failure) {
// API failed, fallback to cache
print('API failed, falling back to cache: ${failure.message}');
return _loadFromCache();
},
(products) => products,
);
} catch (e) {
// API error, fallback to cache
print('API error, falling back to cache: $e');
return _loadFromCache();
}
} else {
// Offline, load from cache
print('Offline, loading from cache');
return _loadFromCache();
}
}
Future<SyncStatus> _performSync() async {
if (!await ref.read(networkInfoProvider).isConnected) {
return SyncStatus.offline;
}
try {
// Sync categories first
await ref.read(categoriesProvider.notifier).syncCategories();
// Then sync products and variants
await ref.read(productsProvider.notifier).syncProducts();
// Sync suppliers
await ref.read(suppliersProvider.notifier).syncSuppliers();
// Update last sync time
await ref.read(settingsProvider.notifier).updateLastSync();
return SyncStatus.success;
} catch (e) {
return SyncStatus.failed;
}
Future<List<Product>> _loadFromCache() async {
final repository = ref.read(productRepositoryProvider);
final result = await repository.getAllProducts();
return result.fold(
(failure) {
print('Cache load failed: ${failure.message}');
return <Product>[];
},
(products) => products,
);
}
}
```
@@ -1134,7 +1152,7 @@ class DataSync extends _$DataSync {
### Code Review Checklist
- [ ] Follows clean architecture principles
- [ ] Proper error handling implemented
- [ ] Offline-first approach maintained
- [ ] **Online-first approach maintained** (API first, cache fallback)
- [ ] Performance optimizations applied
- [ ] Proper state management with Riverpod
- [ ] Hive models and adapters properly defined