# MindooDB > End-to-end encrypted, offline-first sync database. Keys stay on devices; servers store and sync ciphertext. Open source (Apache 2.0). For Node.js, browsers, and React Native. MindooDB is an open-source database for building secure, collaborative applications where encryption keys never leave client devices. Data is encrypted before it touches a server, signed for authorship proof, and stored in an append-only, cryptographically chained history. Servers can store and relay data but cannot read it — even a complete server breach yields only ciphertext and public keys. The database is built on Automerge CRDTs for automatic conflict-free merging, a content-addressed store abstraction for flexible deployment topologies (client-server, peer-to-peer, relay, mesh), and a metadata-first sync protocol that transfers only missing entries. It supports chunked encrypted attachments, hierarchical Virtual Views (inspired by HCL Notes/Domino), incremental cursor-based indexing, and time travel queries over the full document history. MindooDB is alpha software. APIs may change without notice. --- # Page: Home URL: https://mindoodb.com/ ## Your Data. Your Keys. Your Control. MindooDB is an end-to-end encrypted, offline-first sync database for secure collaboration — servers can store and sync, but cannot read. Works client-server, peer-to-peer and local-only. For browsers, NodeJS and React Native. ### Zero-trust storage Server breach yields ciphertext. Keys stay on devices. Three independent encryption layers: AES-256-GCM at rest, per-user RSA in transit, TLS on the wire. Servers never see plaintext. ### Offline-first UX Work without network. Create and edit locally. Metadata-first reconciliation syncs only what changed — bandwidth proportional to delta, not total size. ### Collaboration Conflict-free merges. Automerge CRDTs ensure concurrent edits converge automatically. Order-independent sync — entries can arrive in any sequence. ### When to choose MindooDB Choose MindooDB when: - You need end-to-end encryption and cannot trust your hosting provider - You require complete audit trails with cryptographic integrity - You need offline-first operation for field or remote operations - You collaborate across organizations and need fine-grained access control - You need technical controls for compliance — encryption, signed audit trails, and coordinated data erasure that support HIPAA, SOX, GDPR, PCI-DSS programs - You want simple backups without key exposure - You need multi-party collaboration with different access levels Consider alternatives when: - You only need simple CRUD operations without collaboration - You always have reliable network connectivity and don't need offline-first - You don't need end-to-end encryption and can trust your hosting provider - You have simple access control needs that don't require document-level encryption - You need complex relational queries that don't fit document model - You have very high write throughput that may challenge append-only stores ### Quick comparison | Feature | MindooDB | PostgreSQL/Firebase | Blockchains | |---------|----------|---------------------|-------------| | End-to-end encryption | Yes (servers can't decrypt) | No (server-side keys) | Public by default | | Offline-first | Built-in | Requires custom logic | Requires network | | Audit trails | Append-only, cryptographically chained | Requires custom implementation | Immutable public records | | Multi-org collaboration | Fine-grained access control | Server-side access control | All-or-nothing visibility | | Performance | High (no consensus needed) | Very high | Lower (consensus overhead) | | Data privacy | Private by default | Depends on server security | Public by default | ### Adoption effort - Local-only: Hours. `npm install mindoodb`, create a tenant, open a DB, and start storing encrypted documents. No server needed. - Client-server sync: Days. Implement 2 auth endpoints + 3 sync endpoints. The reference server is included as a starting point. - Advanced topologies: Incremental. Add P2P, relay nodes, or Bloom filter optimization later — same protocol, no code changes. ### Quick Start code ```typescript import { BaseMindooTenantFactory, InMemoryContentAddressedStoreFactory } from "mindoodb"; const factory = new BaseMindooTenantFactory(new InMemoryContentAddressedStoreFactory()); const { tenant } = await factory.createTenant({ tenantId: "acme", adminName: "cn=admin/o=acme", adminPassword: "admin-pw", userName: "cn=alice/o=acme", userPassword: "alice-pw", }); const db = await tenant.openDB("todos"); const doc = await db.createDocument(); await db.changeDoc(doc, (d) => { const data = d.getData(); data.title = "Buy milk"; data.done = false; }); const loaded = await db.getDocument(doc.getId()); console.log(loaded.getData()); // { title: "Buy milk", done: false } ``` ### Sync code ```typescript const doc = await contactsDB1.createDocument(); await contactsDB1.changeDoc(doc, (d) => { const data = d.getData(); data.name = "John Doe"; data.email = "john.doe@example.com"; }); await contactsDB2.pullChangesFrom(contactsDB1.getStore()); await contactsDB2.changeDoc(await contactsDB2.getDocument(doc.getId()), (d) => { d.getData().name = "John Smith"; }); await contactsDB2.pushChangesTo(contactsDB1.getStore()); await contactsDB1.syncStoreChanges(); // Both stores converge automatically (CRDTs) ``` ### Differentiators - Signed, tamperproof history: Append-only, cryptographically chained history for auditability and integrity. - Fine-grained access: Named keys enable need-to-know access control for sensitive documents. - Encrypted attachments: Chunked uploads, streaming reads, and tenant-wide deduplication. - Time travel: Retrieve document state at any timestamp and traverse full history. - Virtual Views: Hierarchical categorized views with totals (Domino/Notes-inspired). - Sync anywhere: Peer-to-peer, client-server, and hybrid deployments using the same primitives. ### Deployment topologies All topologies use the same ContentAddressedStore interface and the same sync protocol. Switching from client-server to peer-to-peer is a deployment decision, not a code change. - Client-Server: Standard sync with a central server. Simplest deployment. - Peer-to-Peer: Two devices sync directly over LAN, WebRTC, or Bluetooth. No server dependency. - Relay / Passthrough: Data flows through nodes that cannot decrypt it. Sync operates on encrypted metadata. - Store Chaining: A node forwards sync requests to another remote store for edge caching or access control boundaries. - Mesh: Multiple peers sync with each other. Entries deduplicate automatically. CRDT convergence guarantees consistency. - Multi-Party: Different participants hold different keys. A hospital server syncs patient records it cannot read. ### Protocol guarantees - Completeness — after a full sync cycle, the client has metadata awareness of every remote entry - Idempotency — every endpoint can be called repeatedly without side effects - Order independence — entries can arrive in any sequence; CRDTs handle causal ordering - Deduplication — entries identified by id, deduplicated by contentHash - Immediate revocation — enforced at challenge generation and token validation --- # Page: How It Works URL: https://mindoodb.com/how-it-works ## From Launch to Orbit A step-by-step walkthrough of how two users set up a MindooDB tenant, exchange encrypted data, and collaborate — all without the server ever seeing plaintext. ### Phase 1: Launch — Admin bootstraps the tenant Step 1 — Create the Tenant: The admin creates a new tenant with a single call. This generates all keys, opens the tenant, and registers the first user in the directory. ```typescript const { tenant, adminUser, appUser, keyBag } = await factory.createTenant({ tenantId: "acme", adminName: "cn=admin/o=acme", adminPassword: "••••••••", userName: "cn=alice/o=acme", userPassword: "••••••••", }); ``` Step 2 — Publish to Server: The admin registers the tenant on a MindooDB server. The server only stores encrypted data and public keys. ```typescript await tenant.publishToServer("https://sync.acme.com", { registerUsers: [appUser] }); ``` Step 3 — Create & Sync a Document: Alice creates a todo document and pushes the encrypted changes to the server. ```typescript const db = await tenant.openDB("todos"); const doc = await db.createDocument(); await db.changeDoc(doc, (d) => { const data = d.getData(); data.title = "Buy groceries"; data.done = false; }); const remote = await tenant.connectToServer("https://sync.acme.com", "todos"); await db.pushChangesTo(remote); ``` ### Phase 2: Signal — A new user requests to join Step 4 — Create Join Request: Bob creates his identity locally — his private keys never leave his device. He generates a join request containing only public keys. ```typescript const bob = await factory.createUserId("cn=bob/o=acme", "••••••••"); const joinRequestURI = factory.createJoinRequest(bob, { format: "uri" }); // → mdb://join-request/eyJ2IjoxLCJ1c2Vy... ``` The join request is safe to share via any channel (email, chat, QR code) because it contains no secrets. ### Phase 3: Docking — Admin approves the join request Step 6 — Approve Join Request: The admin approves Bob's request. This registers Bob in the directory and encrypts the symmetric keys with a shared password. ```typescript const joinResponseURI = await tenant.approveJoinRequest(joinRequestURI, { adminSigningKey: adminUser.userSigningKeyPair.privateKey, adminPassword: "••••••••", sharePassword: "one-time-secret", format: "uri", }); // → mdb://join-response/eyJ2IjoxLCJ0ZW5h... ``` The share password is communicated separately via a secure channel (phone, in person). ### Phase 4: Orbit — Real-time collaboration begins Step 8 — Join, Pull, Modify, Push: Bob joins the tenant, pulls the latest data, marks the todo as done, and pushes back. ```typescript const { tenant: bobTenant } = await factory.joinTenant(joinResponseURI, { user: bob, password: "••••••••", sharePassword: "one-time-secret", }); const remote = await bobTenant.connectToServer("https://sync.acme.com", "todos"); const db = await bobTenant.openDB("todos"); await db.pullChangesFrom(remote); await db.syncStoreChanges(); const todo = await db.getDocument(todoDocId); await db.changeDoc(todo, (d) => { d.getData().done = true; }); await db.pushChangesTo(remote); ``` Step 9 — Fetch Changes: Alice pulls the latest changes and sees the todo is done. ```typescript await db.pullChangesFrom(remote); await db.syncStoreChanges(); const updated = await db.getDocument(todoDocId); console.log(updated.getData().done); // → true ``` ### What the Server Sees vs. Doesn't See Server sees: - Public signing keys (Ed25519) - Public encryption keys (RSA-OAEP) - Encrypted blobs (AES-256-GCM ciphertext) - Entry metadata (timestamps, content hashes) Server never sees: - Usernames (encrypted with admin RSA key) - Document content (end-to-end encrypted) - Private keys (stay on device) - Shared passwords (out-of-band only) - Symmetric encryption keys --- # Page: Architecture URL: https://mindoodb.com/architecture ## Built for zero trust, designed for composability MindooDB's architecture separates the sync concern (moving encrypted bytes) from the application concern (decrypting and interpreting data). This single design choice enables client-server, peer-to-peer, relay, and mesh topologies — all using the same protocol and the same code. ### For decision makers: What this architecture gives you MindooDB is designed for progressive adoption — start local-only, add client-server sync when ready, enable P2P or relay topologies later. Every step uses the same ContentAddressedStore interface, so changing your deployment model is a configuration decision, not a code rewrite. - Adoption effort: Hours for local-only. Days for client-server sync (2 auth + 3 sync endpoints). Incremental for P2P, relay, or Bloom filter optimizations. - Security posture: Three independent protection layers. Servers never see plaintext. A full server breach yields only ciphertext and public keys. - Operational simplicity: No server-side user accounts, no password storage, no session databases. The server is a relay for encrypted blobs. ### Tenants, users, and the trust chain A MindooDB tenant represents an organization or team. Tenants are created entirely client-side. The tenant creator becomes the administrator, whose Ed25519 signing key is the root of trust. Every user registration in the directory is signed with this admin key, and clients and servers verify these signatures before trusting any user's public key. Tenant structure: - Directory database — Admin-signed user registrations, group memberships, settings - Application databases — Created on demand (tenant.openDB("contacts")) - Documents — Automerge CRDTs with signed, encrypted, append-only history - Attachments — Chunked (256KB), encrypted, deduplicated file storage Key hierarchy: - Admin signing key (Ed25519) — Root of trust; signs directory entries - Admin encryption key (RSA-OAEP) — Encrypts usernames for privacy - User signing keys (Ed25519) — Prove authorship of document changes - User encryption keys (RSA-OAEP) — Protect local KeyBag storage - Default tenant key (AES-256) — Encrypts documents for all members - Named keys (AES-256) — Fine-grained access for specific users ### The content-addressed store At the center of MindooDB's flexibility is the ContentAddressedStore interface. Every store — whether backed by local disk, in-memory data, or a remote network connection — implements this same interface. The sync methods pullChangesFrom() and pushChangesTo() accept any ContentAddressedStore, which means they work identically regardless of whether the other side is a local store, a remote server, or another client connected over WebRTC. - Append-only entries: Every document change, snapshot, and attachment chunk is stored as an immutable entry with a unique ID and content hash. Entries are never modified or deleted. - Cryptographic chaining: Each entry references its parent entries by ID (forming a DAG) and is signed by its creator. Tampering with any entry breaks the chain. - Automatic deduplication: Entries are identified by id and deduplicated by contentHash (SHA-256 of encrypted payload). ### Sync protocol The sync protocol offers two paths. Baseline sync: send your known entry IDs, receive metadata for what you're missing, fetch those entries. Optimized sync: adds cursor-based scanning and Bloom filter summaries for larger datasets — negotiated at runtime through capability discovery. Protocol guarantees (hold across all deployment topologies): - Completeness — After a full sync cycle, the client has metadata awareness of every remote entry - Idempotency — Every endpoint can be called repeatedly without side effects - Order independence — Entries can arrive in any sequence; CRDTs handle convergence - Deduplication — Identical entries from multiple sources stored once Performance optimization: - Cursor scanning — Page through remote metadata incrementally. Request size stays constant regardless of total store size. - Bloom filter summary — Download a compact probabilistic set representation to pre-filter IDs. Eliminates 90-99% of exact existence checks. - CRDT snapshots — Periodic snapshots prevent performance degradation from replaying long document histories. Authentication: Challenge-response with Ed25519. The server generates a random challenge, the client signs it with its private key, and the server verifies against the registered public key. Revocation is enforced at both challenge generation and token validation. ### Deployment topologies Because sync operates on encrypted entries and uses the same ContentAddressedStore interface everywhere, any node can participate in sync without decrypting data. | Topology | When to use | Infrastructure needed | Key benefit | |----------|------------|----------------------|-------------| | Client-server | Default starting point | One server + clients | Simplest deployment | | Peer-to-peer | Same-network sync without server | Clients only (LAN/WebRTC) | No server needed | | Relay | Data distribution through untrusted nodes | Relay server (no keys needed) | Secure data distribution | | Store chain | Edge caching, geographic distribution | Origin + edge nodes | Latency reduction | | Mesh | Resilient multi-peer convergence | Multiple peers | No single point of failure | | Hybrid | Server for reliability, P2P for speed | Server + direct peer links | Best of both worlds | ### Durability: Crash safety and data integrity MindooDB stores encrypted, content-addressed entries directly on the filesystem. Write protocol: Every file write follows an atomic protocol: write to a temp file, fsync, atomic rename, fsync the parent directory. Readers never see partially written state. - Crash between payload and metadata — Orphaned payload is harmless - Crash between metadata and index — Entry is committed; index rebuilt on startup - Crash during compaction — Stale index detected and rebuilt from authoritative entry files Startup recovery: Load metadata snapshot, replay incremental segments, validate against entry files. If anything is stale, fall back to full rebuild — transparently and without data loss. ### Data modeling: Organizing data for growth The primary tool is database-level sharding: split data into separate databases by time period, category, access level, or geography. Each database syncs independently. - Time-based — Yearly or monthly databases keep sync fast for active data - Category-based — Separate databases by document type, project, or business unit - Access-based — Isolate data by security level - Geographic — Databases per region for data residency requirements ### Honest tradeoffs - Revocation limitations: Revoking a user blocks future sync and rejects their future changes. However, previously synced data on their local device remains accessible. Mitigation: use named keys for sensitive documents, rotate keys when users leave. - No server-side queries: Because data is encrypted, the server cannot execute queries. All querying happens client-side through incremental indexing, Virtual Views, or pluggable search indexers. - Key management complexity: Multiple keys per user require secure distribution. Mitigation: single password unlocks all keys via KDF. KeyBag provides unified storage. Join flow handles key exchange. - Append-only storage growth: Data accumulates. Mitigation: database-level sharding, CRDT snapshots, GDPR purge (purgeDocHistory). --- # Page: Security Model URL: https://mindoodb.com/security ## Assume servers are compromised MindooDB is designed so that storage and sync infrastructure can be untrusted. Three independent encryption layers protect data confidentiality. Cryptographic signatures prove authorship and prevent tampering. Even a complete server breach yields only ciphertext and public keys — no plaintext data, no private keys, no usernames. ### Three independent encryption layers Layer 1 — Application-level encryption: Before an entry ever enters the store, its payload is encrypted with a symmetric key (AES-256-GCM). The server storing entries cannot read their contents. Layer 2 — Transport payload encryption: When the server responds to a sync request, it wraps entry payloads in an additional RSA encryption layer using the requesting user's public key. Layer 3 — Channel encryption: All communication happens over TLS. This protects metadata not covered by the payload encryption layers. ### Trust model Trust flows from a single root: the admin's Ed25519 signing key. The admin signs the directory database, which contains user registrations. Every user's public key is recorded in a directory entry signed by the admin. When a client or server receives a document change, it verifies the signer's public key against the directory. ### What the server sees vs. doesn't see Server sees: - Public signing keys (Ed25519) - Public encryption keys (RSA-OAEP) - Encrypted blobs (AES-256-GCM ciphertext) - Entry metadata (timestamps, content hashes) - Username hashes (SHA-256 — not actual usernames) Server never sees: - Document content (end-to-end encrypted) - Usernames (encrypted with admin RSA key) - Private signing or encryption keys - Symmetric encryption keys (tenant or named) - Shared passwords (out-of-band only) ### Encryption-based access control MindooDB enforces access control through encryption keys, not server-side permissions. - Default tenant key: All documents encrypted with the tenant's default AES-256 key unless another key is specified. Every registered user receives this key during onboarding. - Named keys: For sensitive documents, create a named encryption key and share it only with authorized users. Keys are distributed offline. - $publicinfos key: A special key that encrypts only directory access-control entries. Servers use this to validate which signing keys are trusted — without seeing usernames or business data. | Operation | Enforced by | |-----------|-------------| | User registration | Admin signature required (Ed25519) | | Document creation | Must have encryption key (default or named) | | Document modification | Must have signing key (registered user) + encryption key | | Document reading | Must have decryption key | | User revocation | Admin signature required; blocks sync and rejects future changes | ### Authentication Challenge-response with Ed25519: 1. Client sends its public signing key to the server 2. Server looks up the key in the directory and sends a random challenge 3. Client signs the challenge with its private key 4. Server verifies the signature, checks revocation status, issues a short-lived JWT No passwords or session databases on the server. ### Secure user onboarding (join request / response) New users join through a three-step handshake where private keys never leave the device: 1. Join request — New user generates keys locally, creates a request containing only public keys. Safe to share via any channel. 2. Admin approval — Admin registers user in directory, encrypts symmetric keys with a one-time share password. 3. Split-channel exchange — Join response sent via email/chat; share password communicated separately by phone or in person. ### Cryptographic primitives Algorithms: - Signing: Ed25519 (128-bit security, elliptic curve) - Payload encryption: AES-256-GCM (256-bit security) - Transport encryption: RSA-OAEP with SHA-256 (3072-bit keys) - Key derivation: PBKDF2 with unique salts per key type - Token signing: HMAC-SHA256 - Hashing: SHA-256 (content addressing, username privacy) Security guarantees: - Confidentiality: AES-256-GCM encryption — only key holders can read - Authenticity: Ed25519 signatures — proves who created each change - Integrity: Hash chaining — tampering breaks the chain - Non-repudiation: Signatures are unforgeable — authorship is provable - Privacy: Usernames hashed and encrypted — server cannot identify users ### Threat model Attacks defended: - Server breach — Attacker gets ciphertext and public keys only - Network interception — Three encryption layers protect data even if TLS is compromised - Unauthorized changes — Every change is signed; unsigned changes are rejected - Tampering — Hash chaining makes any modification detectable - Revoked user access — Revocation enforced at both challenge and token validation - Relay eavesdropping — Relay nodes store and forward encrypted entries they cannot decrypt Metadata exposure (deliberate tradeoff for sync protocol): - Visible: Entry timestamps, content hashes, document structure, access patterns - Not visible: Document content, usernames, encryption keys, attachment contents --- # Page: Get Started URL: https://mindoodb.com/get-started ## One SDK. Every platform. Encrypted sync everywhere. MindooDB runs on Node.js servers, web browsers, and React Native mobile apps — all syncing through the same end-to-end encrypted protocol. Pick your platform and build your first synced document in minutes. ### Platform guides - Node.js: CLI/server quickstart with verified output. → /get-started/node - Web Browser: Use mindoodb/browser with Web Crypto. → /get-started/web - React Native: Native-first setup via `mindoodb setup-react-native`. → /get-started/react-native ### Quickstart: tenant, document, sync One call creates the tenant with admin + user keys, KeyBag, and directory registration. This is the same code on every platform — only the import path changes. ```typescript import { BaseMindooTenantFactory, InMemoryContentAddressedStoreFactory } from "mindoodb"; const storeFactory = new InMemoryContentAddressedStoreFactory(); const factory = new BaseMindooTenantFactory(storeFactory); const { tenant, adminUser, appUser, keyBag } = await factory.createTenant({ tenantId: "acme", adminName: "cn=admin/o=acme", adminPassword: "admin-password", userName: "cn=alice/o=acme", userPassword: "alice-password", }); const db = await tenant.openDB("contacts"); const doc = await db.createDocument(); await db.changeDoc(doc, (d) => { d.getData().name = "John Doe"; }); await tenant.publishToServer("https://sync.acme.com", { registerUsers: [factory.toPublicUserId(appUser)], }); const remote = await tenant.connectToServer("https://sync.acme.com", "contacts"); await db.pushChangesTo(remote); ``` ### Cross-platform sync Every MindooDB client — whether running on a Node.js backend, a web frontend, or a React Native app — speaks the same encrypted sync protocol. The server stores and relays ciphertext without ever seeing plaintext. Users can work offline and sync seamlessly when connectivity returns. --- # Page: Get Started — Node.js URL: https://mindoodb.com/get-started/node Install: ```bash npm init -y npm install mindoodb ``` Complete Node.js example — create a tenant, open a database, create a todo document, and read it back. Uses createTenant() convenience method which generates all keys, opens the tenant, and registers the first user. --- # Page: Get Started — Web Browser URL: https://mindoodb.com/get-started/web Install: ```bash npm create vite@latest my-mindoodb-app -- --template vanilla cd my-mindoodb-app npm install mindoodb ``` Browser build uses Web Crypto. Import from `mindoodb/browser` and create a crypto adapter with `createCryptoAdapter()`. All other code is identical to Node.js. --- # Page: Get Started — React Native URL: https://mindoodb.com/get-started/react-native Install: ```bash npm install mindoodb react-native-automerge-generated npx mindoodb setup-react-native ``` React Native requires native Automerge backend (react-native-automerge-generated) and polyfills for crypto (react-native-quick-crypto), TextDecoder, and URL handling. The setup helper configures polyfills automatically. Use QuickCryptoAdapter for native crypto performance. --- # Page: Documentation URL: https://mindoodb.com/docs Curated entry points to the GitHub documentation. The website stays concise; these links take you to the deeper technical documentation. ### Platform guides - Node.js quickstart: /get-started/node - Web quickstart: /get-started/web - React Native quickstart: /get-started/react-native ### Start here - Project README (concepts + quick start) - Architecture specification - Network sync protocol (design, integration guide, security) - P2P sync and advanced network topologies - Attachments - Virtual Views - Time travel ### Deep dives by topic Sync: - Network sync protocol — authentication, reconciliation, security model - P2P sync — relay nodes, store chaining, multi-party encrypted sync Indexing & querying: - Data indexing (iterateChangesSince) - Virtual Views Security: - Revocation timestamp protection - Logging & sanitization Attachments: - Attachment storage design History: - Time travel --- # Page: Use Cases URL: https://mindoodb.com/use-cases ## Where MindooDB fits best ### Offline-first field apps Local-first editing with later sync, even across unstable networks. Key features: Offline-first, Sync missing entries, Conflict-free merges (CRDT). Watch-outs: Plan for key distribution and onboarding flows. ### Secure collaboration Collaborate without trusting servers with plaintext. Key features: End-to-end encryption, Signed changes, Append-only audit trail. Watch-outs: Servers can't run plaintext queries without client keys. ### Multi-tenant SaaS Tenant isolation with a cryptographic trust model and secure sync. Key features: Tenant keys, Directory trust chain, Hybrid deployments. Watch-outs: Define support/ops model for key recovery (if any). ### Audit & compliance workflows Full history with integrity guarantees and explainable provenance. Key features: Append-only history, Time travel, Authorship proofs. Watch-outs: Be explicit about revocation semantics in policies. ### Encrypted file workflows Chunked encrypted attachments with streaming reads and deduplication. Key features: Attachments, Streaming, Dedup by contentHash. Watch-outs: Some metadata still exists (doc id, sizes in chunk data). ### Cross-org reporting Hierarchical Virtual Views can unify multiple origins for reporting. Key features: Virtual Views, Totals, Multi-origin views. Watch-outs: Decide which data should be joined and where access checks live. ### Decision framework Use MindooDB when you need: - End-to-end encryption and cannot trust hosting providers - Offline-first operation for field or remote work - Complete audit trails with cryptographic integrity - Multi-party collaboration across organizations - Technical controls for compliance (HIPAA, SOX, GDPR, PCI-DSS) - Simple backups without key exposure - Conflict-free collaboration with automatic merging Don't use MindooDB when: - You only need simple CRUD operations without collaboration - You always have reliable connectivity - You need complex SQL queries with joins and aggregations - You have very high write throughput (millions of writes/second) - You trust your hosting provider completely - You need server-side querying of decrypted data --- # Page: Industries URL: https://mindoodb.com/industries ## Built for regulated industries and secure collaboration ### Healthcare Healthcare organizations face uniquely stringent requirements around data privacy, regulatory compliance, and multi-party collaboration. MindooDB's end-to-end encryption ensures patient data is never visible to servers, while complete audit trails support HIPAA compliance. Key requirements: HIPAA, Complete audit trails, Data encryption, Access control. Use cases: - Electronic Health Records (EHR): Patient-centric document organization with complete history, tamper-proof records, and fine-grained access control for different care teams. - Medical Device Data Collection: Time-series data from IoT sensors and monitors with offline operation. - Multi-Institutional Research: Secure collaboration across hospitals using named encryption keys. Benefits: - Patient data isolation with separate databases per patient - HIPAA-compliant audit trails with cryptographic integrity - Secure multi-institutional collaboration - Offline operation for field healthcare workers and remote clinics ### Financial Services Financial institutions operate under strict regulatory oversight. MindooDB's append-only architecture naturally supports immutable record-keeping, comprehensive audit trails, and secure multi-party transactions. Key requirements: SOX, PCI-DSS, Immutable records, Audit trails. Use cases: - Transaction Ledgers: Immutable append-only transaction records with time-based sharding. - Multi-Party Agreements: Contracts with multiple signatories and cryptographically signed changes. - Regulatory Reporting: Cross-entity aggregation using Virtual Views. Benefits: - Immutable audit trails through append-only architecture - SOX and PCI-DSS compliance patterns - Secure multi-party contracts with complete signature history ### IoT & Edge Computing IoT and edge environments present unique challenges: intermittent connectivity, limited bandwidth, and uncertain physical device security. Key requirements: Offline operation, Bandwidth optimization, Time-series data, Device management. Use cases: - Sensor Data Collection: Time-series data with monthly databases per device and automatic synchronization. - Device Management: Configuration and firmware updates with centralized device registry. - Edge-to-Cloud Sync: Efficient incremental synchronization minimizing bandwidth. Benefits: - Offline device independence for remote locations - Bandwidth optimization through incremental sync - Efficient time-series storage with time-based sharding ### Collaborative Workspaces Modern teams require seamless collaboration regardless of location, connectivity, or organizational boundaries. Key requirements: Real-time collaboration, Offline editing, Version control, Access control. Use cases: - Document Management: Version-controlled documents with offline editing and automatic conflict resolution. - Project Management: Task tracking with real-time collaboration. - Knowledge Bases: Wiki-style documentation with access control and Virtual Views. Benefits: - Real-time collaboration via Automerge CRDTs - Offline editing with automatic sync - Complete version history through append-only architecture --- # Page: Compliance URL: https://mindoodb.com/compliance ## Technical controls that support compliance MindooDB provides cryptographic building blocks — end-to-end encryption, signed append-only history, and coordinated data erasure — that address key technical requirements of common regulatory frameworks. ### HIPAA (Healthcare) How MindooDB helps: - End-to-end encryption ensures patient data is never visible to servers - Signed write history — every change is Ed25519-signed - Fine-grained access control with named keys for different care teams - Data retention strategies via time-sharded databases - Offline operation for field healthcare workers Note: HIPAA also requires read-access logging, BAAs, administrative safeguards, and physical security. ### SOX (Financial) How MindooDB helps: - Immutable records through append-only architecture - Cryptographic integrity — hash-chained entries prove records haven't been altered - Complete write history with signed authorship - Time travel to reconstruct any historical state ### GDPR (Data Protection) How MindooDB helps: - Coordinated data erasure — purgeDocHistory() propagates deletion requests via the directory DB - Data portability through document export capabilities - Data protection by design through end-to-end encryption - Write audit trail — signed, append-only history Note: Purge requests reach clients on their next directory sync — devices that never reconnect retain the data. ### PCI-DSS (Payments) How MindooDB helps: - Strong encryption — AES-256-GCM at rest, per-user RSA in transit - Access controls with named keys for restricted access - Write audit trail — signed, append-only history ### Technical controls provided Built-in — Audit & integrity: - Complete write history (append-only) - Cryptographic signatures (authorship proof) - Tamperproof records (hash-chained) - Time travel (reconstruct any state) Built-in — Data protection: - Client-side encryption (AES-256-GCM) - Fine-grained access control (named keys) - Key management (password-protected KeyBag) - Coordinated data erasure (directory-propagated purge) You build — Application-level: - Read-access logging - Consent management - Role-based access control (using named keys) - Data retention policies (using time-sharding) ### Compliance feature matrix | Requirement | HIPAA | SOX | GDPR | PCI-DSS | |-------------|-------|-----|------|---------| | Data encryption | E2E encryption | E2E encryption | E2E encryption | E2E encryption | | Access control | Named keys | Named keys | Named keys | Named keys | | Write audit trail | Signed, append-only | Signed, append-only | Signed, append-only | Signed, append-only | | Data integrity | Hash-chained | Hash-chained | Hash-chained | Hash-chained | | Data erasure | Coordinated purge | N/A | Coordinated purge* | N/A | | Read-access logging | You build | You build | You build | You build | --- # Page: Indexing & Querying URL: https://mindoodb.com/indexing ## Query everything. Reprocess nothing. MindooDB's append-only store and cursor-based change tracking let you build indexes that stay up to date by processing only what changed — never rescanning the entire database. ### iterateChangesSince() — the foundation A cursor-based async generator that yields documents in modification order. On the first call it walks the entire database; on subsequent calls it picks up exactly where it left off. Deleted documents are included with a deletion marker. Cost proportional to the number of changes since the last cursor. ```typescript let cursor = null; for await (const { doc, cursor: newCursor } of db.iterateChangesSince(cursor)) { if (doc.isDeleted()) myIndex.remove(doc.getId()); else myIndex.update(doc); cursor = newCursor; } ``` ### Virtual Views Hierarchical in-memory tree structure that categorizes, sorts, and aggregates documents. Inspired by HCL Notes/Domino views. Features: - Category columns — group documents into nested hierarchies - Sorted columns — sort entries within each category - Total columns — automatic SUM or AVERAGE per category, updated incrementally - Display columns — additional data shown alongside each entry - Navigation — expand/collapse, position-based jumps, forward/backward iteration - Access control callbacks — filter visible entries per user ```typescript const view = await VirtualViewFactory.createView() .addCategoryColumn("department", { sorting: ColumnSorting.ASCENDING }) .addCategoryColumn("year", { sorting: ColumnSorting.DESCENDING }) .addSortedColumn("lastName", ColumnSorting.ASCENDING) .addTotalColumn("salary", TotalMode.SUM) .withDB("employees", employeeDB, (doc) => doc.getData().type === "employee") .buildAndUpdate(); ``` ### Cross-boundary queries Virtual Views can combine documents from multiple MindooDB instances into a single unified view. Each data source is identified by an "origin" string. Supports multi-database views, multi-tenant views, and independent cursor tracking per source. ```typescript const unifiedView = await VirtualViewFactory.createView() .addCategoryColumn("region") .addTotalColumn("revenue", TotalMode.SUM) .withDB("us-products", usProductsDB, (doc) => doc.getData().type === "product") .withDB("eu-products", euProductsDB, (doc) => doc.getData().type === "product") .buildAndUpdate(); ``` ### External indexer integration Push incremental updates to any external system. Compatible search indexers: FlexSearch, MiniSearch, Lunr.js, or custom indexers. ```typescript async function syncToSearchIndex() { for await (const { doc, cursor: newCursor } of db.iterateChangesSince(cursor)) { if (doc.isDeleted()) flexSearchIndex.remove(doc.getId()); else flexSearchIndex.add(doc.getId(), `${data.title} ${data.content}`); cursor = newCursor; } } ``` ### Time travel Retrieve document state at any historical timestamp. Walk the full change history with author metadata. List all document IDs at a specific time. ```typescript const docYesterday = await db.getDocumentAtTimestamp(docId, yesterday); for await (const { doc, changeCreatedAt, changeCreatedByPublicKey } of db.iterateDocumentHistory(docId)) { console.log(`${new Date(changeCreatedAt).toISOString()} by ${changeCreatedByPublicKey}`); } const idsAtEndOfQ1 = await db.getAllDocumentIdsAtTimestamp(endOfQ1); ``` --- # Page: Compare — MindooDB vs. Alternatives URL: https://mindoodb.com/compare MindooDB is designed for specific use cases where end-to-end encryption, offline operation, and multi-party collaboration are essential. ### vs. PostgreSQL / MySQL | Feature | MindooDB | PostgreSQL/MySQL | |---------|----------|------------------| | End-to-end encryption | Yes (servers can't decrypt) | No (server-side keys) | | Offline-first | Built-in | Requires custom logic | | Complex SQL queries | No (document model) | Full SQL support | | Write throughput | Good (append-only) | Very high | | Audit trails | Built-in (append-only) | Requires custom implementation | | Data sovereignty | Client-side tenant creation | Server-managed | ### vs. Firebase / Supabase | Feature | MindooDB | Firebase/Supabase | |---------|----------|-------------------| | End-to-end encryption | Yes (servers can't decrypt) | No (server-side keys) | | Vendor lock-in | No (client-side tenants) | Yes (cloud-managed) | | Offline-first | Built-in by design | Supported but not core | | Managed infrastructure | Self-hosted or custom | Fully managed | | Data sovereignty | Complete control | Cloud provider controls | ### vs. MongoDB | Feature | MindooDB | MongoDB | |---------|----------|---------| | End-to-end encryption | Yes (servers can't decrypt) | No (server-side keys) | | Offline-first | Built-in | Requires custom logic | | Conflict resolution | Automatic (CRDTs) | Manual or last-write-wins | | Query flexibility | Via Virtual Views/indexing | Rich query language | | Audit trails | Built-in (append-only) | Requires oplog or custom | ### vs. Blockchains | Feature | MindooDB | Blockchains | |---------|----------|-------------| | Data privacy | Private by default | Public by default | | Performance | High (no consensus) | Lower (consensus overhead) | | Cost | Low (no mining fees) | Higher (mining/validator costs) | | Public verifiability | Private verification | Anyone can verify | | Access control | Fine-grained permissions | All-or-nothing visibility | ### Migration considerations From SQL databases: Convert relational data to document model. Map foreign keys to document references. Use Virtual Views for cross-database queries. From cloud databases: Export data from cloud platform. Import into MindooDB tenant. Set up key distribution for users. --- # Page: Imprint URL: https://mindoodb.com/imprint ## Legal Notice Mindoo GmbH Karpfenweg 12 76189 Karlsruhe Germany Website: www.mindoo.de Responsible for content: Karsten Lehmann --- # Full API Documentation The following sections contain the complete API documentation from the MindooDB repository. ## Getting Started Guide Source: https://github.com/klehmann/MindooDB/blob/main/docs/getting-started.md MindooDB is an end-to-end encrypted, offline-first sync database that runs on Node.js, web browsers, and React Native. You create tenants and users entirely on the client — private keys never leave the device, and the server only ever sees encrypted blobs. ### Installation ```bash npm install mindoodb ``` Platform imports: | Platform | Import | |----------|--------| | Node.js | `import { BaseMindooTenantFactory, ... } from "mindoodb"` | | Web Browser | `import { BaseMindooTenantFactory, ... } from "mindoodb/browser"` | | React Native | `import { BaseMindooTenantFactory, ... } from "mindoodb"` (with native Automerge setup) | ### Step 1: Create a Tenant A tenant represents your organization or team. Creating one generates all cryptographic keys, opens the tenant for use, and registers the first user in the directory — in a single call. ```javascript import { BaseMindooTenantFactory, InMemoryContentAddressedStoreFactory } from "mindoodb"; const storeFactory = new InMemoryContentAddressedStoreFactory(); const factory = new BaseMindooTenantFactory(storeFactory); const { tenant, adminUser, appUser, keyBag } = await factory.createTenant({ tenantId: "acme", adminName: "cn=admin/o=acme", adminPassword: "strong-admin-password", userName: "cn=alice/o=acme", userPassword: "strong-user-password", }); ``` Behind the scenes, createTenant performs five operations: creates admin identity (Ed25519 + RSA-OAEP), creates user identity, generates tenant encryption key and $publicinfos key in a new KeyBag, opens the tenant, and registers the user in the directory. ### Step 2: Publish the Tenant to a Server ```javascript await tenant.publishToServer("https://sync.example.com"); ``` This sends the admin's public keys and the $publicinfos key to the server. Optionally pre-register users: ```javascript await tenant.publishToServer("https://sync.example.com", { registerUsers: [factory.toPublicUserId(appUser)], }); ``` ### Step 3: Create and Sync Your First Document ```javascript const db = await tenant.openDB("todos"); const doc = await db.createDocument(); await db.changeDoc(doc, (d) => { d.getData().title = "Buy groceries"; d.getData().done = false; }); const remote = await tenant.connectToServer("https://sync.example.com", "todos"); await db.pushChangesTo(remote); ``` ### Step 4: Invite a Second User Step 4a — New user creates a join request: ```javascript const bob = await factory.createUserId("cn=bob/o=acme", "bobs-password"); const joinRequest = factory.createJoinRequest(bob, { format: "uri" }); // → "mdb://join-request/eyJ2IjoxLCJ1c2VybmFtZSI6..." ``` Step 4b — Admin approves: ```javascript const joinResponse = await tenant.approveJoinRequest(joinRequest, { adminSigningKey: adminUser.userSigningKeyPair.privateKey, adminPassword: "strong-admin-password", sharePassword: "one-time-secret-42", serverUrl: "https://sync.example.com", format: "uri", }); ``` Step 4c — New user joins: ```javascript const { tenant: bobTenant, keyBag: bobKeyBag } = await factory.joinTenant(joinResponse, { user: bob, password: "bobs-password", sharePassword: "one-time-secret-42", }); ``` ### Step 5: Collaborate ```javascript const remote = await bobTenant.connectToServer("https://sync.example.com", "todos"); const db = await bobTenant.openDB("todos"); await db.pullChangesFrom(remote); await db.syncStoreChanges(); const ids = await db.getAllDocumentIds(); const todo = await db.getDocument(ids[0]); await db.changeDoc(todo, (d) => { d.getData().done = true; }); await db.pushChangesTo(remote); ``` ### Step 6: Persisting and Restoring a Session Three pieces of data need to be saved: 1. The user identity (PrivateUserId) — encrypted private keys, safe to write to disk 2. The KeyBag — call keyBag.save() to get an encrypted Uint8Array 3. Tenant metadata — tenant ID and admin's public keys Restoring: ```javascript const keyBag = new KeyBag(savedUser.userEncryptionKeyPair.privateKey, "strong-user-password"); await keyBag.load(keyBagBlob); const tenant = await factory.openTenant( meta.tenantId, meta.adminSigningPublicKey, meta.adminEncryptionPublicKey, savedUser, "strong-user-password", keyBag, ); ``` ### Browser Setup ```javascript import { BaseMindooTenantFactory, InMemoryContentAddressedStoreFactory, createCryptoAdapter } from "mindoodb/browser"; const cryptoAdapter = createCryptoAdapter(); const factory = new BaseMindooTenantFactory(storeFactory, cryptoAdapter); ``` For persistent browser storage, use IndexedDBContentAddressedStoreFactory. ### React Native / Expo ```bash npm install mindoodb react-native-automerge-generated npx mindoodb setup-react-native ``` The react-native-automerge-generated package provides a native Rust backend for Automerge (via UniFFI bindings). MindooDB detects and uses this native backend automatically. ## Architecture Specification (Key Sections) Source: https://github.com/klehmann/MindooDB/blob/main/docs/specification.md ### Tenant Keys | Key | Type | Purpose | |-----|------|---------| | Default Encryption Key | AES-256 (symmetric) | Default encryption when no other key specified | | Administration Signing Key | Ed25519 (asymmetric) | Signs user registrations & admin operations | | Administration Encryption Key | RSA-OAEP (asymmetric) | Encrypts sensitive admin data | ### User Key Pairs | Key | Type | Purpose | |-----|------|---------| | Signing Key | Ed25519 | Signs document changes (proves authorship) | | Encryption Key | RSA-OAEP (3072-bit) | Encrypts local KeyBag storage | Key derivation: Both private keys encrypted with a single password using KDF with different salts (signing key: "signing", encryption key: "encryption", tenant keys: "tenant:v1:${tenantId}", document keys: "doc:v1:${keyId}"). ### Store Entry Structure ```typescript interface StoreEntryMetadata { entryType: StoreEntryType; // doc_create | doc_change | doc_snapshot | doc_delete | attachment_chunk id: string; // Entry identity (primary key) contentHash: string; // SHA-256(encryptedData) docId: string; // Document ID dependencyIds: string[]; // Parent entry IDs (DAG) createdAt: number; // Unix timestamp (ms) createdByPublicKey: string; // Author's Ed25519 public key decryptionKeyId: string; // "default" or named key ID signature: Uint8Array; // Ed25519 signature originalSize: number; // Plaintext size (bytes) encryptedSize: number; // Encrypted size (bytes) } ``` ### ContentAddressedStore Interface ```typescript interface ContentAddressedStore { getId(): string; putEntries(entries: StoreEntry[]): Promise; getEntries(ids: string[]): Promise; hasEntries(ids: string[]): Promise; getAllIds(): Promise; findNewEntries(knownIds: string[]): Promise; findNewEntriesForDoc(knownIds: string[], docId: string): Promise; findEntries(type: StoreEntryType, from: number | null, until: number | null): Promise; resolveDependencies(startId: string, options?: ResolveOptions): Promise; purgeDocHistory(docId: string): Promise; clearAllLocalData?(): Promise; awaitIndexReady?(options?: { timeoutMs?: number }): Promise; } ``` ### Document Lifecycle ```typescript // Create const doc = await db.createDocument(); // Uses "default" key const doc = await db.createEncryptedDocument("confidential-key"); // Named key // Modify await db.changeDoc(doc, async (d) => { d.getData().title = "Project X"; }); // Read const loaded = await db.getDocument(docId); console.log(loaded.getData()); ``` ### Synchronization ```typescript // Connect to server const remote = await tenant.connectToServer("https://sync.example.com", "todos"); // Push local changes await db.pushChangesTo(remote); // Pull remote changes await db.pullChangesFrom(remote); await db.syncStoreChanges(); ``` ### Attachment API ```typescript // Write await doc.addAttachment(fileData, "report.pdf", "application/pdf"); await doc.addAttachmentStream(asyncIterable, "video.mp4", "video/mp4"); await doc.appendToAttachment(attachmentId, moreData); await doc.removeAttachment(attachmentId); // Read const attachments = doc.getAttachments(); const data = await doc.getAttachment(attachmentId); const range = await doc.getAttachmentRange(attachmentId, 0, 1024); for await (const chunk of doc.streamAttachment(attachmentId)) { ... } ``` ### Incremental Queries ```typescript let cursor = null; for await (const { doc, cursor: currentCursor } of db.iterateChangesSince(cursor)) { cursor = currentCursor; } // Subsequent calls: only changed documents for await (const { doc, cursor: currentCursor } of db.iterateChangesSince(cursor)) { cursor = currentCursor; } ``` --- ## Source Code and Links - GitHub Repository: https://github.com/klehmann/MindooDB - npm Package: https://www.npmjs.com/package/mindoodb - Website: https://mindoodb.com - License: Apache 2.0 - Author: Mindoo GmbH, Karlsruhe, Germany