# Hive CE Database Setup

This directory contains the Hive CE (Community Edition) database configuration and services for the Worker Flutter app.

## Overview

The app uses Hive CE for offline-first local data persistence. Hive is a lightweight, fast NoSQL database written in pure Dart, perfect for Flutter applications.

## Key Features

- **Offline-First**: All data is stored locally and synced with the backend
- **Fast Performance**: Hive is optimized for speed with minimal overhead
- **Type-Safe**: Uses type adapters for strong typing
- **Encryption Support**: Optional AES encryption for sensitive data
- **Auto-Compaction**: Automatic database maintenance and cleanup
- **Migration Support**: Built-in schema versioning and migrations

## File Structure

```
lib/core/database/
├── README.md                 # This file
├── hive_service.dart         # Main Hive initialization and lifecycle management
├── database_manager.dart     # High-level database operations
└── models/
    ├── cached_data.dart      # Generic cache wrapper model
    └── enums.dart            # All enum type adapters
```

## Setup Instructions

### 1. Install Dependencies

The required packages are already in `pubspec.yaml`:

```yaml
dependencies:
  hive_ce: ^2.6.0
  hive_ce_flutter: ^2.1.0

dev_dependencies:
  hive_ce_generator: ^1.6.0
  build_runner: ^2.4.11
```

Run:
```bash
flutter pub get
```

### 2. Generate Type Adapters

After creating Hive models with `@HiveType` annotations, run:

```bash
dart run build_runner build --delete-conflicting-outputs
```

Or for continuous watching during development:
```bash
dart run build_runner watch --delete-conflicting-outputs
```

### 3. Initialize Hive in main.dart

```dart
import 'package:flutter/material.dart';
import 'core/database/hive_service.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();

  // Initialize Hive
  final hiveService = HiveService();
  await hiveService.initialize();

  runApp(const MyApp());
}
```

## Creating Hive Models

### Basic Model Example

```dart
import 'package:hive_ce/hive.dart';
import '../../constants/storage_constants.dart';

part 'user_model.g.dart'; // Generated file

@HiveType(typeId: HiveTypeIds.user)
class UserModel extends HiveObject {
  @HiveField(0)
  final String id;

  @HiveField(1)
  final String name;

  @HiveField(2)
  final String email;

  UserModel({
    required this.id,
    required this.name,
    required this.email,
  });
}
```

### Enum Example

```dart
@HiveType(typeId: HiveTypeIds.memberTier)
enum MemberTier {
  @HiveField(0)
  gold,

  @HiveField(1)
  platinum,

  @HiveField(2)
  diamond,
}
```

### Important Rules

1. **Type IDs must be unique** across the entire app (0-223 for user types)
2. **Never change field numbers** once assigned - it will break existing data
3. **Use `part` directive** to include generated adapter file
4. **Extend HiveObject** for model classes (optional but recommended for auto-save)
5. **Register adapters** before opening boxes (handled by HiveService)

## Box Management

### Available Boxes

The app uses these pre-configured boxes (see `storage_constants.dart`):

- `user_box` - User profile and auth data (encrypted)
- `product_box` - Product catalog cache
- `cart_box` - Shopping cart items (encrypted)
- `order_box` - Order history (encrypted)
- `project_box` - Construction projects (encrypted)
- `loyalty_box` - Loyalty transactions (encrypted)
- `rewards_box` - Rewards catalog
- `settings_box` - App settings
- `cache_box` - Generic API cache
- `sync_state_box` - Sync timestamps
- `notification_box` - Notifications
- `address_box` - Delivery addresses (encrypted)
- `offline_queue_box` - Failed API requests queue (encrypted)

### Using Boxes

```dart
// Using DatabaseManager (recommended)
final dbManager = DatabaseManager();

// Save data
await dbManager.save(
  boxName: HiveBoxNames.productBox,
  key: 'product_123',
  value: product,
);

// Get data
final product = dbManager.get(
  boxName: HiveBoxNames.productBox,
  key: 'product_123',
);

// Get all
final products = dbManager.getAll(boxName: HiveBoxNames.productBox);
```

## Caching Strategy

### Save to Cache

```dart
final dbManager = DatabaseManager();

await dbManager.saveToCache(
  key: HiveKeys.productsCacheKey,
  data: products,
);
```

### Get from Cache

```dart
final products = dbManager.getFromCache<List<Product>>(
  key: HiveKeys.productsCacheKey,
  maxAge: CacheDuration.products, // 6 hours
);

if (products == null) {
  // Cache miss or expired - fetch from API
  final freshProducts = await api.getProducts();
  await dbManager.saveToCache(
    key: HiveKeys.productsCacheKey,
    data: freshProducts,
  );
}
```

### Check Cache Validity

```dart
final isValid = dbManager.isCacheValid(
  key: HiveKeys.productsCacheKey,
  maxAge: CacheDuration.products,
);

if (!isValid) {
  // Refresh cache
}
```

## Offline Queue

Handle failed API requests when offline:

```dart
// Add to queue when API call fails
await dbManager.addToOfflineQueue({
  'endpoint': '/api/orders',
  'method': 'POST',
  'body': orderData,
});

// Process queue when back online
final queue = dbManager.getOfflineQueue();
for (var i = 0; i < queue.length; i++) {
  try {
    await api.request(queue[i]);
    await dbManager.removeFromOfflineQueue(i);
  } catch (e) {
    // Keep in queue for next retry
  }
}
```

## Data Synchronization

Track sync state for different data types:

