feat: replies to comments

A comment can answer another one (replyTo), one level deep: answering a
reply joins the same thread, and it must be on the same ticket. Whoever
wrote the comment gets a new REPLIED notification, and the activity says
"respondió a un comentario".

A comment deleted while it has replies stays, without its text
(deleted: true), so the thread still reads; it goes with its last reply
and does not count in commentCount.

The ticket page shows threads with their replies indented and a
"Responder" box; REST, GraphQL and the MCP (add_comment, get_issue) take
and show replyTo. Existing comments are unchanged. Docs, Word and PDF
updated.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-09 11:14:37 +02:00
parent c2928d2385
commit ea4ef82239
44 changed files with 517 additions and 60 deletions

View File

@@ -4406,7 +4406,7 @@
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/CommentBodyDto"
"$ref": "#/components/schemas/AddCommentDto"
}
}
}
@@ -4491,7 +4491,7 @@
"pireon": []
}
],
"summary": "Comment on the ticket",
"summary": "Comment on the ticket, or answer a comment (replyTo)",
"tags": [
"Issues"
]
@@ -11423,7 +11423,18 @@
"$ref": "#/components/schemas/UserRefDto"
},
"body": {
"type": "string"
"type": "string",
"description": "Empty on a deleted comment kept for its replies"
},
"replyTo": {
"type": "string",
"nullable": true,
"format": "uuid",
"description": "The top-level comment it answers; null for a top-level one"
},
"deleted": {
"type": "boolean",
"description": "Deleted, but kept (without its text) while it has replies"
},
"createdAt": {
"type": "string",
@@ -11443,6 +11454,8 @@
"issueId",
"author",
"body",
"replyTo",
"deleted",
"createdAt",
"editedAt",
"version"
@@ -11466,13 +11479,18 @@
"total"
]
},
"CommentBodyDto": {
"AddCommentDto": {
"type": "object",
"properties": {
"body": {
"type": "string",
"example": "Reproducido en Safari 17.",
"maxLength": 20000
},
"replyTo": {
"type": "string",
"format": "uuid",
"description": "Comment it answers (one level: answering a reply joins its thread)"
}
},
"required": [
@@ -11497,6 +11515,19 @@
"file"
]
},
"CommentBodyDto": {
"type": "object",
"properties": {
"body": {
"type": "string",
"example": "Reproducido en Safari 17.",
"maxLength": 20000
}
},
"required": [
"body"
]
},
"ReleaseStatus": {
"type": "string",
"enum": [
@@ -11929,6 +11960,7 @@
"QA_FAILED",
"COMMENTED",
"MENTIONED",
"REPLIED",
"WATCHED",
"ADDED_TO_PROJECT",
"REMINDER"