# Database Service Documentation ## Overview The RxMinder application uses a unified database service that implements the Strategy pattern to provide a flexible data access layer. This service can seamlessly switch between different database implementations based on the environment configuration. ## Architecture ### Strategy Pattern Implementation The database service uses the Strategy pattern to abstract database operations: ``` DatabaseService (Context) ├── DatabaseStrategy (Interface) ├── MockDatabaseStrategy (Concrete Strategy) └── ProductionDatabaseStrategy (Concrete Strategy) ``` ### Key Components - **DatabaseService**: Main service class that delegates operations to the selected strategy - **DatabaseStrategy**: Interface defining all database operations - **MockDatabaseStrategy**: In-memory implementation for development and testing - **ProductionDatabaseStrategy**: CouchDB implementation for production environments ## Configuration ### Environment-Based Strategy Selection The service automatically selects the appropriate strategy based on environment variables: 1. **Test Environment**: Always uses `MockDatabaseStrategy` 2. **Production Environment**: Uses `ProductionDatabaseStrategy` if CouchDB URL is configured 3. **Fallback**: Uses `MockDatabaseStrategy` if production strategy fails to initialize ### Environment Variables ```bash # CouchDB Configuration (for production) VITE_COUCHDB_URL=http://localhost:5984 COUCHDB_URL=http://localhost:5984 # Test Environment Detection NODE_ENV=test ``` ## Usage ### Basic Usage ```typescript import { databaseService } from './services/database'; // The service automatically selects the appropriate strategy const users = await databaseService.getAllUsers(); ``` ### Strategy Information ```typescript // Check which strategy is being used console.log(databaseService.getStrategyType()); // "MockDatabaseStrategy" or "ProductionDatabaseStrategy" // Check if using mock strategy if (databaseService.isUsingMockStrategy()) { console.log('Using in-memory database'); } // Check if using production strategy if (databaseService.isUsingProductionStrategy()) { console.log('Using CouchDB database'); } ``` ## API Reference ### User Operations #### createUser(user) Creates a new user in the database. ```typescript const user = await databaseService.createUser({ _id: 'user1', _rev: '1-abc123', username: 'john_doe', email: 'john@example.com', role: UserRole.USER, status: AccountStatus.ACTIVE, }); ``` #### updateUser(user) Updates an existing user. ```typescript const updatedUser = await databaseService.updateUser({ ...existingUser, username: 'new_username', }); ``` #### getUserById(id) Retrieves a user by their ID. ```typescript const user = await databaseService.getUserById('user1'); ``` #### findUserByEmail(email) Finds a user by their email address. ```typescript const user = await databaseService.findUserByEmail('john@example.com'); ``` #### deleteUser(id) Deletes a user from the database. ```typescript const success = await databaseService.deleteUser('user1'); ``` #### getAllUsers() Retrieves all users from the database. ```typescript const users = await databaseService.getAllUsers(); ``` ### Authentication Operations #### createUserWithPassword(email, hashedPassword, username?) Creates a user with password-based authentication. ```typescript const user = await databaseService.createUserWithPassword('user@example.com', 'hashed_password', 'username'); ``` #### createUserFromOAuth(email, username, provider) Creates a user from OAuth authentication. ```typescript const user = await databaseService.createUserFromOAuth('user@example.com', 'username', 'google'); ``` ### Medication Operations #### createMedication(userId, medication) Creates a new medication for a user. ```typescript const medication = await databaseService.createMedication('user1', { name: 'Aspirin', dosage: '100mg', frequency: Frequency.Daily, startTime: '08:00', notes: 'Take with food', }); ``` #### updateMedication(medication) Updates an existing medication. ```typescript const updatedMedication = await databaseService.updateMedication({ ...existingMedication, dosage: '200mg', }); ``` #### getMedications(userId) Retrieves all medications for a user. ```typescript const medications = await databaseService.getMedications('user1'); ``` #### deleteMedication(id) Deletes a medication. ```typescript const success = await databaseService.deleteMedication('medication1'); ``` ### User Settings Operations #### getUserSettings(userId) Retrieves user settings. ```typescript const settings = await databaseService.getUserSettings('user1'); ``` #### updateUserSettings(settings) Updates user settings. ```typescript const updatedSettings = await databaseService.updateUserSettings({ ...existingSettings, notificationsEnabled: false, }); ``` ### Taken Doses Operations #### getTakenDoses(userId) Retrieves taken doses record for a user. ```typescript const takenDoses = await databaseService.getTakenDoses('user1'); ``` #### updateTakenDoses(takenDoses) Updates the taken doses record. ```typescript const updatedTakenDoses = await databaseService.updateTakenDoses({ ...existingTakenDoses, doses: { ...existingTakenDoses.doses, dose1: new Date().toISOString() }, }); ``` ### Custom Reminders Operations #### createCustomReminder(userId, reminder) Creates a custom reminder for a user. ```typescript const reminder = await databaseService.createCustomReminder('user1', { title: 'Doctor Appointment', icon: '🏥', frequencyMinutes: 60, startTime: '09:00', endTime: '17:00', }); ``` #### updateCustomReminder(reminder) Updates a custom reminder. ```typescript const updatedReminder = await databaseService.updateCustomReminder({ ...existingReminder, title: 'Updated Appointment', }); ``` #### getCustomReminders(userId) Retrieves all custom reminders for a user. ```typescript const reminders = await databaseService.getCustomReminders('user1'); ``` #### deleteCustomReminder(id) Deletes a custom reminder. ```typescript const success = await databaseService.deleteCustomReminder('reminder1'); ``` ### Administrative Operations #### suspendUser(userId) Suspends a user account. ```typescript const suspendedUser = await databaseService.suspendUser('user1'); ``` #### activateUser(userId) Activates a suspended user account. ```typescript const activatedUser = await databaseService.activateUser('user1'); ``` #### changeUserPassword(userId, newPassword) Changes a user's password. ```typescript const updatedUser = await databaseService.changeUserPassword('user1', 'new_hashed_password'); ``` #### deleteAllUserData(userId) Deletes all data associated with a user. ```typescript const success = await databaseService.deleteAllUserData('user1'); ``` ## Testing ### Mock Strategy for Testing The `MockDatabaseStrategy` provides an in-memory implementation that's perfect for testing: ```typescript import { DatabaseService } from './services/database'; // In test environment, automatically uses MockDatabaseStrategy const service = new DatabaseService(); // All operations work the same way but use in-memory storage const user = await service.createUser(mockUser); ``` ### Test Utilities The test setup provides utilities for creating mock data: ```typescript import { testUtils } from './tests/setup'; const mockUser = testUtils.createMockUser(); const mockMedication = testUtils.createMockMedication(); ``` ## Error Handling ### DatabaseError All database operations can throw `DatabaseError` for various failure scenarios: ```typescript import { DatabaseError } from './services/database'; try { const user = await databaseService.getUserById('nonexistent'); } catch (error) { if (error instanceof DatabaseError) { console.error('Database operation failed:', error.message); } } ``` ### Fallback Behavior The service automatically falls back to the mock strategy if the production strategy fails to initialize: ```typescript // If CouchDB is not available, this will log a warning and use MockDatabaseStrategy const service = new DatabaseService(); ``` ## Migration from Legacy Implementation ### Removed Files The following deprecated files have been removed: - `services/couchdb.ts` - Legacy CouchDB service - `services/couchdb.factory.ts` - CouchDB factory - `services/couchdb.production.ts` - Production CouchDB configuration - `scripts/migrate-to-unified-config.ts` - Migration script ### Migration Guide 1. **Update imports**: Change from legacy CouchDB imports to unified database service: ```typescript // Old import { couchdbService } from './services/couchdb'; // New import { databaseService } from './services/database'; ``` 2. **Update method calls**: The API remains largely the same, but some methods have been standardized: ```typescript // Old await couchdbService.updateMedication(userId, medication); // New await databaseService.updateMedication(medication); ``` 3. **Environment configuration**: Update environment variables to use the new configuration format. ## Best Practices ### 1. Error Handling Always handle potential database errors: ```typescript try { const user = await databaseService.getUserById(userId); if (!user) { throw new Error('User not found'); } // Process user } catch (error) { console.error('Failed to retrieve user:', error); // Handle error appropriately } ``` ### 2. Transaction-like Operations For operations that affect multiple entities, use proper error handling: ```typescript try { const medications = await databaseService.getMedications(userId); const reminders = await databaseService.getCustomReminders(userId); // Process both together return { medications, reminders }; } catch (error) { console.error('Failed to load user data:', error); throw error; } ``` ### 3. Strategy-Agnostic Code Write code that works with any strategy: ```typescript // Good - works with any strategy const user = await databaseService.getUserById(userId); // Avoid - strategy-specific checks unless necessary if (databaseService.isUsingMockStrategy()) { // Only do this if absolutely necessary } ``` ## Performance Considerations ### Mock Strategy - In-memory storage for fast operations - Perfect for development and testing - Data is lost when the application restarts ### Production Strategy - Persistent storage with CouchDB - Network latency considerations - Proper error handling for network failures ## Security ### Data Validation All data is validated before database operations: - User input sanitization - Type checking with TypeScript interfaces - Required field validation ### Access Control - User authentication required for all operations - Role-based access control for administrative operations - User isolation (users can only access their own data) ## Troubleshooting ### Common Issues 1. **CouchDB Connection Failed** - Check `VITE_COUCHDB_URL` or `COUCHDB_URL` environment variables - Verify CouchDB is running and accessible - Check network connectivity 2. **Strategy Selection Issues** - Verify environment variable configuration - Check console logs for strategy selection messages - Use `getStrategyType()` to confirm active strategy 3. **Test Environment Issues** - Ensure `NODE_ENV=test` is set for test runs - Verify test setup files are properly configured - Check that mock data is being used ### Debug Information Enable debug logging to troubleshoot issues: ```typescript console.log('Active strategy:', databaseService.getStrategyType()); console.log('Using mock strategy:', databaseService.isUsingMockStrategy()); console.log('Using production strategy:', databaseService.isUsingProductionStrategy()); ``` --- ## Related Documentation - [API Documentation](API.md) - REST API endpoints - [Application Security](APPLICATION_SECURITY.md) - Security practices - [Code Quality](CODE_QUALITY.md) - Development standards --- **Last Updated:** January 2024 **Version:** 2.0.0