As a user I want to comment on documents and reply to others so we can discuss and annotate our findings #50
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Background
Family members need a way to discuss documents — to ask questions, share insights, confirm transcriptions, or note historical context. Comments can be left on a document in general, or attached to a specific PDF annotation (from #40). Replies are shown nested one level deep so threads stay readable.
Depends on #35 (profile page) for meaningful
author_namevalues.Works alongside #40 (PDF annotations) — comments can optionally be linked to an annotation.
Desired behaviour
Top-level comments can be attached to:
Replies — UI vs. storage:
created_atEditing:
PATCHrequestcreated_atupdated_at > created_at), a small „bearbeitet" label with the edit timestamp appears next to the comment's original timestamp — on hover the full absolute date/time is shownDeleting:
ADMINpermission can delete any commentAuthor display:
author_nameis captured at write time (same pattern as conversations in #38)Permission model
READ_ALL,ANNOTATE_ALL, orWRITE_ALLANNOTATE_ALLorWRITE_ALLADMINData model
updated_atis set tonow()on every edit. The frontend comparesupdated_attocreated_atto decide whether to show the „bearbeitet" label — no separate flag needed.Invariant:
parent_idalways points to a top-level comment (parent_id IS NULLon the target row). This is resolved by the backend: when a reply is submitted with anycommentId, the backend walks up to the root and stores it under that root.A comment has
annotation_idset when it belongs to a PDF annotation thread;annotation_id = NULLmeans it is a general document comment. Replies inheritannotation_idfrom their parent (set by the backend).REST endpoints
GET/api/documents/{id}/commentsPOST/api/documents/{id}/commentsPOST/api/documents/{id}/comments/{commentId}/repliesPATCH/api/documents/{id}/comments/{commentId}contentandupdated_at)DELETE/api/documents/{id}/comments/{commentId}ADMIN)GET/api/documents/{id}/annotations/{annId}/commentsPOST/api/documents/{id}/annotations/{annId}/commentsPOST/api/documents/{id}/annotations/{annId}/comments/{commentId}/repliesThe
GETendpoints return comments grouped with their replies, ordered bycreated_at:Frontend
General document comments
Appear in a „Diskussion" card at the bottom of the document detail page (
/documents/{id}).Annotation comments — UI design decisions
Comment count pill:
Each annotation overlay shows a small pill badge below the highlight rect (top-right corner is occupied by the delete button). The pill shows the comment count and is only rendered when
count > 0. Since every annotation is created with a mandatory first comment (no empty annotation threads exist), the pill is always visible on persisted annotations.Comment panel — responsive behaviour:
≥ 640px)< 640px)The floating panel on desktop is positioned to the right of the annotation when space allows, otherwise to the left. It does not resize or reflow the PDF viewer.
Closing: explicit ✕ button only (clicking outside does not close the panel).
Panel header: „Kommentare" — the annotated PDF text is not available as a string, so no quote is shown.
No empty state: Annotations always carry at least one comment. The annotation creation flow (see #40) requires the user to enter a first comment before saving the annotation.
Shared comment thread UI (both contexts)
created_atcreated_atupdatedAt > createdAt(absolute datetime on hover)ADMINPATCHand updates the displayed content and edit timestamp in placeTesting
CommentServiceTest— replying via a reply ID resolves to the correct root parent; author can edit own; non-author edit is rejected (403);ADMINcan delete any comment; non-admin non-author delete is rejected (403);updated_atis updated on edit;created_atis unchanged on edit; deleting parent cascades to replies;author_namecaptured at post time@WebMvcTest— post returns 201; edit returns 200; unauthenticated gets 401; unauthorised gets 403User journey
General comment: User views a document and scrolls to „Diskussion". They post a comment, then notice a typo and click „Bearbeiten". An inline text area appears with their original text. They fix the typo and save. The comment now shows „vor 5 Minuten · bearbeitet vor 1 Minute". The sort order in the thread is unchanged.
Annotation comment: User clicks a yellow highlight on page 2. A floating panel opens overlaying the PDF. The panel header reads „Kommentare". The annotation pill already shows „1" from the first comment written at creation time. Others reply using the Reply button on the last comment in the thread.
Dependencies
author_namepopulated from user profile