Overview
Two related changes to comment persistence:
- Comment deletion — essay owners and admins can delete any comment on an essay; comment authors can delete their own. Threaded parent comments with existing replies are tombstoned rather than hard-deleted.
- Deleted-user attribution — when a user account is removed from the system, their comments stay on the essay but display as "Deleted user" instead of the original author.
Comment deletion
Who can delete
| Actor |
Can delete |
| Comment author |
Their own comment only |
| Essay owner |
Any comment on their essay |
| Admin / superuser |
Any comment anywhere |
Tombstone vs hard delete
- Parent comment with replies → tombstone: mark
is_deleted=True, clear content and quote, keep the record so the reply thread remains coherent. Display as "[comment deleted]" in the UI.
- Leaf comment / reply with no children → hard delete.
Model changes
# Add to Comment
is_deleted = models.BooleanField(default=False)
Backend
delete_comment(comment, actor) service: checks permission, decides tombstone vs hard delete, sets is_deleted=True + clears content if tombstoning.
DELETE /interactions/comment/<id>/delete/ endpoint — returns {"deleted": true, "tombstoned": bool}.
UI
- Trash icon (or three-dot menu item "Delete") shown only to users with delete permission
- Confirm dialog before sending the request
- On success: reactively replace comment node with tombstone placeholder or remove it entirely — no page reload
Deleted-user attribution
Model change
Comment.author currently uses on_delete=CASCADE — deleting a user cascades and removes all their comments.
Change to SET_NULL:
author = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.SET_NULL,
null=True,
blank=True,
related_name="comments",
)
Template
{% if comment.author %}
{{ comment.author.username }}
{% else %}
<span class="text-neutral-500">Deleted user</span>
{% endif %}
Apply the same null-check to avatar display (fall back to a generic placeholder icon) and to the profile link (no link if author is None).
Acceptance criteria
Overview
Two related changes to comment persistence:
Comment deletion
Who can delete
Tombstone vs hard delete
is_deleted=True, clearcontentandquote, keep the record so the reply thread remains coherent. Display as "[comment deleted]" in the UI.Model changes
Backend
delete_comment(comment, actor)service: checks permission, decides tombstone vs hard delete, setsis_deleted=True+ clears content if tombstoning.DELETE /interactions/comment/<id>/delete/endpoint — returns{"deleted": true, "tombstoned": bool}.UI
Deleted-user attribution
Model change
Comment.authorcurrently useson_delete=CASCADE— deleting a user cascades and removes all their comments.Change to
SET_NULL:Template
{% if comment.author %} {{ comment.author.username }} {% else %} <span class="text-neutral-500">Deleted user</span> {% endif %}Apply the same null-check to avatar display (fall back to a generic placeholder icon) and to the profile link (no link if author is None).
Acceptance criteria
Comment.authorFK changed toSET_NULL— deleting a user account does not remove their comments