Files
rxminder/docs/development/DATABASE.md
William Valentin 598c1da17b Complete database service consolidation and documentation
 Features:
- Add comprehensive database service documentation
- Create detailed module README with usage examples
- Expand main documentation index with database links
- Add component test support to Jest configuration

🔧 Improvements:
- Fix AvatarDropdown test failures (dark mode classes and rapid clicking)
- Update documentation version to 2.1
- Include migration guide and troubleshooting sections
- Add performance considerations and security notes

📚 Documentation:
- Complete API reference with code examples
- Architecture overview with Strategy pattern explanation
- Environment configuration and strategy selection guide
- Best practices and development guidelines
- Comprehensive refactoring summary

🧪 Testing:
- All 292 tests passing across all modules
- Component tests now properly integrated with Jest
- Fixed TypeScript compatibility issues in tests
- Verified database service functionality in all environments

📋 Summary:
- Removed deprecated CouchDB service files
- Consolidated database operations under unified service
- Enhanced documentation structure and content
- Improved test coverage and reliability
- Maintained backward compatibility where possible
2025-09-08 18:59:08 -07:00

528 lines
12 KiB
Markdown

# 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