Skip to content

Conversation

@zzacharo
Copy link
Member

@zzacharo zzacharo commented Oct 27, 2025

closes #107

@zzacharo zzacharo force-pushed the comments-threading-rfc branch 3 times, most recently from 14ed33c to d7b6bd0 Compare October 27, 2025 10:07
@zzacharo zzacharo moved this to In review 🔍 in Sprint Q4/2025 Oct 27, 2025
@zzacharo zzacharo moved this from In review 🔍 to In progress in Sprint Q4/2025 Oct 27, 2025
@zzacharo zzacharo force-pushed the comments-threading-rfc branch from d7b6bd0 to fbe0ed4 Compare October 27, 2025 10:27
Copy link
Member

@palkerecsenyi palkerecsenyi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks Zach, this looks great and I agree with the 1-level limit, this makes it much simpler. The API routes are also nicely laid out, I don't think there's any better way of doing this.


### **Search index design**

Children are indexed inline with their parent for efficient retrieval and display. The search mappings include:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Apologies if I misunderstand: won't this mean that child comments are retrieved twice, once for the search query and once for the systemfield calculation? Or will we filter for only null parent_ids during the search query and then just fill in the children with the systemfield?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

During the search query, the children are already indexed. During the systemfield calculation, they are retrieved and then cached locally for subsequent queries. The children actually are not indexed as independent events in the proposed implementation.

When a comment is deleted, the system handles threading carefully:

**Deleting a child comment:**
- The child is converted to a `LogEvent` with "comment deleted" payload
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it not be clearer maybe if we kept it as a CommentEvent? And we could remove the content, but add a field to the payload_schema marking it as deleted, so we can render some text in the UI, e.g. "This comment was deleted", with some formatting to clearly differentiate it from regular comment content. And maybe also the time at which it was deleted.

GitHub uses a sort of similar approach: palkerecsenyi/discussiontest#1 (comment). Although this is confusing because it just removes the comment content without showing a message to clarify that it was deleted.

Image


# Convert to LogEvent
event.type = LogEventType
event["payload"] = {"event": "comment_deleted", "content": "deleted a comment"}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this get i18n-ised when being rendered or is it always in English?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in the code we translate it, I forgot it in the RFC 🙃

- Multiple `children` (replies) - but those children **cannot have children** themselves
- A computed `children` field that includes full metadata of all child events

**Threading depth is limited to exactly 1 level** to keep discussions simple and readable. Attempting to reply to a reply results in a validation error.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Attempting to reply to a reply results in a validation error.

you mean in the REST API, right? UI shouldn't display this option in a first place, maybe worth mentioning

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, exactly. This refers to the REST API

Comment on lines 133 to 137
Threading is implemented via a **dedicated REST API endpoint** rather than accepting `parent_id` in the request body. This design:
- Makes the API more explicit and RESTful
- Prevents users from manipulating `parent_id` in request bodies
- Clearly separates top-level comments from replies
- Ensures `parent_id` comes from the trusted URL path, not user input
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this part is not super clear to me, especially how URL path is more trusted than having parent_id in the payload? I understand it will be validated either way, not sure we need dedicated endpoint. Unless I am missing some context.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I experimented with having one a new param in the payload for parent_id in the same route as creating a comment. In that solution, you needed to ensure that the parent_id passed down was validated to disallow multiple levels of nested replies e.g

if incoming_event.parent_id:
   event_parent = _get_event(incoming_event.parent_id)
   if event_parent.parent_id:
     raise()

The specific reply endpoint just accepts the message in the payload.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I experimented with having one a new param in the payload for parent_id in the same route as creating a comment. In that solution, you needed to ensure that the parent_id passed down was validated to disallow multiple levels of nested replies e.g

if incoming_event.parent_id:
   event_parent = _get_event(incoming_event.parent_id)
   if event_parent.parent_id:
     raise()

The specific reply endpoint just accepts the message in the payload.

Sorry, the validation of the parent_id is always needed. And indeed, is the validation code that ensures the parent_id not the fact that is coming from the URL. Having a dedicated endpoint seems cleaner in the REST API and simplified a bit how the logic of indexing the parent-child events.

Comment on lines 305 to 306
- The parent is converted to a `LogEvent`
- All children are recursively converted to `LogEvents`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wouldn't it be less complex if we keep the same CommentEvent but marked as deleted?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was the case in the past. We will evaluate if it makes sense to change this to actually a CommentEvent or display them differently in the UI

**Key insights**:

1. **Separate methods**: `create()` for top-level, `reply()` for threaded - clear separation of concerns
2. **URL-based parent_id**: Parent comes from URL path, not request body (prevents manipulation)
Copy link
Contributor

@kpsherva kpsherva Oct 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not convinced about "prevents manipulation" part... You can do POST to /comment/234/reply and /comment/254, nothing prevents you to do that, unless I am missing some other detail or misunderstanding the thought behind this.
How are you planning to prevent replies to random comments (especially in request which user shouldn't have access to)?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The permission is being checked on the request level i.e full URL is /requests/<request_id>/comments/<comment_id>/reply. There is no POST action on /requests/<request_id>/comments/<comment_id>, what is your concern?


## Unresolved questions

1. **Notification strategy**: Should replies trigger different notifications than top-level comments? Should users be notified when someone replies to their comment specifically?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could it be opt in/opt out, like "follow the thread"?


1. **Notification strategy**: Should replies trigger different notifications than top-level comments? Should users be notified when someone replies to their comment specifically?

2. **Search and filtering**: How should search work across threaded comments? Should searching return top-level comments with matching children highlighted, or individual matching children?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I saw in some solutions both the whole thread and the child comment were highlighted on search, with an effect of narrowing focus from "big picture" to single comment

@zzacharo zzacharo force-pushed the comments-threading-rfc branch 2 times, most recently from 340c6ee to 609db6d Compare October 29, 2025 13:57
@zzacharo zzacharo force-pushed the comments-threading-rfc branch from 609db6d to 5b7188c Compare October 30, 2025 15:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

RFC: support single threaded discussion on request comments

3 participants