ruvector-extensions
Version:
Advanced features for ruvector: embeddings, UI, exports, temporal tracking, and persistence
724 lines (537 loc) • 17.3 kB
Markdown
# Temporal Tracking Module
Complete version control and time-travel capabilities for RUVector database evolution.
## Overview
The Temporal Tracking module provides enterprise-grade version management for your vector database, enabling:
- **Version Control**: Create snapshots of database state over time
- **Change Tracking**: Track all modifications with full audit trail
- **Time-Travel Queries**: Query database at any point in history
- **Diff Generation**: Compare versions to see what changed
- **Revert Capability**: Safely rollback to previous states
- **Visualization Data**: Generate timeline and change frequency data
- **Delta Encoding**: Efficient storage using incremental changes
- **Event System**: React to changes with event listeners
## Installation
```bash
npm install ruvector-extensions
```
## Quick Start
```typescript
import { TemporalTracker, ChangeType } from 'ruvector-extensions';
const tracker = new TemporalTracker();
// Track a change
tracker.trackChange({
type: ChangeType.ADDITION,
path: 'nodes.User',
before: null,
after: { name: 'User', properties: ['id', 'name', 'email'] },
timestamp: Date.now()
});
// Create version
const version = await tracker.createVersion({
description: 'Initial schema',
tags: ['v1.0', 'production']
});
// Query past state
const pastState = await tracker.queryAtTimestamp(version.timestamp);
// Compare versions
const diff = await tracker.compareVersions(v1.id, v2.id);
```
## Core Concepts
### Change Types
Four types of changes are tracked:
```typescript
enum ChangeType {
ADDITION = 'addition', // New entity added
DELETION = 'deletion', // Entity removed
MODIFICATION = 'modification', // Entity changed
METADATA = 'metadata' // Metadata updated
}
```
### Path System
Changes are organized by path (dot-notation):
```typescript
'nodes.User' // User node type
'edges.FOLLOWS' // FOLLOWS edge type
'config.maxUsers' // Configuration value
'schema.version' // Schema version
'nodes.User.properties' // Nested property
```
### Delta Encoding
Only differences between versions are stored:
```
Baseline (v0): {}
↓ + Change 1: Add User node
V1: { nodes: { User: {...} } }
↓ + Change 2: Add Post node
V2: { nodes: { User: {...}, Post: {...} } }
```
## API Reference
### TemporalTracker Class
#### Constructor
```typescript
const tracker = new TemporalTracker();
```
Creates a new tracker with a baseline version.
#### trackChange(change: Change): void
Track a change to be included in the next version.
```typescript
tracker.trackChange({
type: ChangeType.ADDITION,
path: 'nodes.User',
before: null,
after: { name: 'User', properties: ['id', 'name'] },
timestamp: Date.now(),
metadata: { author: 'system' } // optional
});
```
**Parameters:**
- `type`: Type of change (ADDITION, DELETION, MODIFICATION, METADATA)
- `path`: Dot-notation path to the changed entity
- `before`: Previous value (null for additions)
- `after`: New value (null for deletions)
- `timestamp`: When the change occurred
- `metadata`: Optional metadata about the change
**Events:** Emits `changeTracked` event
#### createVersion(options: CreateVersionOptions): Promise<Version>
Create a new version with all pending changes.
```typescript
const version = await tracker.createVersion({
description: 'Added user authentication',
tags: ['v2.0', 'production'],
author: 'developer@example.com',
metadata: { ticket: 'FEAT-123' }
});
```
**Parameters:**
- `description`: Human-readable description (required)
- `tags`: Array of tags for categorization
- `author`: Who created this version
- `metadata`: Additional custom metadata
**Returns:** Version object with ID, timestamp, changes, checksum
**Events:** Emits `versionCreated` event
#### listVersions(tags?: string[]): Version[]
List all versions, optionally filtered by tags.
```typescript
// All versions
const allVersions = tracker.listVersions();
// Only production versions
const prodVersions = tracker.listVersions(['production']);
// Multiple tags (OR logic)
const tagged = tracker.listVersions(['v1.0', 'v2.0']);
```
**Returns:** Array of versions, sorted newest first
#### getVersion(versionId: string): Version | null
Get a specific version by ID.
```typescript
const version = tracker.getVersion('version-id-here');
if (version) {
console.log(version.description);
console.log(version.changes.length);
}
```
#### compareVersions(fromId, toId): Promise<VersionDiff>
Generate a diff between two versions.
```typescript
const diff = await tracker.compareVersions(v1.id, v2.id);
console.log('Summary:', diff.summary);
// { additions: 5, deletions: 2, modifications: 3 }
diff.changes.forEach(change => {
console.log(`${change.type} at ${change.path}`);
if (change.type === ChangeType.MODIFICATION) {
console.log(` Before: ${change.before}`);
console.log(` After: ${change.after}`);
}
});
```
**Returns:** VersionDiff with:
- `fromVersion`: Source version ID
- `toVersion`: Target version ID
- `changes`: Array of changes
- `summary`: Count of additions/deletions/modifications
#### revertToVersion(versionId: string): Promise<Version>
Revert to a previous version (creates new version with inverse changes).
```typescript
// Revert to v1 state
const revertVersion = await tracker.revertToVersion(v1.id);
console.log('Created revert version:', revertVersion.id);
console.log('Description:', revertVersion.description);
// "Revert to version: {original description}"
```
**Important:** This creates a NEW version with inverse changes, preserving history.
**Events:** Emits `versionReverted` event
#### queryAtTimestamp(timestamp | options): Promise<any>
Perform a time-travel query to get database state at a specific point.
```typescript
// Query at specific timestamp
const yesterday = Date.now() - 86400000;
const pastState = await tracker.queryAtTimestamp(yesterday);
// Query at specific version
const stateAtV1 = await tracker.queryAtTimestamp({
versionId: v1.id
});
// Query with filters
const userNodesOnly = await tracker.queryAtTimestamp({
timestamp: Date.now(),
pathPattern: /^nodes\.User/, // Only User nodes
includeMetadata: true
});
```
**Options:**
- `timestamp`: Unix timestamp
- `versionId`: Specific version to query
- `pathPattern`: RegExp to filter paths
- `includeMetadata`: Include metadata in results
**Returns:** Reconstructed state object
#### addTags(versionId: string, tags: string[]): void
Add tags to an existing version.
```typescript
tracker.addTags(version.id, ['stable', 'tested', 'production']);
```
Tags are useful for:
- Release marking (`v1.0`, `v2.0`)
- Environment (`production`, `staging`)
- Status (`stable`, `experimental`)
- Features (`auth-enabled`, `new-ui`)
#### getVisualizationData(): VisualizationData
Get data for visualizing change history.
```typescript
const vizData = tracker.getVisualizationData();
// Timeline of all versions
vizData.timeline.forEach(item => {
console.log(`${new Date(item.timestamp).toISOString()}`);
console.log(` ${item.description}`);
console.log(` Changes: ${item.changeCount}`);
});
// Change frequency over time
vizData.changeFrequency.forEach(({ timestamp, count, type }) => {
console.log(`${timestamp}: ${count} ${type} changes`);
});
// Most frequently changed paths
vizData.hotspots.forEach(({ path, changeCount }) => {
console.log(`${path}: ${changeCount} changes`);
});
// Version graph (for D3.js, vis.js, etc.)
const graph = vizData.versionGraph;
// graph.nodes: [{ id, label, timestamp }]
// graph.edges: [{ from, to }]
```
**Returns:** VisualizationData with:
- `timeline`: Chronological version list
- `changeFrequency`: Changes over time
- `hotspots`: Most modified paths
- `versionGraph`: Parent-child relationships
#### getAuditLog(limit?: number): AuditLogEntry[]
Get audit trail of all operations.
```typescript
const recentLogs = tracker.getAuditLog(50);
recentLogs.forEach(entry => {
console.log(`[${entry.operation}] ${entry.status}`);
console.log(` By: ${entry.actor || 'system'}`);
console.log(` Details:`, entry.details);
if (entry.error) {
console.log(` Error: ${entry.error}`);
}
});
```
**Returns:** Array of audit entries, newest first
#### pruneVersions(keepCount, preserveTags?): void
Delete old versions to save space.
```typescript
// Keep last 10 versions + tagged ones
tracker.pruneVersions(10, ['baseline', 'production', 'stable']);
```
**Parameters:**
- `keepCount`: Number of recent versions to keep
- `preserveTags`: Tags to always preserve
**Safety:** Never deletes versions with dependencies
#### exportBackup(): BackupData
Export all data for backup.
```typescript
const backup = tracker.exportBackup();
// Save to file
import { writeFileSync } from 'fs';
writeFileSync('backup.json', JSON.stringify(backup));
console.log(`Backed up ${backup.versions.length} versions`);
console.log(`Exported at: ${new Date(backup.exportedAt).toISOString()}`);
```
**Returns:**
- `versions`: All version objects
- `auditLog`: Complete audit trail
- `currentState`: Current database state
- `exportedAt`: Export timestamp
#### importBackup(backup: BackupData): void
Import data from backup.
```typescript
import { readFileSync } from 'fs';
const backup = JSON.parse(readFileSync('backup.json', 'utf8'));
tracker.importBackup(backup);
console.log('Backup restored successfully');
```
**Warning:** Clears all existing data before import
#### getStorageStats(): StorageStats
Get storage statistics.
```typescript
const stats = tracker.getStorageStats();
console.log(`Versions: ${stats.versionCount}`);
console.log(`Changes: ${stats.totalChanges}`);
console.log(`Audit entries: ${stats.auditLogSize}`);
console.log(`Estimated size: ${(stats.estimatedSizeBytes / 1024).toFixed(2)} KB`);
console.log(`Date range: ${new Date(stats.oldestVersion).toISOString()} to ${new Date(stats.newestVersion).toISOString()}`);
```
## Event System
The tracker is an EventEmitter with the following events:
### versionCreated
Emitted when a new version is created.
```typescript
tracker.on('versionCreated', (version: Version) => {
console.log(`New version: ${version.id}`);
console.log(`Changes: ${version.changes.length}`);
// Send notification
notificationService.send(`Version ${version.description} created`);
});
```
### versionReverted
Emitted when reverting to a previous version.
```typescript
tracker.on('versionReverted', (fromVersion: string, toVersion: string) => {
console.log(`Reverted from ${fromVersion} to ${toVersion}`);
// Log critical event
logger.warn('Database reverted', { fromVersion, toVersion });
});
```
### changeTracked
Emitted when a change is tracked.
```typescript
tracker.on('changeTracked', (change: Change) => {
console.log(`Change: ${change.type} at ${change.path}`);
// Real-time monitoring
monitoringService.trackChange(change);
});
```
### auditLogged
Emitted when an audit entry is created.
```typescript
tracker.on('auditLogged', (entry: AuditLogEntry) => {
console.log(`Audit: ${entry.operation} - ${entry.status}`);
// Send to external audit system
auditSystem.log(entry);
});
```
### error
Emitted on errors.
```typescript
tracker.on('error', (error: Error) => {
console.error('Tracker error:', error);
// Error handling
errorService.report(error);
});
```
## Usage Patterns
### Pattern 1: Continuous Development
Track changes as you develop, create versions at milestones.
```typescript
// Development loop
function updateSchema(changes) {
changes.forEach(change => tracker.trackChange(change));
if (readyForRelease) {
await tracker.createVersion({
description: 'Release v2.1',
tags: ['v2.1', 'production']
});
}
}
```
### Pattern 2: Rollback Safety
Keep production-tagged versions for easy rollback.
```typescript
// Before risky change
const safePoint = await tracker.createVersion({
description: 'Safe point before migration',
tags: ['production', 'safe-point']
});
try {
// Risky operation
performMigration();
} catch (error) {
// Rollback on failure
await tracker.revertToVersion(safePoint.id);
console.log('Rolled back to safe state');
}
```
### Pattern 3: Change Analysis
Analyze what changed between releases.
```typescript
const prodVersions = tracker.listVersions(['production']);
const [current, previous] = prodVersions; // Newest first
const diff = await tracker.compareVersions(previous.id, current.id);
console.log('Changes in this release:');
console.log(` Added: ${diff.summary.additions}`);
console.log(` Modified: ${diff.summary.modifications}`);
console.log(` Deleted: ${diff.summary.deletions}`);
// Generate changelog
const changelog = diff.changes.map(c =>
`- ${c.type} ${c.path}`
).join('\n');
```
### Pattern 4: Audit Compliance
Maintain complete audit trail for compliance.
```typescript
// Track all changes with metadata
tracker.trackChange({
type: ChangeType.MODIFICATION,
path: 'sensitive.data',
before: oldValue,
after: newValue,
timestamp: Date.now(),
metadata: {
user: currentUser.id,
reason: 'GDPR request',
ticket: 'LEGAL-456'
}
});
// Export audit log monthly
const log = tracker.getAuditLog();
const monthlyLog = log.filter(e =>
e.timestamp >= startOfMonth && e.timestamp < endOfMonth
);
saveAuditReport('audit-2024-01.json', monthlyLog);
```
### Pattern 5: Time-Travel Debugging
Debug issues by examining past states.
```typescript
// Find when bug was introduced
const versions = tracker.listVersions();
for (const version of versions) {
const state = await tracker.queryAtTimestamp(version.timestamp);
if (hasBug(state)) {
console.log(`Bug present in version: ${version.description}`);
} else {
console.log(`Bug not present in version: ${version.description}`);
// Compare with next version to find the change
const nextVersion = versions[versions.indexOf(version) - 1];
if (nextVersion) {
const diff = await tracker.compareVersions(version.id, nextVersion.id);
console.log('Changes that introduced bug:', diff.changes);
}
break;
}
}
```
## Best Practices
### 1. Meaningful Descriptions
```typescript
// ❌ Bad
await tracker.createVersion({ description: 'Update' });
// ✅ Good
await tracker.createVersion({
description: 'Add email verification to user registration',
tags: ['feature', 'auth'],
metadata: { ticket: 'FEAT-123' }
});
```
### 2. Consistent Tagging
```typescript
// Establish tagging convention
const TAGS = {
PRODUCTION: 'production',
STAGING: 'staging',
FEATURE: 'feature',
BUGFIX: 'bugfix',
HOTFIX: 'hotfix'
};
await tracker.createVersion({
description: 'Fix critical auth bug',
tags: [TAGS.HOTFIX, TAGS.PRODUCTION, 'v2.1.1']
});
```
### 3. Regular Pruning
```typescript
// Prune monthly
setInterval(() => {
tracker.pruneVersions(
50, // Keep last 50 versions
['production', 'baseline', 'hotfix'] // Preserve important ones
);
}, 30 * 24 * 60 * 60 * 1000); // 30 days
```
### 4. Backup Before Major Changes
```typescript
async function majorMigration() {
// Backup first
const backup = tracker.exportBackup();
await saveBackup('pre-migration.json', backup);
// Create checkpoint
const checkpoint = await tracker.createVersion({
description: 'Pre-migration checkpoint',
tags: ['checkpoint', 'migration']
});
// Perform migration
try {
await performMigration();
} catch (error) {
await tracker.revertToVersion(checkpoint.id);
throw error;
}
}
```
### 5. Use Events for Integration
```typescript
// Integrate with monitoring
tracker.on('versionCreated', async (version) => {
await metrics.increment('versions.created');
await metrics.gauge('versions.total', tracker.listVersions().length);
});
// Integrate with notifications
tracker.on('versionReverted', async (from, to) => {
await slack.send(`⚠️ Database reverted from ${from} to ${to}`);
});
```
## Performance Considerations
### Memory Usage
- **In-Memory Storage**: All versions kept in memory
- **Recommendation**: Prune old versions regularly
- **Large Databases**: Consider periodic export/import
### Query Performance
- **Time Complexity**: O(n) where n = version chain length
- **Optimization**: Keep version chains short with pruning
- **Path Filtering**: O(1) lookup with path index
### Storage Size
- **Delta Encoding**: ~70-90% smaller than full snapshots
- **Compression**: Use `exportBackup()` with external compression
- **Estimate**: ~100 bytes per change on average
## TypeScript Support
Full TypeScript definitions included:
```typescript
import type {
TemporalTracker,
Change,
ChangeType,
Version,
VersionDiff,
AuditLogEntry,
CreateVersionOptions,
QueryOptions,
VisualizationData
} from 'ruvector-extensions';
```
## Examples
See `/src/examples/temporal-example.ts` for comprehensive examples covering:
- Basic version management
- Time-travel queries
- Version comparison
- Reverting
- Visualization data
- Audit logging
- Storage management
- Backup/restore
- Event-driven architecture
Run examples:
```bash
npm run build
node dist/examples/temporal-example.js
```
## License
MIT
## Support
- Issues: https://github.com/ruvnet/ruvector/issues
- Documentation: https://github.com/ruvnet/ruvector