@prmichaelsen/remember-mcp 2.3.1 → 2.3.4
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.
- package/AGENT.md +20 -2
- package/CHANGELOG.md +27 -0
- package/agent/commands/acp.commit.md +511 -0
- package/agent/design/comment-memory-type.md +556 -0
- package/agent/design/unified-public-collection.md +545 -0
- package/agent/progress.yaml +26 -0
- package/agent/scripts/install.sh +25 -1
- package/agent/scripts/update.sh +37 -0
- package/dist/server-factory.js +6 -6
- package/dist/server.js +6 -6
- package/package.json +1 -1
- package/src/tools/confirm.ts +8 -6
|
@@ -0,0 +1,556 @@
|
|
|
1
|
+
# Comment Content Type - Threaded Discussions in Shared Spaces
|
|
2
|
+
|
|
3
|
+
**Concept**: Use existing `comment` content type for replies, enabling infinitely nested threaded discussions
|
|
4
|
+
**Created**: 2026-02-16
|
|
5
|
+
**Updated**: 2026-02-16
|
|
6
|
+
**Status**: Design Proposal - Zero New Tools Required
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## Overview
|
|
11
|
+
|
|
12
|
+
Use the existing `comment` content type for replies to memories in shared spaces. Comments enable infinitely nested threaded discussions while maintaining the ability to filter them out during space searches, keeping the main discovery experience clean.
|
|
13
|
+
|
|
14
|
+
**Phase 1 Scope**: Zero new tools required! Use existing `remember_create_memory` with `type: "comment"` and additional fields (`parent_id`, `thread_id`). Thread viewing uses existing `remember_search_space` with filters. Advanced features (dedicated thread tool, voting, moderation) deferred to future versions.
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## Problem Statement
|
|
19
|
+
|
|
20
|
+
### Current Limitations
|
|
21
|
+
|
|
22
|
+
1. **No Discussion Mechanism**: Users can't reply to memories in shared spaces
|
|
23
|
+
2. **No Threading**: Can't build conversations around interesting memories
|
|
24
|
+
3. **No Filtering**: If we add replies as regular memories, they clutter search results
|
|
25
|
+
4. **No Context**: Replies don't reference what they're replying to
|
|
26
|
+
|
|
27
|
+
### Use Cases
|
|
28
|
+
|
|
29
|
+
**Scenario 1**: User finds interesting memory in "The Void"
|
|
30
|
+
```
|
|
31
|
+
Memory: "I just discovered a great hiking trail in Colorado"
|
|
32
|
+
User wants to: "Which trail? I'm planning a trip there!"
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
**Scenario 2**: Discussion thread
|
|
36
|
+
```
|
|
37
|
+
Memory: "Best practices for TypeScript generics"
|
|
38
|
+
Comment 1: "Great point about constraint inference!"
|
|
39
|
+
Comment 2: "Have you tried conditional types?"
|
|
40
|
+
Comment 3: "This helped me solve my problem, thanks!"
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
**Scenario 3**: Clean discovery
|
|
44
|
+
```
|
|
45
|
+
Search "hiking trails" in The Void
|
|
46
|
+
→ Show only original memories (not 100 comments)
|
|
47
|
+
→ User can choose to view comments on interesting memories
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## Solution: Use Existing Content Type
|
|
53
|
+
|
|
54
|
+
### Architecture
|
|
55
|
+
|
|
56
|
+
**Use Existing `comment` Content Type**: Already in the 45 content types!
|
|
57
|
+
|
|
58
|
+
```typescript
|
|
59
|
+
// Create comment using existing remember_create_memory
|
|
60
|
+
remember_create_memory({
|
|
61
|
+
type: "comment", // ✅ Existing content type!
|
|
62
|
+
content: "Great post!",
|
|
63
|
+
parent_id: "memory123", // ✅ New field
|
|
64
|
+
parent_type: "memory", // ✅ New field
|
|
65
|
+
thread_id: "memory123", // ✅ New field
|
|
66
|
+
spaces: ["the_void"] // ✅ New field (for unified collection)
|
|
67
|
+
})
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### Key Design Decisions
|
|
71
|
+
|
|
72
|
+
1. **Reuse Content Type**: `type: "comment"` already exists
|
|
73
|
+
- No new doc_type needed
|
|
74
|
+
- Filter by content type: `type == "comment"`
|
|
75
|
+
- Consistent with existing architecture
|
|
76
|
+
|
|
77
|
+
2. **Add Thread Fields**: Extend Memory schema
|
|
78
|
+
- `parent_id`: Direct parent (memory or comment)
|
|
79
|
+
- `parent_type`: 'memory' | 'comment'
|
|
80
|
+
- `thread_id`: Root memory (for fetching entire thread)
|
|
81
|
+
- **No depth limit**: Comments can nest infinitely
|
|
82
|
+
|
|
83
|
+
3. **Space Inheritance**: Comments inherit parent's spaces
|
|
84
|
+
- Simplifies publishing
|
|
85
|
+
- Ensures comments stay with memory
|
|
86
|
+
- Automatic multi-space support
|
|
87
|
+
|
|
88
|
+
4. **Zero New Tools**: Reuse existing infrastructure
|
|
89
|
+
- `remember_create_memory` for creating comments
|
|
90
|
+
- `remember_search_space` for viewing comments
|
|
91
|
+
- `remember_update_memory` for editing comments
|
|
92
|
+
- `remember_delete_memory` for deleting comments
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
## Benefits
|
|
97
|
+
|
|
98
|
+
### 1. Clean Discovery Experience
|
|
99
|
+
|
|
100
|
+
**Search without comments** (default):
|
|
101
|
+
```typescript
|
|
102
|
+
remember_search_space({
|
|
103
|
+
spaces: ["the_void"],
|
|
104
|
+
query: "hiking trails"
|
|
105
|
+
// Filters out type: "comment" by default
|
|
106
|
+
})
|
|
107
|
+
// Returns only original memories, not replies
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
**Search with comments** (if needed):
|
|
111
|
+
```typescript
|
|
112
|
+
remember_search_space({
|
|
113
|
+
spaces: ["the_void"],
|
|
114
|
+
query: "hiking trails",
|
|
115
|
+
content_type: null // ✅ Don't filter by type = include comments
|
|
116
|
+
})
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
**Or filter to comments only**:
|
|
120
|
+
```typescript
|
|
121
|
+
remember_search_space({
|
|
122
|
+
spaces: ["the_void"],
|
|
123
|
+
query: "hiking trails",
|
|
124
|
+
content_type: "comment" // ✅ Only comments
|
|
125
|
+
})
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### 2. Threaded Discussions
|
|
129
|
+
|
|
130
|
+
**Create comment** (use existing tool):
|
|
131
|
+
```typescript
|
|
132
|
+
remember_create_memory({
|
|
133
|
+
type: "comment",
|
|
134
|
+
content: "Which trail?",
|
|
135
|
+
parent_id: "memory123",
|
|
136
|
+
parent_type: "memory",
|
|
137
|
+
thread_id: "memory123",
|
|
138
|
+
spaces: ["the_void"] // Inherited from parent
|
|
139
|
+
})
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
**Fetch thread** (use existing search):
|
|
143
|
+
```typescript
|
|
144
|
+
remember_search_space({
|
|
145
|
+
spaces: ["the_void"],
|
|
146
|
+
query: "", // Empty = get all
|
|
147
|
+
content_type: "comment",
|
|
148
|
+
filters: {
|
|
149
|
+
thread_id: "memory123" // Get all comments in this thread
|
|
150
|
+
},
|
|
151
|
+
limit: 100
|
|
152
|
+
})
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
**Response**: Flat list of comments, UI builds tree from `parent_id` relationships
|
|
156
|
+
|
|
157
|
+
### 3. Notification System
|
|
158
|
+
|
|
159
|
+
**Notify parent author**:
|
|
160
|
+
```
|
|
161
|
+
User A publishes memory to The Void
|
|
162
|
+
User B comments on it
|
|
163
|
+
→ User A gets notification: "Someone commented on your memory"
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
---
|
|
167
|
+
|
|
168
|
+
## Implementation
|
|
169
|
+
|
|
170
|
+
### New Tools
|
|
171
|
+
|
|
172
|
+
#### Phase 1: remember_create_comment (v2.5.0)
|
|
173
|
+
|
|
174
|
+
```typescript
|
|
175
|
+
{
|
|
176
|
+
name: 'remember_create_comment',
|
|
177
|
+
description: 'Create a comment (reply) to a memory or another comment in a shared space',
|
|
178
|
+
inputSchema: {
|
|
179
|
+
type: 'object',
|
|
180
|
+
properties: {
|
|
181
|
+
parent_id: {
|
|
182
|
+
type: 'string',
|
|
183
|
+
description: 'ID of memory or comment being replied to'
|
|
184
|
+
},
|
|
185
|
+
content: {
|
|
186
|
+
type: 'string',
|
|
187
|
+
description: 'Comment text'
|
|
188
|
+
},
|
|
189
|
+
parent_type: {
|
|
190
|
+
type: 'string',
|
|
191
|
+
enum: ['memory', 'comment'],
|
|
192
|
+
default: 'memory'
|
|
193
|
+
}
|
|
194
|
+
},
|
|
195
|
+
required: ['parent_id', 'content']
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
#### 2. remember_get_thread
|
|
201
|
+
|
|
202
|
+
```typescript
|
|
203
|
+
{
|
|
204
|
+
name: 'remember_get_thread',
|
|
205
|
+
description: 'Get a memory and all its comments (threaded discussion)',
|
|
206
|
+
inputSchema: {
|
|
207
|
+
type: 'object',
|
|
208
|
+
properties: {
|
|
209
|
+
memory_id: {
|
|
210
|
+
type: 'string',
|
|
211
|
+
description: 'ID of the root memory'
|
|
212
|
+
},
|
|
213
|
+
sort: {
|
|
214
|
+
type: 'string',
|
|
215
|
+
enum: ['recent', 'oldest'], // 'popular' requires voting
|
|
216
|
+
default: 'recent'
|
|
217
|
+
},
|
|
218
|
+
limit: {
|
|
219
|
+
type: 'number',
|
|
220
|
+
description: 'Max comments to return',
|
|
221
|
+
default: 100
|
|
222
|
+
}
|
|
223
|
+
},
|
|
224
|
+
required: ['memory_id']
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
#### 3. remember_vote_comment
|
|
230
|
+
|
|
231
|
+
```typescript
|
|
232
|
+
{
|
|
233
|
+
name: 'remember_vote_comment',
|
|
234
|
+
description: 'Upvote or downvote a comment',
|
|
235
|
+
inputSchema: {
|
|
236
|
+
type: 'object',
|
|
237
|
+
properties: {
|
|
238
|
+
comment_id: {
|
|
239
|
+
type: 'string',
|
|
240
|
+
description: 'ID of comment to vote on'
|
|
241
|
+
},
|
|
242
|
+
vote: {
|
|
243
|
+
type: 'string',
|
|
244
|
+
enum: ['up', 'down', 'remove'],
|
|
245
|
+
description: 'Vote type (remove = remove your vote)'
|
|
246
|
+
}
|
|
247
|
+
},
|
|
248
|
+
required: ['comment_id', 'vote']
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
#### 4. remember_flag_comment
|
|
254
|
+
|
|
255
|
+
```typescript
|
|
256
|
+
{
|
|
257
|
+
name: 'remember_flag_comment',
|
|
258
|
+
description: 'Flag a comment as inappropriate',
|
|
259
|
+
inputSchema: {
|
|
260
|
+
type: 'object',
|
|
261
|
+
properties: {
|
|
262
|
+
comment_id: {
|
|
263
|
+
type: 'string',
|
|
264
|
+
description: 'ID of comment to flag'
|
|
265
|
+
},
|
|
266
|
+
reason: {
|
|
267
|
+
type: 'string',
|
|
268
|
+
enum: ['spam', 'harassment', 'inappropriate', 'other'],
|
|
269
|
+
description: 'Reason for flagging'
|
|
270
|
+
}
|
|
271
|
+
},
|
|
272
|
+
required: ['comment_id', 'reason']
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
### Schema Changes
|
|
278
|
+
|
|
279
|
+
**Add to Weaviate schema**:
|
|
280
|
+
```typescript
|
|
281
|
+
// New properties for comments
|
|
282
|
+
{
|
|
283
|
+
name: 'parent_id',
|
|
284
|
+
dataType: 'text' as any,
|
|
285
|
+
description: 'ID of parent memory or comment'
|
|
286
|
+
},
|
|
287
|
+
{
|
|
288
|
+
name: 'parent_type',
|
|
289
|
+
dataType: 'text' as any,
|
|
290
|
+
description: 'Type of parent: memory or comment'
|
|
291
|
+
},
|
|
292
|
+
{
|
|
293
|
+
name: 'thread_id',
|
|
294
|
+
dataType: 'text' as any,
|
|
295
|
+
description: 'Root memory ID for thread queries'
|
|
296
|
+
},
|
|
297
|
+
{
|
|
298
|
+
name: 'upvotes',
|
|
299
|
+
dataType: 'number' as any,
|
|
300
|
+
description: 'Number of upvotes'
|
|
301
|
+
},
|
|
302
|
+
{
|
|
303
|
+
name: 'downvotes',
|
|
304
|
+
dataType: 'number' as any,
|
|
305
|
+
description: 'Number of downvotes'
|
|
306
|
+
},
|
|
307
|
+
{
|
|
308
|
+
name: 'flagged',
|
|
309
|
+
dataType: 'boolean' as any,
|
|
310
|
+
description: 'Whether comment has been flagged'
|
|
311
|
+
},
|
|
312
|
+
{
|
|
313
|
+
name: 'hidden',
|
|
314
|
+
dataType: 'boolean' as any,
|
|
315
|
+
description: 'Whether comment is hidden by moderators'
|
|
316
|
+
}
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
### Firestore Changes (Phase 1 - Basic Only)
|
|
320
|
+
|
|
321
|
+
**No additional Firestore collections needed for Phase 1**
|
|
322
|
+
|
|
323
|
+
Comments stored in Weaviate with basic fields only.
|
|
324
|
+
|
|
325
|
+
**Future Firestore Collections** (when ACL system ready):
|
|
326
|
+
- `users/{user_id}/votes/{comment_id}` - Vote tracking
|
|
327
|
+
- `comments/{comment_id}/moderation/{space_id}` - Per-space moderation
|
|
328
|
+
- `spaces/{space_id}/moderators/{user_id}` - Moderator permissions
|
|
329
|
+
|
|
330
|
+
---
|
|
331
|
+
|
|
332
|
+
## User Experience
|
|
333
|
+
|
|
334
|
+
### Scenario 1: Discovering and Commenting
|
|
335
|
+
|
|
336
|
+
```
|
|
337
|
+
1. User searches The Void: "best hiking trails"
|
|
338
|
+
→ Results show only memories (no comments)
|
|
339
|
+
|
|
340
|
+
2. User finds interesting memory: "Bear Lake Trail is amazing"
|
|
341
|
+
→ Clicks to view details
|
|
342
|
+
|
|
343
|
+
3. User sees comment count: "15 comments"
|
|
344
|
+
→ Clicks to view thread
|
|
345
|
+
|
|
346
|
+
4. User reads deeply nested discussion (10+ levels)
|
|
347
|
+
→ UI renders tree structure from flat comment list
|
|
348
|
+
|
|
349
|
+
5. User replies to a deeply nested comment
|
|
350
|
+
→ Creates comment with parent_id pointing to that comment
|
|
351
|
+
|
|
352
|
+
6. Original author gets notification
|
|
353
|
+
→ Can reply at any depth in the thread
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
### Scenario 2: Filtering Comments
|
|
357
|
+
|
|
358
|
+
```typescript
|
|
359
|
+
// Default: Comments not included
|
|
360
|
+
remember_search_space({
|
|
361
|
+
spaces: ["the_void"],
|
|
362
|
+
query: "hiking"
|
|
363
|
+
// include_comments: false (default)
|
|
364
|
+
})
|
|
365
|
+
// Returns: 10 memories
|
|
366
|
+
|
|
367
|
+
// Include comments
|
|
368
|
+
remember_search_space({
|
|
369
|
+
spaces: ["the_void"],
|
|
370
|
+
query: "hiking",
|
|
371
|
+
include_comments: true // ✅ Positive flag
|
|
372
|
+
})
|
|
373
|
+
// Returns: 10 memories + 50 comments = 60 results
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
---
|
|
377
|
+
|
|
378
|
+
## Trade-offs
|
|
379
|
+
|
|
380
|
+
### Pros
|
|
381
|
+
|
|
382
|
+
✅ **Clean Discovery**: Comments don't clutter search results
|
|
383
|
+
✅ **Threaded Discussions**: Enable conversations around memories
|
|
384
|
+
✅ **Community Engagement**: Upvotes, flags, moderation
|
|
385
|
+
✅ **Flexible**: Can include/exclude comments as needed
|
|
386
|
+
✅ **Scalable**: Separate doc_type enables efficient filtering
|
|
387
|
+
✅ **Notifications**: Authors know when someone engages
|
|
388
|
+
|
|
389
|
+
### Cons
|
|
390
|
+
|
|
391
|
+
❌ **Complexity**: New document type, new tools, new UI
|
|
392
|
+
❌ **Moderation**: Need to handle spam, harassment
|
|
393
|
+
❌ **Storage**: Comments add to storage costs
|
|
394
|
+
❌ **Performance**: Thread queries could be expensive
|
|
395
|
+
❌ **Notifications**: Need notification system
|
|
396
|
+
|
|
397
|
+
---
|
|
398
|
+
|
|
399
|
+
## Alternatives Considered
|
|
400
|
+
|
|
401
|
+
### Alternative 1: Comments as Regular Memories
|
|
402
|
+
|
|
403
|
+
**Approach**: Use existing `memory` type with `reply_to` field
|
|
404
|
+
|
|
405
|
+
**Pros**: Simpler, reuses existing infrastructure
|
|
406
|
+
**Cons**: Can't filter out replies, clutters search results
|
|
407
|
+
**Verdict**: ❌ Poor UX for discovery
|
|
408
|
+
|
|
409
|
+
### Alternative 2: Comments as Relationships
|
|
410
|
+
|
|
411
|
+
**Approach**: Use `relationship` type with `observation` as comment
|
|
412
|
+
|
|
413
|
+
**Pros**: Reuses existing type
|
|
414
|
+
**Cons**: Relationships are for connecting memories, not discussions
|
|
415
|
+
**Verdict**: ❌ Wrong semantic model
|
|
416
|
+
|
|
417
|
+
### Alternative 3: Separate Comments Collection
|
|
418
|
+
|
|
419
|
+
**Approach**: `Memory_public_comments` collection
|
|
420
|
+
|
|
421
|
+
**Pros**: Complete isolation
|
|
422
|
+
**Cons**: Can't search comments with memories, complex queries
|
|
423
|
+
**Verdict**: ❌ Too isolated
|
|
424
|
+
|
|
425
|
+
### Alternative 4: Comments in Firestore Only
|
|
426
|
+
|
|
427
|
+
**Approach**: Store comments in Firestore, not Weaviate
|
|
428
|
+
|
|
429
|
+
**Pros**: Simpler Weaviate schema
|
|
430
|
+
**Cons**: Can't search comment content, no vector similarity
|
|
431
|
+
**Verdict**: ❌ Loses search capability
|
|
432
|
+
|
|
433
|
+
---
|
|
434
|
+
|
|
435
|
+
## Security Considerations
|
|
436
|
+
|
|
437
|
+
### Comment Moderation
|
|
438
|
+
|
|
439
|
+
**Auto-hide spam**:
|
|
440
|
+
```typescript
|
|
441
|
+
if (comment.flagged_count > 3) {
|
|
442
|
+
comment.hidden = true;
|
|
443
|
+
notifyModerators(comment);
|
|
444
|
+
}
|
|
445
|
+
```
|
|
446
|
+
|
|
447
|
+
**Rate limiting**:
|
|
448
|
+
```typescript
|
|
449
|
+
// Max 10 comments per user per hour
|
|
450
|
+
const recentComments = await getRecentComments(userId, '1h');
|
|
451
|
+
if (recentComments.length >= 10) {
|
|
452
|
+
throw new Error('Rate limit exceeded');
|
|
453
|
+
}
|
|
454
|
+
```
|
|
455
|
+
|
|
456
|
+
### Vote Manipulation
|
|
457
|
+
|
|
458
|
+
**One vote per user per comment**:
|
|
459
|
+
```typescript
|
|
460
|
+
// Store in Firestore: users/{user_id}/votes/{comment_id}
|
|
461
|
+
const existingVote = await getVote(userId, commentId);
|
|
462
|
+
if (existingVote) {
|
|
463
|
+
// Update or remove vote
|
|
464
|
+
} else {
|
|
465
|
+
// Create new vote
|
|
466
|
+
}
|
|
467
|
+
```
|
|
468
|
+
|
|
469
|
+
**Prevent self-voting**:
|
|
470
|
+
```typescript
|
|
471
|
+
if (comment.user_id === userId) {
|
|
472
|
+
throw new Error('Cannot vote on your own comment');
|
|
473
|
+
}
|
|
474
|
+
```
|
|
475
|
+
|
|
476
|
+
---
|
|
477
|
+
|
|
478
|
+
## Open Questions
|
|
479
|
+
|
|
480
|
+
1. **Edit/delete comments?**
|
|
481
|
+
- Recommendation: Yes, with edit history
|
|
482
|
+
- Show "[edited]" indicator
|
|
483
|
+
|
|
484
|
+
2. **Anonymous comments?**
|
|
485
|
+
- Recommendation: No, require attribution
|
|
486
|
+
- Reduces spam and abuse
|
|
487
|
+
|
|
488
|
+
3. **Comment length limit?**
|
|
489
|
+
- Recommendation: 1000 characters
|
|
490
|
+
- Shorter than memories (10,000)
|
|
491
|
+
|
|
492
|
+
4. **Notification system?**
|
|
493
|
+
- Recommendation: Firestore + Cloud Functions
|
|
494
|
+
- Real-time notifications
|
|
495
|
+
|
|
496
|
+
---
|
|
497
|
+
|
|
498
|
+
## Implementation Roadmap
|
|
499
|
+
|
|
500
|
+
### Phase 1: Basic Comments (v2.5.0)
|
|
501
|
+
|
|
502
|
+
- [ ] Add `comment` doc_type to schema
|
|
503
|
+
- [ ] Implement `remember_create_comment`
|
|
504
|
+
- [ ] Implement `remember_get_thread`
|
|
505
|
+
- [ ] Update search to exclude comments by default
|
|
506
|
+
- [ ] Add `include_comments` parameter (default: false)
|
|
507
|
+
|
|
508
|
+
### Phase 2: Engagement (v2.6.0)
|
|
509
|
+
|
|
510
|
+
- [ ] Implement `remember_vote_comment`
|
|
511
|
+
- [ ] Add upvote/downvote tracking in Firestore
|
|
512
|
+
- [ ] Sort comments by popularity
|
|
513
|
+
- [ ] Show vote counts in UI
|
|
514
|
+
|
|
515
|
+
### Phase 3: Moderation (v2.7.0)
|
|
516
|
+
|
|
517
|
+
- [ ] Implement `remember_flag_comment` (with space_id)
|
|
518
|
+
- [ ] Add per-space moderation tracking in Firestore
|
|
519
|
+
- [ ] Implement `remember_hide_comment` (moderator tool)
|
|
520
|
+
- [ ] Auto-hide heavily flagged comments per space
|
|
521
|
+
- [ ] Filter hidden comments when fetching threads
|
|
522
|
+
- [ ] Moderator dashboard per space
|
|
523
|
+
|
|
524
|
+
### Phase 4: Notifications (v2.8.0)
|
|
525
|
+
|
|
526
|
+
- [ ] Notify authors of new comments
|
|
527
|
+
- [ ] Notify users of replies to their comments
|
|
528
|
+
- [ ] Email/push notification integration
|
|
529
|
+
- [ ] Notification preferences
|
|
530
|
+
|
|
531
|
+
---
|
|
532
|
+
|
|
533
|
+
## Success Criteria
|
|
534
|
+
|
|
535
|
+
- [ ] Users can comment on memories in shared spaces
|
|
536
|
+
- [ ] Comments don't clutter search results by default
|
|
537
|
+
- [ ] Thread view shows infinitely nested comments correctly
|
|
538
|
+
- [ ] UI efficiently builds tree from flat comment list
|
|
539
|
+
- [ ] Upvotes/downvotes work and affect sorting
|
|
540
|
+
- [ ] Flagging system prevents spam per space
|
|
541
|
+
- [ ] Comments can be hidden in one space but visible in others
|
|
542
|
+
- [ ] Moderators can manage comments in their spaces
|
|
543
|
+
- [ ] Authors receive notifications
|
|
544
|
+
- [ ] Performance acceptable with 1000+ comments per memory
|
|
545
|
+
- [ ] All tests passing
|
|
546
|
+
|
|
547
|
+
---
|
|
548
|
+
|
|
549
|
+
**Status**: Design Proposal - Awaiting Approval
|
|
550
|
+
**Recommendation**: Implement in v2.5.0 after unified public collection (v2.4.0)
|
|
551
|
+
|
|
552
|
+
**Next Steps**:
|
|
553
|
+
1. Review and approve design
|
|
554
|
+
2. Decide on open questions
|
|
555
|
+
3. Create implementation tasks
|
|
556
|
+
4. Begin Phase 1 development
|