OmniStream Docs
  • Panduan Pengguna
  • Developer
  • API Reference
Developer Hub
Pendahuluan
Autentikasi
Model Data
    Ikhtisar Model DataSchema PostgreSQLKoleksi MongoDBRedis Pub/SubModel AgentModel ContactModel ConversationModel MessageRoles & Permissions
Webhook
WebSocket
Self-Hosting
Error & Rate Limit
Model Data

Koleksi MongoDB

Koleksi MongoDB

OmniStream menyimpan dua kelas data di MongoDB: pesan chat (messages) dan payload webhook mentah (webhook_audit). Alasan kedua kelas ini bukan di PostgreSQL sama: volume tinggi, dominan append-only, dan jarang di-update.

Database name default: omnistream (di-override lewat MONGODB_URI). Koleksi dan indeks dibuat otomatis saat service pertama kali start, via setup_indexes() di crates/omni-common/src/db/mongodb.rs:31.

Koleksi messages

Setiap dokumen merepresentasikan satu pesan chat. Struct Rust dan schema lapangan lengkap dibahas di developer/model-data/message — halaman ini fokus pada koleksinya (indeks, volume, pattern akses).

Indeks yang dibuat otomatis

Dari setup_indexes (mongodb.rs:31-104):

  1. Compound { conversation_id: 1, created_at: 1 } Query hot path: "ambil N pesan terakhir di conversation X, urut waktu". Cursor pagination memakai ini.

  2. Sparse unique { external_id: 1 } Dedup pesan webhook. Field boleh null (mis. pesan outbound sistem yang belum punya ID dari Meta), sparse index mengizinkan banyak null tanpa konflik.

  3. Text { "content.body": "text", "content.text": "text", "content.caption": "text" } dengan opsi language_override = "text_search_language". Full-text search pesan di halaman Inbox. language_override dipakai agar field language.code di payload template WhatsApp tidak salah diinterpretasi sebagai hint bahasa indeks (salah satu bug awal yang sudah ditangani — setup_indexes otomatis men-drop indeks text lama kalau tidak memiliki language_override dan membuatnya ulang).

Pattern akses umum

PatternQuery
Ambil 50 pesan terakhir per conversationfind({conversation_id}).sort({created_at: -1}).limit(50)
Pagination cursorfind({conversation_id, _id: {$lt: cursor}}).sort({_id: -1})
Full-text searchfind({$text: {$search: "...", $language: "simple"}})
Dedup pada webhook ingestUpsert by external_id + conversation_id

Volume

Per percakapan aktif, ekspektasi kira-kira 20-200 dokumen. Pada tenant yang ramai, koleksi bisa mencapai puluhan juta dokumen — itu sebabnya kami tidak memasang TTL di sini. Histori pesan adalah data bisnis yang harus dipertahankan. Pembersihan dilakukan secara eksplisit lewat tool admin (bukan bagian v1).

Koleksi webhook_audit

Dokumen di koleksi ini adalah payload mentah dari setiap webhook inbound yang diterima webhook-ingestor, disimpan sebelum parsing. Tujuannya tiga:

  1. Replay — kalau parser punya bug, kita bisa mengulang ingest dari raw payload tanpa meminta ulang ke Meta.
  2. Forensik — debug kenapa sebuah pesan tidak muncul di UI: cek apakah webhook bahkan sampai ke kita.
  3. Audit eksternal — bukti bahwa integrasi channel sedang hidup (jumlah dokumen per hari = throughput).

Struct Rust ada di crates/omni-common/src/models/webhook_audit.rs.

Indeks TTL

Tidak seperti messages, webhook_audit ada TTL:

Code
// crates/omni-common/src/db/mongodb.rs:106-122 // ── webhook_audit collection ── // TTL index: auto-delete documents after 90 days let webhook_audit = db.collection::<::bson::Document>("webhook_audit"); webhook_audit .create_index( IndexModel::builder() .keys(doc! { "received_at": 1 }) .options( IndexOptions::builder() .expire_after(Duration::from_secs(90 * 24 * 60 * 60)) // 90 days .build(), ) .build(), None, ) .await?; info!("MongoDB index created: webhook_audit.received_at (TTL 90 days)");

Semua dokumen dihapus otomatis oleh MongoDB setelah 90 hari sejak received_at. Kalau anda butuh retention lebih lama (regulated industry, audit legal), edit nilai expire_after di mongodb.rs dan restart service — MongoDB akan mengubah TTL indeks tanpa drop-and-create.

Koneksi dan konfigurasi

Variabel lingkungan:

  • MONGODB_URI — wajib (mis. mongodb://mongo:27017/omnistream). Tidak ada nilai default; service gagal start kalau kosong.

Connection pool: omni-common membangun mongodb::Client sekali per service lewat db::mongodb::build_client() dan men-share-nya via AppState. Seluruh service memakai UUID sebagai BinData(0) (bukan sebagai string) supaya ukuran index lebih kecil dan query tipe-safe — konversi uuid::Uuid ↔ bson::Binary ditangani oleh helper bson::Uuid::from(uuid::Uuid).

Troubleshooting cepat

GejalaPenyebab umum
Pesan inbound tidak muncul di UI, tapi webhook Meta OKCek webhook_audit — kalau ada raw payload tapi messages kosong, bug parser
Text search warning "language override ..."Indeks text lama. Restart service: setup_indexes auto-drop dan rebuild
Duplikasi pesan di conversationexternal_id tidak terisi pada ingest. Cek parser channel terkait
Koleksi webhook_audit terus tumbuhFitur TTL bekerja di background — tunggu 24 jam pertama, MongoDB men-sweep secara berkala

Referensi

  • Model Rust: crates/omni-common/src/models/message.rs, crates/omni-common/src/models/webhook_audit.rs
  • Setup indeks: crates/omni-common/src/db/mongodb.rs::setup_indexes (mongodb.rs:31-130)
  • Parser channel: crates/chat-engine/src/parser/*.rs
  • Detail field Message: developer/model-data/message
Last modified on June 8, 2026
Schema PostgreSQLRedis Pub/Sub
On this page
  • Koleksi messages
    • Indeks yang dibuat otomatis
    • Pattern akses umum
    • Volume
  • Koleksi webhook_audit
    • Indeks TTL
  • Koneksi dan konfigurasi
  • Troubleshooting cepat
  • Referensi
Rust