Package Exports
- chronos-db
Readme
Chronos-DB 🚀
Enterprise-Grade MongoDB Persistence Layer with Embedded Multi-Tenancy & Big Data Architecture
🎯 Built for Big Data & Enterprise
Chronos-DB is designed for large-scale applications requiring tenant isolation, data versioning, and complex data relationships. Built with embedded multi-tenancy by design and tiered architecture to handle big data workloads efficiently.
🏢 Enterprise Features
- 🏢 Embedded Multi-Tenancy: Built-in tenant isolation with configurable database tiers
- 📊 Tiered Architecture: Separate metadata, knowledge, runtime, and logs databases
- ⚡ Big Data Ready: Optimized for high-volume operations with S3 integration
- 🔄 Time-Travel Queries: Full historical data access and point-in-time recovery
- 🔒 Enterprise Security: Row-level security with tenant-based data isolation
- 📈 Scalable Design: Horizontal scaling across multiple MongoDB clusters
📖 Overview
chronos-db
provides a production-ready persistence layer designed for enterprise applications and big data projects that combines:
- 🏢 Multi-Tenant Architecture: Built-in tenant isolation with configurable database tiers (metadata, knowledge, runtime, logs)
- 📊 MongoDB for indexed metadata, head pointers, and bounded recent version index
- ☁️ S3-compatible storage for authoritative payloads, full JSON per version
- 🔄 Automatic versioning with explicit restore capabilities and time-travel queries
- ⚡ Multi-backend routing with connection pooling for horizontal scaling
- 🔒 Transaction locking for concurrent write prevention across multiple servers
- 📈 Big Data Optimization: Efficient handling of large datasets with S3 integration
- 🎯 Tenant Isolation: Row-level security with configurable tenant boundaries
- Cheap analytics with conditional counters
- Enrichment API for incremental updates
- Fallback queues for guaranteed durability
- Write optimization for high-throughput scenarios
Key Principles
✅ No Environment Variables - All configuration via JSON
✅ Cost-First - Minimize storage and compute costs
✅ Stability-First - Immutable versioning, transactions, optimistic locking
✅ Concurrent-Safe - Transaction locking prevents multi-server write conflicts
✅ Portable - Works with any S3-compatible provider
✅ Type-Safe - Full TypeScript support with Zod validation
🏢 Multi-Tenant Architecture & Big Data Use Cases
Perfect for Enterprise Applications
Chronos-DB is specifically designed for large-scale, multi-tenant applications that need to handle:
- 🏢 SaaS Platforms: Multi-tenant applications with strict data isolation
- 📊 Analytics Platforms: Big data processing with time-series analysis
- 🔄 E-commerce Systems: High-volume transaction processing with audit trails
- 📈 Financial Services: Regulatory compliance with full data lineage
- 🎯 CRM Systems: Customer data management with relationship tracking
- 📱 IoT Platforms: Massive data ingestion with historical analysis
Tiered Database Architecture
Chronos-DB uses a sophisticated tiered approach to optimize for different data types:
// Multi-tier database configuration
databases: {
metadata: [ // System metadata, configurations, schemas
{ key: 'meta-prod', tenantId: 'system', dbName: 'chronos_metadata' }
],
knowledge: [ // Reference data, lookups, master data
{ key: 'knowledge-prod', tenantId: 'shared', dbName: 'chronos_knowledge' }
],
runtime: [ // Transactional data, user records, business data
{ key: 'runtime-tenant-a', tenantId: 'tenant-a', dbName: 'tenant_a_data' },
{ key: 'runtime-tenant-b', tenantId: 'tenant-b', dbName: 'tenant_b_data' }
],
logs: { // System logs, audit trails, monitoring
connection: { key: 'logs-prod', dbName: 'chronos_logs' }
}
}
Embedded Multi-Tenancy Benefits
- 🔒 Data Isolation: Each tenant's data is completely isolated
- 📈 Horizontal Scaling: Scale tenants independently across database clusters
- 💰 Cost Optimization: Efficient resource utilization per tenant
- 🛡️ Security: Row-level security with tenant-based access control
- ⚡ Performance: Optimized queries with tenant-specific routing
🚀 Quick Start
Installation
npm install chronos-db
Multi-Tenant Enterprise Setup
import { initChronos } from 'chronos-db';
const chronos = initChronos({
// MongoDB connections for different tiers
mongoConns: [
{ key: 'mongo-primary', mongoUri: 'mongodb://primary-cluster:27017' },
{ key: 'mongo-analytics', mongoUri: 'mongodb://analytics-cluster:27017' }
],
// Tiered database architecture
databases: {
metadata: [{
key: 'meta-prod',
mongoConnKey: 'mongo-primary',
tenantId: 'system',
dbName: 'chronos_metadata'
}],
knowledge: [{
key: 'knowledge-prod',
mongoConnKey: 'mongo-primary',
tenantId: 'shared',
dbName: 'chronos_knowledge'
}],
runtime: [
{
key: 'runtime-tenant-a',
mongoConnKey: 'mongo-primary',
spacesConnKey: 's3-prod',
tenantId: 'tenant-a',
dbName: 'tenant_a_data'
},
{
key: 'runtime-tenant-b',
mongoConnKey: 'mongo-primary',
spacesConnKey: 's3-prod',
tenantId: 'tenant-b',
dbName: 'tenant_b_data'
}
],
logs: {
connection: {
key: 'logs-prod',
mongoConnKey: 'mongo-analytics',
spacesConnKey: 's3-logs',
dbName: 'chronos_logs'
}
}
},
// S3 storage for big data
spacesConns: [{
key: 's3-prod',
endpoint: 'https://s3.amazonaws.com',
region: 'us-east-1',
accessKey: 'YOUR_ACCESS_KEY',
secretKey: 'YOUR_SECRET_KEY',
buckets: {
json: 'chronos-json-prod',
content: 'chronos-content-prod',
versions: 'chronos-versions-prod',
backup: 'chronos-backups-prod'
}
}],
// Enterprise configuration
routing: { hashAlgo: 'rendezvous' },
retention: { ver: { days: 90 }, counters: { days: 30 } },
collectionMaps: {
users: { indexedProps: ['email', 'tenantId'] },
orders: { indexedProps: ['orderId', 'customerId', 'tenantId'] }
}
});
// Multi-tenant operations
const tenantAOps = chronos.with({
key: 'runtime-tenant-a',
collection: 'users'
});
const tenantBOps = chronos.with({
key: 'runtime-tenant-b',
collection: 'users'
});
// Create users in different tenants
await tenantAOps.create({ email: 'user@tenant-a.com', name: 'User A' });
await tenantBOps.create({ email: 'user@tenant-b.com', name: 'User B' });
🏢 Multi-Tenant Usage
For complex multi-tenant architectures with multiple database types and tiers:
import { initChronos } from 'chronos-db';
const chronos = initChronos({
mongoConns: [
{ key: 'mongo-cluster-a', mongoUri: 'mongodb+srv://user:pass@cluster-a.mongodb.net' },
{ key: 'mongo-cluster-b', mongoUri: 'mongodb+srv://user:pass@cluster-b.mongodb.net' }
],
databases: {
metadata: [
{ key: 'meta-domain1', mongoConnKey: 'mongo-cluster-a', spacesConnKey: 'aws-us-east', tenantId: 'domain1', dbName: 'metadata_domain1' },
{ key: 'meta-tenant-a', mongoConnKey: 'mongo-cluster-b', spacesConnKey: 'aws-us-east', tenantId: 'tenant-a', dbName: 'metadata_tenant_a' }
],
knowledge: [
{ key: 'know-domain1', mongoConnKey: 'mongo-cluster-a', spacesConnKey: 'aws-us-east', tenantId: 'domain1', dbName: 'knowledge_domain1' },
{ key: 'know-tenant-a', mongoConnKey: 'mongo-cluster-b', spacesConnKey: 'aws-us-east', tenantId: 'tenant-a', dbName: 'knowledge_tenant_a' }
],
runtime: [
{ key: 'runtime-domain1', mongoConnKey: 'mongo-cluster-a', spacesConnKey: 'aws-us-east', tenantId: 'domain1', dbName: 'runtime_domain1' },
{ key: 'runtime-tenant-a', mongoConnKey: 'mongo-cluster-b', spacesConnKey: 'aws-us-east', tenantId: 'tenant-a', dbName: 'runtime_tenant_a' }
],
logs: {
connection: { key: 'logs-main', mongoConnKey: 'mongo-cluster-a', spacesConnKey: 'aws-us-east', dbName: 'chronos_logs' }
}
},
spacesConns: [{
key: 'aws-us-east',
endpoint: 'https://s3.us-east-1.amazonaws.com',
region: 'us-east-1',
accessKey: 'YOUR_AWS_ACCESS_KEY',
secretKey: 'YOUR_AWS_SECRET_KEY',
buckets: {
json: 'chronos-json-us-east',
content: 'chronos-content-us-east',
versions: 'chronos-versions-us-east',
backup: 'chronos-backups-us-east'
}
}],
counters: { mongoUri: 'mongodb+srv://user:pass@cluster-metrics.mongodb.net', dbName: 'chronos_counters' },
routing: { hashAlgo: 'rendezvous' },
retention: {},
rollup: {},
});
// Option A: Direct key usage (simplest)
const ops = chronos.with({
key: 'runtime-tenant-a', // Unique key, automatically resolves everything
collection: 'users'
});
// Option B: Tenant-based routing
const ops2 = chronos.with({
databaseType: 'runtime',
tenantId: 'tenant-a', // Maps to tenant-specific database
collection: 'users'
});
// Option C: Logs database (no tiers)
const ops3 = chronos.with({
key: 'logs-main',
collection: 'audit'
});
await ops.create({ email: 'user@example.com' });
await ops2.create({ email: 'user2@example.com' });
await ops3.create({ event: 'user_login', timestamp: new Date() });
📊 Big Data Capabilities & Performance
Designed for High-Volume Operations
Chronos-DB is optimized for big data scenarios with enterprise-grade performance features:
- ⚡ High-Throughput: Optimized for millions of operations per day
- 📈 Horizontal Scaling: Distribute load across multiple MongoDB clusters
- ☁️ S3 Integration: Efficient storage of large datasets and files
- 🔄 Batch Operations: Bulk processing with write optimization
- 📊 Analytics Ready: Built-in counters and metrics for business intelligence
- 💾 Cost Optimization: Intelligent data lifecycle management
Big Data Use Cases
// High-volume data ingestion
const batchOps = chronos.with({ key: 'runtime-analytics', collection: 'events' });
// Bulk insert for IoT data
const events = Array.from({ length: 10000 }, (_, i) => ({
deviceId: `device-${i}`,
timestamp: new Date(),
temperature: Math.random() * 100,
humidity: Math.random() * 100
}));
// Batch processing with enrichment
for (const event of events) {
await batchOps.create(event, 'iot-ingestion', 'sensor-data');
}
// Time-series analysis
const historicalData = await batchOps.query(
{ deviceId: 'device-123' },
{
at: '2024-01-01T00:00:00Z',
sort: { timestamp: 1 },
limit: 1000
}
);
// Analytics with counters
const metrics = await chronos.counters.getTotals('events', {
deviceId: 'device-123',
dateRange: { from: '2024-01-01', to: '2024-01-31' }
});
Performance Optimizations
- 🚀 Write Optimization: Batch S3 operations and debounced counters
- 💾 Smart Caching: Dev shadow for frequently accessed data
- 📦 Data Compression: Automatic rollup of old versions
- 🔄 Connection Pooling: Efficient MongoDB connection management
- ⚡ Index Optimization: Configurable indexing for query performance
⚙️ Configuration Reference
Basic Configuration
interface ChronosConfig {
// Required: MongoDB connections (define once, reference by key)
mongoConns: MongoConnConfig[];
// Required: Database configuration (can have empty sections)
databases: {
metadata?: DatabaseConnection[];
knowledge?: DatabaseConnection[];
runtime?: DatabaseConnection[];
logs?: LogsDatabaseConfig;
};
// Optional: S3-compatible storage (if not using localStorage)
spacesConns?: SpacesConnConfig[];
// Optional: Local filesystem storage (for development/testing)
localStorage?: {
basePath: string;
enabled: boolean;
};
// Required: Counters database
counters: {
mongoUri: string;
dbName: string;
};
// Optional: Routing configuration
routing?: {
hashAlgo?: 'rendezvous' | 'jump';
chooseKey?: string | ((ctx: RouteContext) => string);
};
// Optional: Data retention policies
retention?: {
ver?: {
days?: number;
maxPerItem?: number;
};
counters?: {
days?: number;
weeks?: number;
months?: number;
};
};
// Optional: Data rollup configuration
rollup?: any;
// Optional: Collection mapping and validation
collectionMaps?: Record<string, {
indexedProps: string[]; // Empty array = auto-index all properties
base64Props?: Record<string, {
contentType: string;
preferredText?: boolean;
textCharset?: string;
}>;
validation?: {
requiredIndexed?: string[];
};
}>;
// Optional: Counter rules
counterRules?: {
rules?: Array<{
name: string;
on?: ('CREATE' | 'UPDATE' | 'DELETE')[];
scope?: 'meta' | 'payload';
when: Record<string, any>;
}>;
};
// Optional: Development shadow storage
devShadow?: {
enabled: boolean;
ttlHours: number;
maxBytesPerDoc?: number;
};
// Optional: Logical delete (default: enabled)
logicalDelete?: {
enabled: boolean; // Set to false for hard deletes (default: true)
};
// Optional: Versioning (default: enabled)
versioning?: {
enabled: boolean; // Set to false to disable time-travel (default: true)
};
// Optional: Hard delete capability
hardDeleteEnabled?: boolean;
// Optional: Fallback queue configuration
fallback?: {
enabled: boolean;
maxRetries?: number;
retryDelayMs?: number;
maxDelayMs?: number;
deadLetterCollection?: string;
};
// Optional: Write optimization
writeOptimization?: any;
// Optional: Transaction configuration
transactions?: {
enabled?: boolean;
autoDetect?: boolean;
};
}
interface MongoConnConfig {
key: string; // Unique key for referencing this connection
mongoUri: string; // MongoDB connection URI
}
interface DatabaseConnection {
key: string; // Globally unique identifier for direct routing
mongoConnKey: string; // References a connection in mongoConns array
dbName: string; // Database name
tenantId?: string; // Optional tenant ID for mapping
spacesConnKey?: string; // References a connection in spacesConns array
}
interface LogsDatabaseConfig {
connection: DatabaseConnection; // Single connection for logs (no tiers)
}
interface SpacesConnConfig {
key: string; // Unique key for referencing this S3 connection
endpoint: string; // S3 endpoint URL
region: string; // AWS region
accessKey: string; // Access key
secretKey: string; // Secret key
buckets: {
json: string; // Bucket for JSON data (chronos-jsons)
content: string; // Bucket for content files
versions: string; // Bucket for versions/manifests
backup?: string; // Bucket for backups (optional - can reuse json bucket)
};
forcePathStyle?: boolean; // Force path style (for MinIO)
}
Multi-Tenant Architecture Explained
interface EnhancedChronosConfig extends ChronosConfig {
// Optional: Enhanced multi-tenant database configuration
databaseTypes?: {
metadata?: DatabaseTypeConfig;
knowledge?: DatabaseTypeConfig;
runtime?: DatabaseTypeConfig;
};
}
interface DatabaseTypeConfig {
generic: DatabaseConnection;
domains: DatabaseConnection[];
tenants: DatabaseConnection[];
}
interface DatabaseConnection {
key: string; // Unique identifier
mongoUri: string; // MongoDB connection URI
dbName: string; // Database name
extIdentifier?: string; // External identifier for mapping
}
Multi-Tenant Architecture Explained
Database Types
metadata
- System configuration, user settings, application metadataknowledge
- Content, documents, knowledge base, static dataruntime
- User data, transactions, dynamic application data
Tiers
generic
- Shared across all tenants (system-wide data)domain
- Shared within a domain (multi-tenant within domain)tenant
- Isolated per tenant (single-tenant data)
Keys vs ExtIdentifiers
key
- Globally unique identifier for direct routing (e.g.,"runtime-tenant-a"
)extIdentifier
- External, non-unique identifier for mapping (e.g.,"tenant-a"
)
Usage Patterns
Option A: Direct Key Usage (Simplest)
const ops = chronos.with({
key: 'runtime-tenant-a', // Direct lookup, no resolution needed
collection: 'users'
});
Option B: Tier + ExtIdentifier Usage
const ops = chronos.with({
databaseType: 'runtime', // metadata | knowledge | runtime
tier: 'tenant', // generic | domain | tenant
extIdentifier: 'tenant-a', // Maps to key: 'runtime-tenant-a'
collection: 'users'
});
Option C: Generic Tier (No ExtIdentifier)
const ops = chronos.with({
databaseType: 'metadata',
tier: 'generic', // No extIdentifier needed
collection: 'config'
});
Complete Multi-Tenant Example
const chronos = initChronos({
mongoUris: [
// Metadata databases
'mongodb://meta-generic:27017',
'mongodb://meta-domain1:27017',
'mongodb://meta-tenant-a:27017',
'mongodb://meta-tenant-b:27017',
// Knowledge databases
'mongodb://know-generic:27017',
'mongodb://know-domain1:27017',
'mongodb://know-tenant-a:27017',
'mongodb://know-tenant-b:27017',
// Runtime databases
'mongodb://runtime-generic:27017',
'mongodb://runtime-domain1:27017',
'mongodb://runtime-tenant-a:27017',
'mongodb://runtime-tenant-b:27017'
],
spacesConns: [/* S3 config */],
counters: { mongoUri: 'mongodb://localhost:27017', dbName: 'chronos_counters' },
routing: { hashAlgo: 'rendezvous' },
retention: {},
rollup: {},
databaseTypes: {
metadata: {
generic: {
key: 'meta-generic',
mongoUri: 'mongodb://meta-generic:27017',
dbName: 'meta_generic'
},
domains: [
{
key: 'meta-domain-1',
extIdentifier: 'domain-1',
mongoUri: 'mongodb://meta-domain1:27017',
dbName: 'meta_domain_1'
}
],
tenants: [
{
key: 'meta-tenant-a',
extIdentifier: 'tenant-a',
mongoUri: 'mongodb://meta-tenant-a:27017',
dbName: 'meta_tenant_a'
},
{
key: 'meta-tenant-b',
extIdentifier: 'tenant-b',
mongoUri: 'mongodb://meta-tenant-b:27017',
dbName: 'meta_tenant_b'
}
]
},
knowledge: {
generic: {
key: 'know-generic',
mongoUri: 'mongodb://know-generic:27017',
dbName: 'know_generic'
},
domains: [
{
key: 'know-domain-1',
extIdentifier: 'domain-1',
mongoUri: 'mongodb://know-domain1:27017',
dbName: 'know_domain_1'
}
],
tenants: [
{
key: 'know-tenant-a',
extIdentifier: 'tenant-a',
mongoUri: 'mongodb://know-tenant-a:27017',
dbName: 'know_tenant_a'
},
{
key: 'know-tenant-b',
extIdentifier: 'tenant-b',
mongoUri: 'mongodb://know-tenant-b:27017',
dbName: 'know_tenant_b'
}
]
},
runtime: {
generic: {
key: 'runtime-generic',
mongoUri: 'mongodb://runtime-generic:27017',
dbName: 'runtime_generic'
},
domains: [
{
key: 'runtime-domain-1',
extIdentifier: 'domain-1',
mongoUri: 'mongodb://runtime-domain1:27017',
dbName: 'runtime_domain_1'
}
],
tenants: [
{
key: 'runtime-tenant-a',
extIdentifier: 'tenant-a',
mongoUri: 'mongodb://runtime-tenant-a:27017',
dbName: 'runtime_tenant_a'
},
{
key: 'runtime-tenant-b',
extIdentifier: 'tenant-b',
mongoUri: 'mongodb://runtime-tenant-b:27017',
dbName: 'runtime_tenant_b'
}
]
}
}
});
// Usage Examples:
// 1. Direct key usage (fastest)
const tenantAUsers = chronos.with({
key: 'runtime-tenant-a',
collection: 'users'
});
// 2. Tier + extIdentifier usage (flexible)
const tenantAUsers2 = chronos.with({
databaseType: 'runtime',
tier: 'tenant',
extIdentifier: 'tenant-a', // Resolves to 'runtime-tenant-a'
collection: 'users'
});
// 3. Generic tier (shared data)
const systemConfig = chronos.with({
databaseType: 'metadata',
tier: 'generic',
collection: 'config'
});
// 4. Domain tier (shared within domain)
const domainContent = chronos.with({
databaseType: 'knowledge',
tier: 'domain',
extIdentifier: 'domain-1', // Resolves to 'know-domain-1'
collection: 'articles'
});
// Operations work the same regardless of routing method
await tenantAUsers.create({ email: 'user@tenant-a.com' });
await tenantAUsers2.create({ email: 'user2@tenant-a.com' });
await systemConfig.create({ setting: 'global_value' });
await domainContent.create({ title: 'Shared Article' });
S3 Configuration
interface SpacesConnConfig {
endpoint: string; // S3 endpoint URL
region: string; // S3 region
accessKey: string; // Access key
secretKey: string; // Secret key
backupsBucket: string; // Backups bucket name
jsonBucket: string; // JSON storage bucket name
contentBucket: string; // Content storage bucket name
forcePathStyle?: boolean; // Force path-style URLs
}
Configuration Examples
Minimal Configuration (localStorage)
const chronos = initChronos({
mongoUris: ['mongodb://localhost:27017'],
localStorage: { enabled: true, basePath: './data' },
counters: { mongoUri: 'mongodb://localhost:27017', dbName: 'chronos_counters' },
routing: { hashAlgo: 'rendezvous' },
retention: {},
rollup: {},
});
Production Configuration (S3)
const chronos = initChronos({
mongoUris: ['mongodb://prod1:27017', 'mongodb://prod2:27017'],
spacesConns: [{
endpoint: 'https://nyc3.digitaloceanspaces.com',
region: 'nyc3',
accessKey: 'YOUR_ACCESS_KEY',
secretKey: 'YOUR_SECRET_KEY',
backupsBucket: 'chronos-backups',
jsonBucket: 'chronos-json',
contentBucket: 'chronos-content',
}],
counters: { mongoUri: 'mongodb://prod1:27017', dbName: 'chronos_counters' },
routing: { hashAlgo: 'rendezvous' },
retention: {
ver: { days: 30, maxPerItem: 100 },
counters: { days: 7, weeks: 4, months: 12 }
},
rollup: {},
collectionMaps: {
users: {
indexedProps: ['email', 'status'],
validation: { requiredIndexed: ['email'] }
}
},
devShadow: { enabled: true, ttlHours: 24 },
fallback: {
enabled: true,
maxRetries: 3,
retryDelayMs: 1000,
maxDelayMs: 60000,
deadLetterCollection: 'chronos_fallback_dead'
},
transactions: { enabled: true, autoDetect: true }
});
🎯 Core Features
1. CRUD Operations
Full transaction support with optimistic locking:
// Create with automatic versioning (ov=0)
const created = await ops.create(data, 'actor', 'reason');
// Returns: { id, ov: 0, cv: 0, createdAt }
// Update with optimistic lock
const updated = await ops.update(id, newData, expectedOv, 'actor', 'reason');
// Returns: { id, ov: 1, cv: 1, updatedAt }
// Logical delete (default)
const deleted = await ops.delete(id, expectedOv, 'actor', 'reason');
// Returns: { id, ov: 2, cv: 2, deletedAt }
2. Enrichment API
Incrementally augment records without full rewrite:
// Deep merge with array union
await ops.enrich(id, {
tags: ['premium'], // Arrays unioned
metadata: { newField: 'value' }, // Objects deep merged
}, {
functionId: 'enricher@v1', // Provenance tracking
actor: 'system',
reason: 'automated enrichment',
});
// Batch enrichment
await ops.enrich(id, [
{ tags: ['vip'] },
{ metadata: { score: 100 } },
{ tags: ['verified'] },
]);
3. Read Operations
Multiple read strategies with presigned URL support:
// Get latest version
const latest = await ops.getLatest(id, {
presign: true,
ttlSeconds: 3600,
projection: ['email', 'status'],
});
// Get specific version
const v1 = await ops.getVersion(id, 1);
// Get as of time
const historical = await ops.getAsOf(id, '2025-09-01T00:00:00Z');
// List by metadata with pagination
const results = await ops.listByMeta({
filter: { status: 'active' },
limit: 50,
afterId: lastId,
sort: { updatedAt: -1 },
}, { presign: true });
4. Restore Operations
Explicit, append-only restore:
// Restore object to specific version
await ops.restoreObject(id, { ov: 5 });
// or by time
await ops.restoreObject(id, { at: '2025-09-01T00:00:00Z' });
// Restore entire collection
await ops.restoreCollection({ cv: 100 });
// or by time
await ops.restoreCollection({ at: '2025-09-01T00:00:00Z' });
5. Counters & Analytics
Cheap, always-on totals:
// Configure conditional counters
const config = {
// ... other config
counterRules: {
rules: [
{
name: 'activeUsers',
when: { status: 'active' },
on: ['CREATE', 'UPDATE'],
scope: 'meta',
},
],
},
};
// Query totals
const totals = await chronos.counters.getTotals({
dbName: 'myapp',
collection: 'users',
});
// Returns:
// {
// created: 1000,
// updated: 500,
// deleted: 50,
// activeUsers: 750,
// }
6. Fallback Queues
Guaranteed durability with automatic retry:
// Enable fallback queues
const config = {
// ... other config
fallback: {
enabled: true,
maxAttempts: 10,
baseDelayMs: 2000,
maxDelayMs: 60000,
deadLetterCollection: 'chronos_fallback_dead',
},
};
// Start worker for automatic retries
await chronos.fallback?.startWorker();
// Monitor queue
const stats = await chronos.fallback?.getQueueStats();
console.log('Pending ops:', stats.queueSize);
console.log('Dead letters:', stats.deadLetterSize);
// Retry dead letter operation
const deadLetters = await chronos.fallback?.getDeadLetterOps({}, 10);
for (const op of deadLetters) {
await chronos.fallback?.retryDeadLetter(op._id.toString());
}
// Stop worker
await chronos.fallback?.stopWorker();
7. Transaction Locking
Prevent concurrent writes across multiple servers:
// Automatic transaction locking on all write operations
// No additional configuration needed - works out of the box
// Create operation - automatically acquires lock on item
const result = await ops.create(data, 'actor', 'reason');
// Update operation - automatically acquires lock on item
await ops.update(id, newData, expectedOv, 'actor', 'reason');
// Delete operation - automatically acquires lock on item
await ops.delete(id, expectedOv, 'actor', 'reason');
// Locks are automatically released after operation completes
// If operation fails, locks are cleaned up automatically
// Expired locks (30s timeout) are cleaned up periodically
How it works:
- Each write operation acquires an exclusive lock on the item
- Locks are stored in MongoDB with automatic expiration
- Multiple servers can run simultaneously without conflicts
- Failed transactions are automatically recovered via queue system
8. System Fields & State Management
Every record includes comprehensive system tracking:
{
"_system": {
"insertedAt": "2025-10-01T12:00:00Z",
"updatedAt": "2025-10-01T12:30:00Z",
"deletedAt": "2025-10-01T13:00:00Z",
"deleted": false,
"functionIds": ["scorer@v1", "enricher@v2"],
"state": "new" // NEW: Data sync and TTL state
}
}
State Values:
"new-not-synched"
- Data exists only in MongoDB record, not synced to JSON storage"new"
- Data is synced to JSON storage but hasn't passed TTL"processed"
- Data has passed TTL, some data may only exist in JSON storage
State Management:
// Mark items as processed based on TTL expiration
const result = await chronos.admin.markItemsAsProcessedByTTL(
{ dbName: 'myapp', collection: 'users' },
24, // TTL in hours
{ confirm: true, dryRun: false }
);
// Mark specific item as processed
const marked = await chronos.admin.markItemAsProcessed(
{ dbName: 'myapp', collection: 'users' },
'item-id',
{ confirm: true }
);
9. Collection Maps & Auto-Indexing
chronos-db supports flexible collection mapping with automatic indexing:
// Option 1: No collection map - all properties are automatically indexed
const chronos = initChronos({
mongoUris: ['mongodb://localhost:27017'],
localStorage: { enabled: true, basePath: './data' },
// No collectionMaps defined - all properties are indexed automatically
});
// Option 2: Explicit collection map for specific collections
const chronos = initChronos({
mongoUris: ['mongodb://localhost:27017'],
localStorage: { enabled: true, basePath: './data' },
collectionMaps: {
users: {
indexedProps: ['email', 'status'], // Only these are indexed
validation: {
requiredIndexed: ['email'], // Required fields
},
},
// Other collections without maps will auto-index all properties
},
});
Auto-Indexing Behavior:
- No collection map: All properties are automatically indexed (except
_system
) - Empty
indexedProps
: All properties are indexed - Specified
indexedProps
: Only listed properties are indexed - Required fields: Only validated if explicitly defined
Benefits:
- ✅ Zero configuration for simple use cases
- ✅ Gradual adoption - add maps only when needed
- ✅ Full control when required for complex schemas
- ✅ Performance optimization - index only what you need
10. Admin API & DigitalOcean Spaces Integration
Comprehensive admin tools for production management:
// Test S3 connectivity
const connectivity = await chronos.admin.testS3Connectivity({
dbName: 'myapp',
collection: 'users'
});
if (connectivity.success) {
console.log('Available buckets:', connectivity.buckets);
} else {
console.log('Connectivity issue:', connectivity.error);
}
// Validate DigitalOcean Spaces configuration
const validation = await chronos.admin.validateSpacesConfiguration({
dbName: 'myapp',
collection: 'users'
});
if (!validation.valid) {
console.log('Issues:', validation.issues);
console.log('Recommendations:', validation.recommendations);
}
// Ensure required buckets exist (with auto-creation)
const bucketResult = await chronos.admin.ensureBucketsExist(
{ dbName: 'myapp', collection: 'users' },
{
confirm: true,
createIfMissing: true,
dryRun: false
}
);
console.log(`Checked ${bucketResult.bucketsChecked} buckets`);
console.log(`Created ${bucketResult.bucketsCreated} buckets`);
// State management for TTL processing
const stateResult = await chronos.admin.markItemsAsProcessedByTTL(
{ dbName: 'myapp', collection: 'users' },
24, // TTL in hours
{ confirm: true, dryRun: false }
);
console.log(`Processed ${stateResult.itemsProcessed} items`);
Admin Functions:
testS3Connectivity()
- Test S3 credentials and list bucketsvalidateSpacesConfiguration()
- Validate DigitalOcean Spaces setupensureBucketsExist()
- Check and create required bucketsmarkItemsAsProcessedByTTL()
- Process items based on TTL expirationmarkItemAsProcessed()
- Mark specific item as processed
🏗️ Architecture
Data Flow
┌─────────────┐
│ Client │
└──────┬──────┘
│
▼
┌─────────────────────────────────┐
│ Unified Data Manager (UDM) │
│ ┌───────────────────────────┐ │
│ │ Router (HRW Hashing) │ │
│ └───────────────────────────┘ │
│ │ │ │
│ ▼ ▼ │
│ ┌──────────┐ ┌──────────┐ │
│ │ Mongo │ │ S3 │ │
│ │ (Indexed)│ │(Payloads)│ │
│ └──────────┘ └──────────┘ │
│ │
│ ┌───────────────────────────┐ │
│ │ Fallback Queue (Optional)│ │
│ └───────────────────────────┘ │
└─────────────────────────────────┘
MongoDB Collections
<collection>_head
- Latest state pointers<collection>_ver
- Immutable version index<collection>_counter
- Collection version counter<collection>_locks
- Transaction locks for concurrent write preventioncnt_total
- Counter totals (in separate DB)chronos_fallback_ops
- Fallback queue (if enabled)chronos_fallback_dead
- Dead letter queue (if enabled)
S3 Storage Layout
<jsonBucket>/
<collection>/
<itemId>/
v0/item.json
v1/item.json
v2/item.json
<contentBucket>/
<collection>/
<itemId>/
v0/
<property>/blob.bin
<property>/text.txt
v1/
<property>/blob.bin
🔐 Production Deployment
MongoDB Replica Set (REQUIRED)
⚠️ MongoDB MUST run as a 3-node replica set in production
# Example docker-compose.yml
services:
mongo1:
image: mongo:6
command: mongod --replSet rs0
mongo2:
image: mongo:6
command: mongod --replSet rs0
mongo3:
image: mongo:6
command: mongod --replSet rs0
Connection string:
mongodb://mongo1:27017,mongo2:27017,mongo3:27017/dbname?replicaSet=rs0
S3-Compatible Providers
Tested with:
- ✅ AWS S3
- ✅ DigitalOcean Spaces
- ✅ MinIO
- ✅ Cloudflare R2
📚 Documentation
- Implementation Status - Complete feature matrix
- Configuration Guide - Detailed configuration
- Architecture Plan - Master workplan
- Extensions - System fields & shadows
- Enrichment API - Deep merge semantics
- DigitalOcean Spaces Integration - Complete setup guide
- DigitalOcean Troubleshooting - Credential and permission issues
🤝 Contributing
Contributions welcome! Please ensure:
- TypeScript compilation passes
- Documentation is updated
- Changes are backward compatible
📄 License
MIT © nx-intelligence
🙏 Credits
Built with:
- MongoDB - Document database
- AWS SDK - S3-compatible storage
- TypeScript - Type safety
- Zod - Schema validation
- tsup - Build system
📋 Frequently Asked Questions (FAQs)
Q: What's the difference between the old and new configuration structure?
A: The new structure (v1.5+) uses a simplified key-based mapping system:
- Old:
mongoUris
array +databaseTypes
with nested tiers - New:
mongoConns
array +databases
with direct arrays +key
/mongoConnKey
/spacesConnKey
mapping - Benefits: More flexible, reusable connections, explicit relationships, easier maintenance
Q: When should I use direct keys vs tenant-based routing?
A:
- Direct keys (
key: 'runtime-tenant-a'
) - Use when you know the exact database connection and want maximum performance - Tenant-based routing (
databaseType: 'runtime', tenantId: 'tenant-a'
) - Use when you want to route based on tenant context - Logs database (
key: 'logs-main'
) - Use for system logs and audit trails (no tiers)
Q: How do I disable logical delete and use hard deletes instead?
A: Set logicalDelete.enabled: false
in your configuration:
const chronos = initChronos({
// ... other config
logicalDelete: {
enabled: false // This will perform hard deletes instead of logical deletes
}
});
Q: How do I disable versioning to save storage space?
A: Set versioning.enabled: false
in your configuration:
const chronos = initChronos({
// ... other config
versioning: {
enabled: false // This disables time-travel queries and version storage
}
});
Q: What's the difference between logical delete and hard delete?
A:
- Logical delete (default): Sets
deletedAt
timestamp, records remain in database but are hidden from queries - Hard delete: Permanently removes records from both MongoDB and S3 storage
- Hard delete capability: Enables the
admin.hardDelete()
API for irreversible deletion
Q: Can I mix different routing methods in the same application?
A: Yes! You can use different routing methods for different operations:
// Direct key for critical operations
const criticalOps = chronos.with({ key: 'runtime-tenant-a', collection: 'payments' });
// Tier-based for flexible operations
const flexibleOps = chronos.with({
databaseType: 'runtime',
tier: 'tenant',
extIdentifier: 'tenant-a',
collection: 'users'
});
Q: What happens if I don't provide a collection map?
A: If no collection map is defined, chronos-db automatically indexes all properties (except _system
). This is called "auto-indexing" and is perfect for rapid prototyping and simple use cases.
Q: How does the state field work with TTL?
A: The state
field tracks data lifecycle:
"new-not-synched"
- Data exists only in MongoDB record"new"
- Data is synced to JSON storage but hasn't passed TTL"processed"
- Data has passed TTL, some data may only exist in JSON storage
Use markItemsAsProcessedByTTL()
to transition states based on TTL expiration.
Q: Can I use chronos-db without S3?
A: Yes! Use localStorage
for development/testing:
const chronos = initChronos({
mongoUris: ['mongodb://localhost:27017'],
localStorage: { enabled: true, basePath: './data' },
counters: { mongoUri: 'mongodb://localhost:27017', dbName: 'chronos_counters' },
routing: { hashAlgo: 'rendezvous' },
retention: {},
rollup: {},
});
Q: How do I handle failed operations?
A: Enable fallback queues for automatic retry:
const chronos = initChronos({
// ... other config
fallback: {
enabled: true,
maxRetries: 3,
retryDelayMs: 1000,
maxDelayMs: 60000,
deadLetterCollection: 'chronos_fallback_dead'
}
});
Q: What's the difference between hard delete and soft delete?
A:
- Soft delete (default) - Sets
deleted: true
anddeletedAt
timestamp, data remains recoverable - Hard delete - Permanently removes data from both MongoDB and S3 (enable with
hardDeleteEnabled: true
)
Q: How do I monitor chronos-db performance?
A: Use the admin API for monitoring:
// Health check
const health = await chronos.admin.health();
// Backend information
const backends = await chronos.admin.listBackends();
// Counter analytics
const totals = await chronos.counters.getTotals({ dbName: 'myapp', collection: 'users' });
Q: Can I use chronos-db with DigitalOcean Spaces?
A: Yes! DigitalOcean Spaces is S3-compatible. Use the admin API to validate your configuration:
const validation = await chronos.admin.validateSpacesConfiguration({
dbName: 'myapp',
collection: 'users'
});
if (!validation.valid) {
console.log('Issues:', validation.issues);
console.log('Recommendations:', validation.recommendations);
}
📊 Logging & Monitoring with logs-gateway
chronos-db integrates seamlessly with logs-gateway for comprehensive logging and monitoring:
Structured Logging
chronos-db uses structured logging that works perfectly with logs-gateway:
import { logger } from 'chronos-db';
// All chronos-db operations automatically log structured data
const result = await ops.create({ email: 'user@example.com' });
// Logs include:
// - Operation type (CREATE, UPDATE, DELETE)
// - Collection and database information
// - Routing decisions
// - Performance metrics
// - Error details (if any)
Log Categories
chronos-db generates logs in these categories:
1. Operation Logs
{
"level": "info",
"category": "chronos-operation",
"operation": "CREATE",
"collection": "users",
"dbName": "myapp",
"tenantId": "tenant-a",
"duration": 45,
"timestamp": "2024-01-15T10:30:00Z"
}
2. Routing Logs
{
"level": "debug",
"category": "chronos-routing",
"method": "getRouteInfo",
"ctx": {
"dbName": "myapp",
"collection": "users",
"key": "runtime-tenant-a"
},
"index": 2,
"backend": "mongodb://runtime-tenant-a:27017",
"routingKey": "runtime-tenant-a",
"resolvedDbName": "runtime_tenant_a"
}
3. Performance Logs
{
"level": "info",
"category": "chronos-performance",
"operation": "bulkCreate",
"itemsCount": 100,
"duration": 1250,
"avgPerItem": 12.5,
"timestamp": "2024-01-15T10:30:00Z"
}
4. Error Logs
{
"level": "error",
"category": "chronos-error",
"operation": "UPDATE",
"error": "OptimisticLockError",
"message": "Version mismatch: expected 5, got 3",
"collection": "users",
"itemId": "507f1f77bcf86cd799439011",
"timestamp": "2024-01-15T10:30:00Z"
}
logs-gateway Integration
Configure logs-gateway to capture chronos-db logs:
// logs-gateway configuration
const logsGateway = new LogsGateway({
sources: [
{
name: 'chronos-db',
patterns: [
'chronos-operation:*',
'chronos-routing:*',
'chronos-performance:*',
'chronos-error:*'
],
processors: [
'chronos-performance-analyzer',
'chronos-error-aggregator',
'chronos-routing-optimizer'
]
}
],
outputs: [
{
type: 'elasticsearch',
index: 'chronos-logs-{YYYY.MM.DD}'
},
{
type: 'grafana',
dashboard: 'chronos-db-monitoring'
}
]
});
Custom Logging
Add custom logging to your chronos-db operations:
// Custom operation logging
const ops = chronos.with({
key: 'runtime-tenant-a',
collection: 'users'
});
// Wrap operations with custom logging
const createUser = async (userData) => {
const startTime = Date.now();
try {
logger.info('chronos-operation:CREATE:START', {
collection: 'users',
tenantId: 'tenant-a',
userData: { email: userData.email } // Don't log sensitive data
});
const result = await ops.create(userData);
logger.info('chronos-operation:CREATE:SUCCESS', {
collection: 'users',
tenantId: 'tenant-a',
itemId: result.id,
duration: Date.now() - startTime
});
return result;
} catch (error) {
logger.error('chronos-operation:CREATE:ERROR', {
collection: 'users',
tenantId: 'tenant-a',
error: error.message,
duration: Date.now() - startTime
});
throw error;
}
};
Monitoring Dashboards
Create Grafana dashboards for chronos-db monitoring:
Performance Dashboard
- Operations per second by collection
- Average operation duration
- Error rates by operation type
- Backend utilization
Routing Dashboard
- Routing decisions by tenant
- Backend distribution
- Routing performance metrics
- Multi-tenant usage patterns
Storage Dashboard
- S3 storage usage
- MongoDB collection sizes
- TTL processing metrics
- State transition statistics
Alerting Rules
Set up alerts for critical chronos-db metrics:
# Prometheus alerting rules
groups:
- name: chronos-db
rules:
- alert: ChronosHighErrorRate
expr: rate(chronos_errors_total[5m]) > 0.1
for: 2m
labels:
severity: warning
annotations:
summary: "High error rate in chronos-db operations"
- alert: ChronosSlowOperations
expr: histogram_quantile(0.95, rate(chronos_operation_duration_seconds_bucket[5m])) > 5
for: 5m
labels:
severity: critical
annotations:
summary: "95th percentile operation duration exceeds 5 seconds"
- alert: ChronosBackendDown
expr: up{job="chronos-backend"} == 0
for: 1m
labels:
severity: critical
annotations:
summary: "Chronos backend is down"
Log Analysis Queries
Useful queries for analyzing chronos-db logs:
-- Top collections by operation count
SELECT collection, COUNT(*) as operations
FROM chronos_logs
WHERE category = 'chronos-operation'
GROUP BY collection
ORDER BY operations DESC;
-- Average operation duration by tenant
SELECT tenantId, AVG(duration) as avg_duration
FROM chronos_logs
WHERE category = 'chronos-performance'
GROUP BY tenantId;
-- Error rate by operation type
SELECT operation,
COUNT(CASE WHEN level = 'error' THEN 1 END) as errors,
COUNT(*) as total,
(errors * 100.0 / total) as error_rate
FROM chronos_logs
WHERE category = 'chronos-operation'
GROUP BY operation;
📞 Support
For issues, questions, or feature requests, please open an issue on GitHub.
Made with ❤️ for production-grade data management