✨ 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
428 lines
10 KiB
Markdown
428 lines
10 KiB
Markdown
# Database Service Module
|
|
|
|
A unified database abstraction layer implementing the Strategy pattern for flexible data persistence in the RxMinder application.
|
|
|
|
## Overview
|
|
|
|
This module provides a clean, consistent interface for all database operations while supporting multiple backend implementations. It automatically selects the appropriate strategy based on environment configuration.
|
|
|
|
## Architecture
|
|
|
|
```
|
|
services/database/
|
|
├── README.md # This file
|
|
├── index.ts # Public exports
|
|
├── types.ts # Type definitions and interfaces
|
|
├── DatabaseService.ts # Main service class (Strategy Context)
|
|
├── MockDatabaseStrategy.ts # In-memory implementation
|
|
├── ProductionDatabaseStrategy.ts # CouchDB implementation
|
|
└── __tests__/ # Test files
|
|
├── DatabaseService.test.ts
|
|
└── MockDatabaseStrategy.test.ts
|
|
```
|
|
|
|
## Quick Start
|
|
|
|
```typescript
|
|
import { databaseService } from './services/database';
|
|
|
|
// Service automatically selects appropriate strategy
|
|
const users = await databaseService.getAllUsers();
|
|
const user = await databaseService.getUserById('user123');
|
|
```
|
|
|
|
## Strategy Selection
|
|
|
|
The service automatically chooses the implementation based on environment:
|
|
|
|
| Environment | Strategy | Backend |
|
|
| ---------------------- | -------------------------- | --------- |
|
|
| `NODE_ENV=test` | MockDatabaseStrategy | In-memory |
|
|
| CouchDB URL configured | ProductionDatabaseStrategy | CouchDB |
|
|
| Default/Fallback | MockDatabaseStrategy | In-memory |
|
|
|
|
## Environment Variables
|
|
|
|
```bash
|
|
# Production CouchDB
|
|
VITE_COUCHDB_URL=http://localhost:5984
|
|
COUCHDB_URL=http://localhost:5984
|
|
|
|
# Force mock strategy (optional)
|
|
VITE_COUCHDB_URL=mock
|
|
```
|
|
|
|
## Core Interfaces
|
|
|
|
### DatabaseStrategy
|
|
|
|
All implementations must conform to this interface:
|
|
|
|
```typescript
|
|
interface DatabaseStrategy {
|
|
// User operations
|
|
createUser(user: Omit<User, '_rev'>): Promise<User>;
|
|
updateUser(user: User): Promise<User>;
|
|
getUserById(id: string): Promise<User | null>;
|
|
findUserByEmail(email: string): Promise<User | null>;
|
|
deleteUser(id: string): Promise<boolean>;
|
|
getAllUsers(): Promise<User[]>;
|
|
|
|
// Auth operations
|
|
createUserWithPassword(email: string, hashedPassword: string, username?: string): Promise<User>;
|
|
createUserFromOAuth(email: string, username: string, provider: string): Promise<User>;
|
|
|
|
// Medication operations
|
|
createMedication(userId: string, medication: Omit<Medication, '_id' | '_rev'>): Promise<Medication>;
|
|
updateMedication(medication: Medication): Promise<Medication>;
|
|
getMedications(userId: string): Promise<Medication[]>;
|
|
deleteMedication(id: string): Promise<boolean>;
|
|
|
|
// Settings operations
|
|
getUserSettings(userId: string): Promise<UserSettings>;
|
|
updateUserSettings(settings: UserSettings): Promise<UserSettings>;
|
|
|
|
// Doses operations
|
|
getTakenDoses(userId: string): Promise<TakenDoses>;
|
|
updateTakenDoses(takenDoses: TakenDoses): Promise<TakenDoses>;
|
|
|
|
// Reminders operations
|
|
createCustomReminder(userId: string, reminder: Omit<CustomReminder, '_id' | '_rev'>): Promise<CustomReminder>;
|
|
updateCustomReminder(reminder: CustomReminder): Promise<CustomReminder>;
|
|
getCustomReminders(userId: string): Promise<CustomReminder[]>;
|
|
deleteCustomReminder(id: string): Promise<boolean>;
|
|
}
|
|
```
|
|
|
|
## Implementations
|
|
|
|
### MockDatabaseStrategy
|
|
|
|
**Use Cases:**
|
|
|
|
- Development environment
|
|
- Unit testing
|
|
- Integration testing
|
|
- Demos and prototyping
|
|
|
|
**Features:**
|
|
|
|
- In-memory storage using Maps
|
|
- Immediate consistency
|
|
- No network dependencies
|
|
- Automatic data reset between tests
|
|
- Fast operations
|
|
|
|
**Limitations:**
|
|
|
|
- Data lost on application restart
|
|
- No persistence across sessions
|
|
- Single-process only
|
|
|
|
### ProductionDatabaseStrategy
|
|
|
|
**Use Cases:**
|
|
|
|
- Production deployments
|
|
- Staging environments
|
|
- Data persistence requirements
|
|
|
|
**Features:**
|
|
|
|
- CouchDB backend
|
|
- Persistent storage
|
|
- Document versioning with `_rev`
|
|
- ACID compliance
|
|
- Horizontal scaling support
|
|
|
|
**Requirements:**
|
|
|
|
- CouchDB server running
|
|
- Network connectivity
|
|
- Proper authentication/authorization
|
|
|
|
## Usage Examples
|
|
|
|
### Basic Operations
|
|
|
|
```typescript
|
|
import { databaseService } from './services/database';
|
|
|
|
// Create a user
|
|
const user = await databaseService.createUser({
|
|
_id: 'user123',
|
|
username: 'john_doe',
|
|
email: 'john@example.com',
|
|
role: UserRole.USER,
|
|
status: AccountStatus.ACTIVE,
|
|
});
|
|
|
|
// Add medication
|
|
const medication = await databaseService.createMedication(user._id, {
|
|
name: 'Aspirin',
|
|
dosage: '100mg',
|
|
frequency: Frequency.Daily,
|
|
startTime: '08:00',
|
|
});
|
|
|
|
// Update user settings
|
|
const settings = await databaseService.getUserSettings(user._id);
|
|
await databaseService.updateUserSettings({
|
|
...settings,
|
|
notificationsEnabled: true,
|
|
});
|
|
```
|
|
|
|
### Administrative Operations
|
|
|
|
```typescript
|
|
// User management
|
|
await databaseService.suspendUser('user123');
|
|
await databaseService.activateUser('user123');
|
|
await databaseService.changeUserPassword('user123', 'new_hashed_password');
|
|
|
|
// Complete data deletion
|
|
await databaseService.deleteAllUserData('user123');
|
|
```
|
|
|
|
### Strategy Inspection
|
|
|
|
```typescript
|
|
// Check active strategy
|
|
console.log('Strategy:', databaseService.getStrategyType());
|
|
|
|
// Strategy-specific logic (avoid when possible)
|
|
if (databaseService.isUsingMockStrategy()) {
|
|
console.log('Using in-memory storage');
|
|
} else if (databaseService.isUsingProductionStrategy()) {
|
|
console.log('Using CouchDB storage');
|
|
}
|
|
```
|
|
|
|
## Testing
|
|
|
|
### Unit Tests
|
|
|
|
```typescript
|
|
import { DatabaseService } from './DatabaseService';
|
|
import { MockDatabaseStrategy } from './MockDatabaseStrategy';
|
|
|
|
describe('DatabaseService', () => {
|
|
let service: DatabaseService;
|
|
|
|
beforeEach(() => {
|
|
// In test environment, automatically uses MockDatabaseStrategy
|
|
service = new DatabaseService();
|
|
});
|
|
|
|
test('should create user', async () => {
|
|
const user = await service.createUser(mockUser);
|
|
expect(user._id).toBeDefined();
|
|
expect(user.username).toBe(mockUser.username);
|
|
});
|
|
});
|
|
```
|
|
|
|
### Test Utilities
|
|
|
|
```typescript
|
|
import { testUtils } from '../../tests/setup';
|
|
|
|
const mockUser = testUtils.createMockUser();
|
|
const mockMedication = testUtils.createMockMedication();
|
|
```
|
|
|
|
## Error Handling
|
|
|
|
### DatabaseError
|
|
|
|
```typescript
|
|
import { DatabaseError } from './services/database';
|
|
|
|
try {
|
|
const user = await databaseService.getUserById('invalid-id');
|
|
} catch (error) {
|
|
if (error instanceof DatabaseError) {
|
|
console.error('Database operation failed:', error.message);
|
|
}
|
|
}
|
|
```
|
|
|
|
### Fallback Behavior
|
|
|
|
```typescript
|
|
// Service automatically falls back to MockDatabaseStrategy
|
|
// if ProductionDatabaseStrategy fails to initialize
|
|
const service = new DatabaseService(); // Safe to use
|
|
```
|
|
|
|
## Performance
|
|
|
|
### MockDatabaseStrategy
|
|
|
|
- **Pros:** Instant operations, no I/O overhead
|
|
- **Cons:** Memory usage grows with data size
|
|
- **Best for:** Development, testing, small datasets
|
|
|
|
### ProductionDatabaseStrategy
|
|
|
|
- **Pros:** Persistent storage, designed for scale
|
|
- **Cons:** Network latency, connection overhead
|
|
- **Best for:** Production, large datasets, multi-user
|
|
|
|
## Security
|
|
|
|
### Data Isolation
|
|
|
|
- Users can only access their own data
|
|
- User ID validation on all operations
|
|
- Role-based access for administrative functions
|
|
|
|
### Input Validation
|
|
|
|
- TypeScript interfaces enforce type safety
|
|
- Required field validation
|
|
- Email format validation
|
|
- ID format validation
|
|
|
|
### Authentication
|
|
|
|
- No anonymous access allowed
|
|
- User context required for all operations
|
|
- Password hashing handled by auth service
|
|
|
|
## Migration Guide
|
|
|
|
### From Legacy CouchDB Service
|
|
|
|
```typescript
|
|
// Old import
|
|
import { couchdbService } from './services/couchdb';
|
|
|
|
// New import
|
|
import { databaseService } from './services/database';
|
|
|
|
// Old method signature
|
|
await couchdbService.updateMedication(userId, medication);
|
|
|
|
// New method signature
|
|
await databaseService.updateMedication(medication);
|
|
```
|
|
|
|
### Breaking Changes
|
|
|
|
1. **Method signatures:** Some methods now accept the full entity instead of separate parameters
|
|
2. **Return types:** Consistent return types across all operations
|
|
3. **Error handling:** Unified error types with `DatabaseError`
|
|
|
|
## Troubleshooting
|
|
|
|
### Common Issues
|
|
|
|
**1. Strategy Selection**
|
|
|
|
```bash
|
|
# Check environment variables
|
|
echo $VITE_COUCHDB_URL
|
|
echo $NODE_ENV
|
|
|
|
# Verify strategy selection
|
|
console.log(databaseService.getStrategyType());
|
|
```
|
|
|
|
**2. CouchDB Connection**
|
|
|
|
```bash
|
|
# Test CouchDB connectivity
|
|
curl $VITE_COUCHDB_URL
|
|
|
|
# Check CouchDB logs
|
|
docker logs couchdb-container
|
|
```
|
|
|
|
**3. Test Environment**
|
|
|
|
```bash
|
|
# Ensure test environment
|
|
NODE_ENV=test npm test
|
|
|
|
# Verify mock strategy in tests
|
|
expect(databaseService.isUsingMockStrategy()).toBe(true);
|
|
```
|
|
|
|
### Debug Logging
|
|
|
|
```typescript
|
|
// Enable debug information
|
|
const strategy = databaseService.getStrategyType();
|
|
console.log(`Using ${strategy} for database operations`);
|
|
|
|
// Check environment
|
|
console.log('Environment:', process.env.NODE_ENV);
|
|
console.log('CouchDB URL:', process.env.VITE_COUCHDB_URL);
|
|
```
|
|
|
|
## Development
|
|
|
|
### Adding New Operations
|
|
|
|
1. **Update DatabaseStrategy interface** in `types.ts`
|
|
2. **Implement in MockDatabaseStrategy**
|
|
3. **Implement in ProductionDatabaseStrategy**
|
|
4. **Add delegation method** in `DatabaseService`
|
|
5. **Write tests** for all implementations
|
|
6. **Update documentation**
|
|
|
|
### Creating New Strategies
|
|
|
|
```typescript
|
|
class CustomDatabaseStrategy implements DatabaseStrategy {
|
|
// Implement all required methods
|
|
async createUser(user: Omit<User, '_rev'>): Promise<User> {
|
|
// Custom implementation
|
|
}
|
|
|
|
// ... implement all other methods
|
|
}
|
|
```
|
|
|
|
## Contributing
|
|
|
|
1. **Tests required** for all new features
|
|
2. **Type safety** - no `any` types
|
|
3. **Error handling** - proper error propagation
|
|
4. **Documentation** - update README and JSDoc
|
|
5. **Strategy pattern** - maintain abstraction
|
|
|
|
## Dependencies
|
|
|
|
### Production
|
|
|
|
- None (strategy implementations may have their own)
|
|
|
|
### Development
|
|
|
|
- `@types/jest` - Testing types
|
|
- `ts-jest` - TypeScript testing
|
|
- `@testing-library/react` - Component testing
|
|
|
|
## Changelog
|
|
|
|
### v2.0.0
|
|
|
|
- ✅ Unified database service with Strategy pattern
|
|
- ✅ Removed legacy CouchDB service files
|
|
- ✅ Added comprehensive test coverage
|
|
- ✅ Improved error handling
|
|
- ✅ TypeScript strict mode compliance
|
|
|
|
### v1.x.x
|
|
|
|
- ❌ Legacy CouchDB-only implementation (deprecated)
|
|
|
|
---
|
|
|
|
**Maintainers:** Development Team
|
|
**Last Updated:** January 2024
|
|
**License:** MIT
|