@bsv/overlay 0.6.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,345 @@
1
+ # Query Performance and Indexing for Overlays
2
+
3
+ [🏠 Home](../README.md) | [📚 API](../API.md) | [💡 Concepts](./README.md) | [📖 Examples](../examples/README.md) | [⚙️ Internal](../internal/README.md)
4
+
5
+ **Navigation:** [Overview](./00-overview.md) | [Best Practices](./01-best-practices.md) | [Query Performance](./02-query-performance.md) | [Database Monitoring](./03-database-monitoring.md) | [Pagination Example](./04-pagination-example.md) | [Recommendations Summary](./05-recommendations-summary.md)
6
+
7
+ ---
8
+
9
+ ## Overview
10
+
11
+ Efficient query design is critical for scalable overlay performance. Lookup Services often serve thousands of queries per day—fetching messages, reactions, and thread activity—so poor indexing or unbounded queries can quickly degrade performance.
12
+
13
+ This document explains how to design efficient queries for overlay Lookup Services, using real examples from Convo Messenger.
14
+
15
+ ---
16
+
17
+ ## 1. Query Design Guidelines
18
+
19
+ ### 1.1 Use Indexed Fields for All Queries
20
+
21
+ Indexes are critical for overlay scalability. Without them, MongoDB must perform full collection scans — a major performance bottleneck.
22
+
23
+ **Always index fields used in query filters**, such as:
24
+
25
+ * `threadId`
26
+ * `sender`
27
+ * `recipient`
28
+ * `createdAt`
29
+
30
+ Example:
31
+
32
+ ```js
33
+ db.convoMessages.createIndex({ threadId: 1 });
34
+ db.convoMessages.createIndex({ parentMessageId: 1 });
35
+ db.convoMessages.createIndex({ threadId: 1, createdAt: -1 });
36
+ db.convoReactions.createIndex({ threadId: 1 });
37
+ ```
38
+
39
+ These fields match the filters used by:
40
+
41
+ * `listThreadMessages`
42
+ * `listReplies`
43
+ * `listThreadReactions`
44
+ * `countThreadMessages`
45
+ * `countReplies`
46
+
47
+ Rule:
48
+ Design indexes to match the exact fields your Lookup queries use.
49
+
50
+ ### 1.2 Use Range Queries for Time-Based Lookups
51
+
52
+ If you need to filter messages by time, use
53
+
54
+ ```typescript
55
+ { createdAt: { $gte: start, $lte: end } }
56
+ ```
57
+
58
+ Example pattern (recommended if your overlay uses time-range queries):
59
+
60
+ ```typescript
61
+ db.messages.find({
62
+ threadId,
63
+ createdAt: { $gte: startTime }
64
+ })
65
+ .sort({ createdAt: -1 })
66
+ .limit(50)
67
+ ```
68
+
69
+ This ensures MongoDB uses timestamp indexes efficiently.
70
+
71
+ ### 1.3 Combine Pagination With Indexed Sorts
72
+
73
+ When paginating through sorted data, combine `skip` / `limit` with an indexed sort key.
74
+
75
+ ```typescript
76
+ async listThreadMessages(threadId, skip, limit) {
77
+ return await this.messages
78
+ .aggregate([
79
+ { $match: { threadId } },
80
+ { $sort: { createdAt: -1 } },
81
+ { $skip: skip },
82
+ { $limit: limit }
83
+ ])
84
+ .toArray();
85
+ }
86
+ ```
87
+
88
+ Ensure the sort key (`createdAt`) matches an existing index to avoid in-memory sorting.
89
+
90
+ ---
91
+
92
+ ## 2. Common Anti-Patterns
93
+
94
+ | Problematic Pattern | Description | Recommended Fix |
95
+ | ---------------------------- | ------------------------------------------------------- | --------------------------------------------------- |
96
+ | **Unindexed Filters** | Querying on non-indexed fields causes full scans. | Add composite indexes on frequent filter fields. |
97
+ | **Regex or `$text` queries** | Regex searches prevent index usage. | Use prefix matches or precomputed lowercase fields. |
98
+ | **Large `$in` filters** | `$in` with many values increases memory and CPU load. | Batch requests or use intermediate caching. |
99
+ | **Unbounded queries** | Returning unbounded lists consumes memory. | Always apply limit. |
100
+ | **Sorting without an index** | Forces MongoDB to sort in memory. | Add compound index with your sort key. |
101
+
102
+ Examples to avoid:
103
+
104
+ ```typescript
105
+ // ❌ DO NOT DO THIS
106
+ db.messages.find({}).sort({ createdAt: -1 });
107
+
108
+ // ❌ Breaks index usage
109
+ db.messages.find({ sender: { $regex: '^03' } });
110
+ ```
111
+
112
+ ---
113
+
114
+ ## 3. MongoDB Indexing Best Practices
115
+
116
+ ### 3.1 Use Compound Indexes
117
+
118
+ For overlays, most queries filter by a primary grouping field (such as threadId) and a secondary field (such as createdAt). Compound indexes drastically improve performance:
119
+
120
+ ```js
121
+ // convoMessages collection
122
+ db.convoMessages.createIndex({ threadId: 1 });
123
+ db.convoMessages.createIndex({ parentMessageId: 1 });
124
+ db.convoMessages.createIndex({ threadId: 1, createdAt: -1 });
125
+
126
+ // convoReactions collection
127
+ db.convoReactions.createIndex({ threadId: 1 });
128
+
129
+ // convoThreads collection
130
+ db.convoThreads.createIndex({ threadId: 1 }, { unique: true });
131
+ ```
132
+
133
+ These support efficient implmentations of:
134
+
135
+ **Messages in a thread**
136
+ ```typescript
137
+ this.messages
138
+ .find({ threadId })
139
+ .sort({ createdAt: 1 });
140
+ ```
141
+
142
+ **Replies to a message**
143
+ ```typescript
144
+ this.messages
145
+ .find({ parentMessageId })
146
+ .sort({ createdAt: 1 });
147
+ ```
148
+
149
+ **Latest messages across all threads**
150
+ Aggregation pipeline:
151
+ ```typescript
152
+ [
153
+ { $sort: { createdAt: -1 } },
154
+ { $group: {
155
+ _id: "$threadId",
156
+ threadId: { $first: "$threadId" },
157
+ txid: { $first: "$txid" },
158
+ outputIndex: { $first: "$outputIndex" },
159
+ sender: { $first: "$sender" },
160
+ header: { $first: "$header" },
161
+ encryptedPayload: { $first: "$encryptedPayload" },
162
+ createdAt: { $first: "$createdAt" },
163
+ threadName: { $first: "$threadName" },
164
+ parentMessageId: { $first: "$parentMessageId" },
165
+ uniqueId: { $first: "$uniqueId" }
166
+ }},
167
+ { $sort: { createdAt: -1 } },
168
+ { $skip: skip },
169
+ { $limit: limit }
170
+ ]
171
+ ```
172
+
173
+ All supported by the existing indexes.
174
+
175
+ ---
176
+
177
+ ### 3.2 Monitor Index Usage
178
+
179
+ Use MongoDB’s `explain()` command to verify index utilization:
180
+
181
+ Example (threads’ messages lookup):
182
+ ```js
183
+ db.convoMessages
184
+ .find({ threadId: "abc123" })
185
+ .sort({ createdAt: -1 })
186
+ .explain("executionStats");
187
+ ```
188
+
189
+ Key metrics to monitor:
190
+
191
+ * `executionTimeMillis` - how long the query took
192
+ * `totalDocsExamined` - number of documents scanned
193
+ * `totalKeysExamined` - number of index entries scanned
194
+
195
+ **Goal:**
196
+ `totalDocsExamined` should be low (ideally equal to or close to limit) for all Convo queries.
197
+
198
+ ### 3.3 Rebuild Indexes Periodically
199
+
200
+ Indexes can fragment over time, especially with:
201
+
202
+ * frequent inserts
203
+ * deletes (like messages deleted when spent)
204
+ * updates
205
+
206
+ Schedule index rebuilds during low-traffic periods:
207
+ ```js
208
+ db.convoMessages.reIndex();
209
+ db.convoReactions.reIndex();
210
+ db.convoThreads.reIndex();
211
+ ```
212
+
213
+ ---
214
+
215
+ ## 4. Measuring Query Performance
216
+
217
+ ### 4.1 Use Built-In Mongo Metrics
218
+
219
+ MongoDB includes a lightweight profiler that records slow queries.
220
+ This is the easiest way for overlay authors to discover inefficient lookups.
221
+
222
+ Enable profiling for any query taking longer than 100 ms:
223
+
224
+ ```js
225
+ db.setProfilingLevel(1, { slowms: 100 });
226
+ ```
227
+
228
+ Slow query entries appear in the system.profile collection and can be inspected manually or exported to monitoring tools such as:
229
+
230
+ * Prometheus
231
+ * Grafana
232
+ * ELK / OpenSearch
233
+ * Custom dashboards
234
+
235
+ What to look for:
236
+
237
+ * High executionTimeMillis
238
+ * High totalDocsExamined (index not used)
239
+ * High totalKeysExamined (index scan too large)
240
+
241
+ Correctly indexed Convo queries should examine very small numbers of documents.
242
+
243
+ ### 4.2 Add Overlay-Level Timing Logs
244
+
245
+ Your Lookup Service can log query timing directly at the overlay level.
246
+ This measures actual latency experienced by clients, not just database timings.
247
+
248
+ Example (Convo):
249
+
250
+ ```typescript
251
+ const start = performance.now();
252
+ const messages = await this.storage.listThreadMessages(
253
+ threadId,
254
+ skip,
255
+ limit
256
+ );
257
+ console.log(
258
+ `[ls_convo] listThreadMessages(${threadId}) took ${performance.now() - start} ms`
259
+ );
260
+ ```
261
+
262
+ You can add similar timing logs to:
263
+
264
+ * listThreadReactions
265
+ * listReplies
266
+ * listLatestMessages
267
+ *countThreadMessages
268
+ * countReplies
269
+
270
+ This makes it easy to identify:
271
+
272
+ * Query patterns that degrade at scale
273
+ * Missed indexes
274
+ * Inefficient aggregation pipelines
275
+
276
+ Overlay-level logs are invaluable for practical debugging because they show the exact request→response timing seen by apps like Convo Messenger.
277
+
278
+ ### 4.3 Performance Visualization Tooling (Proposed)
279
+
280
+ Although not required for overlay authors today, you can add your own simple visualizations.
281
+
282
+ Potential enhancements include:
283
+
284
+ * **Query Time Dashboard**
285
+
286
+ A small local dashboard showing average duration per lookup type (e.g., listThreadMessages, listReplies).
287
+
288
+ * **Slow Query Warnings**
289
+
290
+ Log a warning if any Lookup query exceeds a threshold (e.g., 200 ms).
291
+
292
+ * **Index Usage Reports**
293
+
294
+ A small script that uses explain("executionStats") on common queries and prints index efficiency.
295
+
296
+ These tools can help team-level debugging (e.g., Convo, Tempo, MetaMarket), but they are not a requirement for overlay authors and should not be confused with BSVA-level monitoring.
297
+
298
+ ---
299
+
300
+ ## 5. Practical Example: Convo Messenger
301
+
302
+ Convo Messenger provides a useful real-world example of how overlay query performance improves when Lookup queries are designed around indexed fields and predictable patterns.
303
+
304
+ Convo optimized its Lookup queries by:
305
+
306
+ Indexing fields used in queries, including:
307
+
308
+ - `threadId`
309
+ - `parentMessageId`
310
+ - `createdAt`
311
+ - compound index: `{ threadId: 1, createdAt: -1 }`
312
+
313
+ Using pagination everywhere, with sensible limits such as:
314
+
315
+ - `50` for message lists
316
+ - `100` for reaction lists
317
+
318
+ Ensuring query patterns always match existing indexes, including:
319
+
320
+ - filtering by `threadId`
321
+ - time ordering by `createdAt`
322
+ - grouping aggregation only after an indexed sort
323
+ - avoiding unbounded fetches (`find({})`)
324
+
325
+
326
+ These design choices ensure Convo’s Lookup Service remains stable and scales predictably, even as message volume grows.
327
+
328
+ This example illustrates how overlays can maintain efficient performance without requiring complex systems—just well-designed indexes, selective filters, and consistent pagination.
329
+
330
+ ---
331
+
332
+ ## 6. Recommendations Summary
333
+
334
+ | Area | Recommendation |
335
+ | ------------ | ----------------------------------------------------------- |
336
+ | Query Design | Always use indexed filters; avoid regex and `$in` scans. |
337
+ | Indexing | Add indexes that match your overlay’s query filters (e.g., `{ threadId, createdAt }`). |
338
+ | Pagination | Combine with indexed sorts to avoid in-memory sorting. |
339
+ | Measurement | Use MongoDB profiler and `explain('executionStats')` to detect slow queries. |
340
+ | Tooling | Explore adding an Overlay Query Monitor to Overlay Express. |
341
+ | Logging | Add timing logs in Lookup Services to measure real client-facing latency |
342
+
343
+ ---
344
+
345
+ Next file: [`03-database-monitoring.md`](./03-database-monitoring.md) — focuses on database health, read-only access for debugging, and workflows for CARS admins.
@@ -0,0 +1,211 @@
1
+ # Overlay Database Monitoring and Debugging
2
+
3
+ [🏠 Home](../README.md) | [📚 API](../API.md) | [💡 Concepts](./README.md) | [📖 Examples](../examples/README.md) | [⚙️ Internal](../internal/README.md)
4
+
5
+ **Navigation:** [Overview](./00-overview.md) | [Best Practices](./01-best-practices.md) | [Query Performance](./02-query-performance.md) | [Database Monitoring](./03-database-monitoring.md) | [Pagination Example](./04-pagination-example.md) | [Recommendations Summary](./05-recommendations-summary.md)
6
+
7
+ ---
8
+
9
+ ## Overview
10
+
11
+ Monitoring and debugging overlay databases helps ensure reliability, correctness, and predictable performance.
12
+ As overlays grow, developers benefit from having ways to inspect what their Lookup Service is storing and validate that Topic Manager admission logic is working as intended.
13
+
14
+ This document outlines optional strategies for:
15
+
16
+ * Providing **safe, read-only** inspection of Lookup data
17
+ * Building **debugging workflows** during overlay development
18
+ * Tracking **basic performance and health metrics**
19
+ * Ensuring correctness without exposing sensitive data or modifying overlay protocols
20
+
21
+ These recommendations are intended for **overlay developers**, not system administrators of BSVA infrastructure.
22
+
23
+ ---
24
+
25
+ ## 1. Goals
26
+
27
+ Overlay authors may want to:
28
+
29
+ * Verify what data is stored after Topic Manager admission
30
+ * Inspect the parsed documents produced by PushDrop decoding
31
+ * Measure lookup latency or query efficiency
32
+ * Debug message ingestion, reactions, or thread activity during development
33
+ * Provide trusted team members with read-only visibility in test or staging environments
34
+
35
+ All monitoring discussed here is optional and applies only to the overlay developer’s own deployment.
36
+
37
+ ---
38
+
39
+ ## 2. Read-Only Access for Debugging
40
+
41
+ ### 2.1 Purpose
42
+
43
+ Read-only visibility is useful during development or internal debugging because it allows developers to:
44
+
45
+ * Confirm that the Lookup Service stored the expected metadata
46
+ * Inspect whether fields such as `threadId`, `createdAt`, or `parentMessageId` were parsed correctly
47
+ * Understand why a transaction may not appear in query results
48
+
49
+ ### 2.2 Implementation Options
50
+
51
+ Overlay authors can choose from several approaches depending on their internal workflow.
52
+
53
+ #### Option A: MongoDB Read-Only Role
54
+
55
+ MongoDB allows creation of roles that grant read-only access to specific collections:
56
+
57
+ ```js
58
+ db.createUser({
59
+ user: "overlayReader",
60
+ pwd: "strongpassword",
61
+ roles: [
62
+ { role: "read", db: "overlaydb" }
63
+ ]
64
+ });
65
+ ```
66
+
67
+ This is useful for:
68
+
69
+ * Internal developers
70
+ * Debugging in staging environments
71
+ * Letting trusted team members inspect lookup data
72
+
73
+ #### Option B: Internal Read-Only Endpoint
74
+
75
+ Some teams choose to expose a controlled debug route during development:
76
+
77
+ ```typescript
78
+ router.get('/debug/messages', async (req, res) => {
79
+ const threadId = req.query.threadId;
80
+ const results = await storage.listThreadMessages(threadId, 0, 25);
81
+ res.json(results);
82
+ });
83
+ ```
84
+
85
+ **Important:**
86
+ Such endpoints must not be exposed publicly. They should be protected with:
87
+
88
+ * API keys
89
+ * Admin tokens
90
+ * IP allowlists
91
+ * Or disabled entirely in production
92
+
93
+ This is entirely optional and depends on each developer’s debugging workflow.
94
+
95
+ ---
96
+
97
+ ## 3. Health and Performance Metrics
98
+
99
+ These metrics are optional but useful during development or debugging.
100
+
101
+ ### 3.1 Basic Metrics
102
+
103
+ Overlay authors may choose to track:
104
+
105
+ * Collection size and document count
106
+ * Index size and index efficiency
107
+ * Average query execution time for common lookups
108
+ * Latency from Topic Manager admission to Lookup write
109
+ * Count of decode or parse failures
110
+
111
+ These can be logged periodically or exported to monitoring tools like Prometheus or Grafana if desired.
112
+
113
+ Example minimal metric:
114
+
115
+ ```typescript
116
+ app.get('/metrics', async (req, res) => {
117
+ const stats = await db.collection('convoMessages').stats();
118
+ res.send(`convo_messages_bytes ${stats.size}\n`);
119
+ });
120
+ ```
121
+
122
+ ### 3.2 Transaction Admission Tracking
123
+
124
+ During development, Topic Managers can log admission decisions:
125
+
126
+ ```typescript
127
+ console.log(`[tm_convo] admitted output ${txid}:${vout}`);
128
+ ```
129
+
130
+ This helps correlate:
131
+
132
+ * The BEEF transaction
133
+ * Decoded PushDrop fields
134
+ * The resulting Lookup Service document
135
+
136
+ This logging is optional and purely for debugging the overlay’s own ingestion logic.
137
+
138
+ ---
139
+
140
+ ## 4. Debugging Workflow Example
141
+
142
+ A typical overlay debugging workflow might look like:
143
+
144
+ 1. Identify the txid of a message that should appear in the UI
145
+ 2. Query the Lookup data (using read-only DB access or internal endpoint)
146
+ 3. Verify that the Topic Manager correctly decoded the PushDrop fields
147
+ 4. Ensure Lookups return expected results (e.g., thread messages, replies, reactions)
148
+ 5. If performance issues appear, check index usage via `explain("executionStats")`
149
+ 6. If admission issues appear, review Topic Manager logs
150
+
151
+ This workflow helps developers confirm correctness without modifying protocol-level logic.
152
+
153
+ ---
154
+
155
+ ## 5. Optional Tools and Enhancements
156
+
157
+ These tools are optional and useful only in development environments.
158
+
159
+ ### 5.1 Overlay Health Dashboard
160
+
161
+ A lightweight web interface integrated into Overlay Express that would:
162
+
163
+ * Display real-time query performance (e.g., avg lookup latency)
164
+ * Show admission rates per Topic Manager
165
+ * Track DB growth and index efficiency
166
+ * Provide a query console for authorized users
167
+
168
+ This is helpful for overlay teams during debugging or feature development.
169
+
170
+ ### 5.2 Integration With Existing Mongo Tooling
171
+
172
+ Developers can use existing Mongo tools with read-only credentials:
173
+
174
+ * Mongo Express
175
+ * MongoDB Compass
176
+ * Atlas Monitoring
177
+
178
+ This allows safe browsing of Lookup documents without risk of modification.
179
+
180
+ ---
181
+
182
+ ## 6. Security Considerations
183
+
184
+ To avoid security risks:
185
+
186
+ * Restrict read-only access to internal team members
187
+ * Do not expose debugging endpoints publicly
188
+ * Use authentication (API keys, tokens) for any admin routes
189
+ * Avoid logging user data such as:
190
+ * CurvePoint headers
191
+ * Encrypted payloads
192
+ * Identity certificates
193
+ * Private metadata
194
+
195
+ Logs should focus on metadata only, such as txid, threadId, and timestamps.
196
+
197
+ ---
198
+
199
+ ## 7. Summary of Recommendations
200
+
201
+ | Area | Recommendation |
202
+ | ----------- | ------------------------------------------------------------------ |
203
+ | Read Access | Provide secure read-only access for overlay and CARS admins. |
204
+ | Metrics | Track query latency, DB size, and failed transactions. |
205
+ | Logging | Record admission flow from Topic Manager to Lookup. |
206
+ | Tools | Use Mongo Express or Compass with read-only roles. |
207
+ | Security | Restrict debugging endpoints and sanitize data. |
208
+
209
+ ---
210
+
211
+ Next file: [`04-pagination-example.md`](./04-pagination-example.md) — Demonstrates performance improvements from pagination in Convo Messenger overlay queries.