```dart
// Update sync timestamp
await dbManager.updateSyncTime(HiveKeys.productsSyncTime);

// Get last sync time
final lastSync = dbManager.getLastSyncTime(HiveKeys.productsSyncTime);

// Check if needs sync
final needsSync = dbManager.needsSync(
  dataType: HiveKeys.productsSyncTime,
  syncInterval: Duration(hours: 6),
);
```

## Encryption

Enable encryption for sensitive data in `storage_constants.dart`:

```dart
class HiveDatabaseConfig {
  static const bool enableEncryption = true;
}
```

Generate and store encryption key securely:

```dart
// Generate key
final encryptionKey = HiveService.generateEncryptionKey();

// Store securely using flutter_secure_storage
final secureStorage = FlutterSecureStorage();
await secureStorage.write(
  key: 'hive_encryption_key',
  value: base64Encode(encryptionKey),
);

// Initialize with key
final storedKey = await secureStorage.read(key: 'hive_encryption_key');
await hiveService.initialize(
  encryptionKey: base64Decode(storedKey!),
);
```

## Migrations

Handle schema changes:

```dart
// In hive_service.dart, add migration logic:

Future<void> _migrateToVersion(int version) async {
  switch (version) {
    case 2:
      await _migrateV1ToV2();
      break;
  }
}

Future<void> _migrateV1ToV2() async {
  // Example: Add new field to existing data
  final userBox = Hive.box(HiveBoxNames.userBox);

  for (var key in userBox.keys) {
    final user = userBox.get(key);
    // Update user data structure
    await userBox.put(key, updatedUser);
  }
}
```

## Database Maintenance

### Clear Expired Cache

```dart
await dbManager.clearExpiredCache();
```

### Compact Boxes

```dart
final hiveService = HiveService();
// Compaction happens automatically during initialization
```

### Clear User Data (Logout)

```dart
await hiveService.clearUserData();
```

### Clear All Data

```dart
await hiveService.clearAllData();
```

### Get Statistics

```dart
final stats = dbManager.getStatistics();
dbManager.printStatistics();
```

## Best Practices

1. **Always initialize Hive before using any boxes**
2. **Use DatabaseManager for common operations**
3. **Cache frequently accessed data**
4. **Set appropriate cache expiration times**
5. **Handle errors gracefully** - Hive operations can fail
6. **Use transactions for multiple related updates**
7. **Compact boxes periodically** for optimal performance
8. **Never store large files in Hive** - use file system instead
9. **Test migrations thoroughly** before release
10. **Monitor database size** in production

## Debugging

### Print Box Contents

```dart
final box = Hive.box(HiveBoxNames.productBox);
print('Box length: ${box.length}');
print('Keys: ${box.keys}');
print('Values: ${box.values}');
```

### Check Box Location

```dart
print('Hive path: ${Hive.box(HiveBoxNames.settingsBox).path}');
```

### View Statistics

```dart
DatabaseManager().printStatistics();
```

## Troubleshooting

### "Box not found" Error
- Ensure Hive is initialized before accessing boxes
- Check that box name is correct

### "TypeAdapter not registered" Error
- Run `build_runner` to generate adapters
- Ensure adapter is registered in `HiveService._registerTypeAdapters()`

### "Cannot write null values" Error
- Make fields nullable with `?` or provide default values
- Check that HiveField annotations are correct

### Data Corruption
- Enable backup/restore functionality
- Implement data validation before saving
- Use try-catch blocks around Hive operations

## Testing

```dart
import 'package:flutter_test/flutter_test.dart';
import 'package:hive_ce/hive.dart';
import 'package:hive_ce_flutter/hive_flutter.dart';

void main() {
  setUp(() async {
    await Hive.initFlutter();
    // Register test adapters
  });

  tearDown(() async {
    await Hive.deleteFromDisk();
  });

  test('Save and retrieve user', () async {
    final box = await Hive.openBox('test_box');
    await box.put('user', UserModel(id: '1', name: 'Test'));

    final user = box.get('user');
    expect(user.name, 'Test');
  });
}
```

## Resources

- [Hive CE Documentation](https://github.com/IO-Design-Team/hive_ce)
- [Original Hive Documentation](https://docs.hivedb.dev/)
- [Flutter Offline-First Best Practices](https://flutter.dev/docs/cookbook/persistence)

## Type Adapter Registry

### Registered Type IDs (0-223)

| Type ID | Model | Status |
|---------|-------|--------|
| 0 | UserModel | TODO |
| 1 | ProductModel | TODO |
| 2 | CartItemModel | TODO |
| 3 | OrderModel | TODO |
| 4 | ProjectModel | TODO |
| 5 | LoyaltyTransactionModel | TODO |
| 10 | OrderItemModel | TODO |
| 11 | AddressModel | TODO |
| 12 | CategoryModel | TODO |
| 13 | RewardModel | TODO |
| 14 | GiftModel | TODO |
| 15 | NotificationModel | TODO |
| 16 | QuoteModel | TODO |
| 17 | PaymentModel | TODO |
| 18 | PromotionModel | TODO |
| 19 | ReferralModel | TODO |
| 20 | MemberTier (enum) | Created |
| 21 | UserType (enum) | Created |
| 22 | OrderStatus (enum) | Created |
| 23 | ProjectStatus (enum) | Created |
| 24 | ProjectType (enum) | Created |
| 25 | TransactionType (enum) | Created |
| 26 | GiftStatus (enum) | Created |
| 27 | PaymentStatus (enum) | Created |
| 28 | NotificationType (enum) | Created |
| 29 | PaymentMethod (enum) | Created |
| 30 | CachedData | Created |
| 31 | SyncState | TODO |
| 32 | OfflineRequest | TODO |

**IMPORTANT**: Never reuse or change these type IDs once assigned!
