Skip to content

✨(backend) add mention read receipts - #769

Open
nicolasaunai wants to merge 1 commit into
suitenumerique:mainfrom
nicolasaunai:feat/mention-read-receipts
Open

✨(backend) add mention read receipts#769
nicolasaunai wants to merge 1 commit into
suitenumerique:mainfrom
nicolasaunai:feat/mention-read-receipts

Conversation

@nicolasaunai

@nicolasaunai nicolasaunai commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Purpose

Add read receipts for @mentions in internal comments (ThreadEvent type im). Currently the author of a comment has no way to know if a mentioned colleague has read the mention — even though the UserEvent.read_at timestamp is already recorded when the reader scrolls the comment into view.

Proposal

  • Backend: new MentionReadByUserSerializer and mention_read_by field on ThreadEventSerializer. Returns the list of mentioned users with read_at IS NOT NULL, or null if the requesting user is not the event author.

  • OpenAPI: updated schema with MentionReadByUser component + field reference.

  • Frontend: ThreadEvent component shows ✓ Lu par X/Y indicator with a Tooltip listing names. Only rendered when the current user is the author and at least one mention has been read.

  • i18n: added read_by_count key in en-US and fr-FR.

  • Backend mention_read_by field

  • OpenAPI schema + generated TypeScript types

  • Frontend UI indicator + tooltip

  • Translations (en, fr)

  • Spec file for reference

Summary by CodeRabbit

  • New Features

    • Added read receipts for mentions in internal comments.
    • Comment authors can see how many mentioned people have read the mention.
    • A tooltip lists the people who have read it, with support for English and French.
  • Documentation

    • Added documentation describing mention read-receipt behavior and access-related handling.

@coderabbitai

coderabbitai Bot commented Jul 29, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Adds an author-only mention_read_by field to thread events, documents its API contract, and renders a localized read-count indicator with a reader tooltip for internal mentions.

Changes

Mention read receipts

Layer / File(s) Summary
Thread event read metadata
spec_read_receipts.md, src/backend/core/api/serializers.py, src/backend/core/api/openapi.json
Defines and exposes mention_read_by as nullable author-scoped reader data containing user identifiers, names, and read timestamps.
Read status indicator
src/frontend/src/features/layouts/components/thread-view/components/thread-event/*, src/frontend/public/locales/common/*.json
Displays a localized read count and tooltip for authored IM mentions, adds styling and translations, and updates event fixtures for the new response field.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant ThreadEventSerializer
  participant UserEvent
  Client->>ThreadEventSerializer: Request thread events
  ThreadEventSerializer->>UserEvent: Query read mention rows
  UserEvent-->>ThreadEventSerializer: Return reader names and read_at values
  ThreadEventSerializer-->>Client: Return mention_read_by
Loading

Suggested reviewers: jbpenrath

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: adding mention read receipts, with backend as the primary implementation area.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Add mention_read_by field to ThreadEventSerializer exposing which mentioned
users have read the mention. Only visible to the event author.

- New MentionReadByUserSerializer + get_mention_read_by on backend
- Updated OpenAPI schema and regenerated TypeScript client
- Frontend shows "Lu par X/Y" indicator with tooltip on author's bubbles
- French and English translations for the read indicator

Signed-off-by: Nicolas Aunai <nicolas.aunai@lpp.polytechnique.fr>
@nicolasaunai
nicolasaunai force-pushed the feat/mention-read-receipts branch from 225e0bd to c41cd96 Compare July 29, 2026 20:54
@nicolasaunai
nicolasaunai marked this pull request as ready for review July 29, 2026 21:18

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/backend/core/api/serializers.py`:
- Around line 1420-1441: Eliminate the per-event UserEvent query in
get_mention_read_by by prefetching filtered, read mention events for all thread
events in the parent events queryset, storing them under a cache attribute.
Update get_mention_read_by to consume that prefetched cache while preserving the
author-only None behavior and existing serialized fields.

In
`@src/frontend/src/features/layouts/components/thread-view/components/thread-event/index.tsx`:
- Around line 313-328: Add component-test coverage for the read-status rendering
in the thread-event component: verify an author with populated mention_read_by
renders the X/Y count and tooltip containing reader names, while non-authors and
null mention_read_by do not render the status. Extend the relevant
assignment-message and group-system-events fixtures or tests without changing
the component behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 74dc8d3f-6153-46ad-a1fe-b72e36d933d4

📥 Commits

Reviewing files that changed from the base of the PR and between cf0b70e and c41cd96.

⛔ Files ignored due to path filters (3)
  • src/frontend/src/features/api/gen/models/index.ts is excluded by !**/gen/**
  • src/frontend/src/features/api/gen/models/mention_read_by_user.ts is excluded by !**/gen/**
  • src/frontend/src/features/api/gen/models/thread_event.ts is excluded by !**/gen/**
📒 Files selected for processing (9)
  • spec_read_receipts.md
  • src/backend/core/api/openapi.json
  • src/backend/core/api/serializers.py
  • src/frontend/public/locales/common/en-US.json
  • src/frontend/public/locales/common/fr-FR.json
  • src/frontend/src/features/layouts/components/thread-view/components/thread-event/_index.scss
  • src/frontend/src/features/layouts/components/thread-view/components/thread-event/assignment-message.test.ts
  • src/frontend/src/features/layouts/components/thread-view/components/thread-event/group-system-events.test.ts
  • src/frontend/src/features/layouts/components/thread-view/components/thread-event/index.tsx

Comment on lines +1420 to +1441
@extend_schema_field(MentionReadByUserSerializer(many=True, allow_null=True))
def get_mention_read_by(self, obj):
"""Return the list of mentioned users who have read this mention.

Only returned for the event author. Returns ``None`` for other users.
"""
request = self.context.get("request")
if not request or request.user != obj.author:
return None
read_mentions = models.UserEvent.objects.filter(
thread_event=obj,
type=enums.UserEventTypeChoices.MENTION,
read_at__isnull=False,
).select_related("user")
return [
{
"id": str(ue.user.id),
"name": ue.user.full_name or ue.user.email or "",
"read_at": ue.read_at.isoformat(),
}
for ue in read_mentions
]

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🚀 Performance & Scalability | 🟠 Major | 🏗️ Heavy lift

Avoid a per-event database query in get_mention_read_by.

For GET /threads/{id}/events/, this method executes a separate UserEvent query for every authored event. select_related("user") only optimizes the user join inside each query; it does not remove the N+1 pattern. Prefetch the filtered mention rows once on the events queryset (or bulk-load them through serializer context) and read that cache here.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/backend/core/api/serializers.py` around lines 1420 - 1441, Eliminate the
per-event UserEvent query in get_mention_read_by by prefetching filtered, read
mention events for all thread events in the parent events queryset, storing them
under a cache attribute. Update get_mention_read_by to consume that prefetched
cache while preserving the author-only None behavior and existing serialized
fields.

Comment on lines +313 to +328
{isAuthor && event.mention_read_by && event.mention_read_by.length > 0 && (
<div className="thread-event__read-status">
<Tooltip
content={event.mention_read_by.map((u) => u.name).join(', ')}
placement="bottom"
>
<span className="thread-event__read-indicator">
<Icon type={IconType.OUTLINED} size={IconSize.X_SMALL} name="done_all" aria-hidden="true" />
{t('read_by_count', {
count: event.mention_read_by.length,
total: (event.data as ThreadEventIMData).mentions?.length ?? 0,
})}
</span>
</Tooltip>
</div>
)}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add coverage for the populated read-status branch.

The changed fixtures in assignment-message.test.ts and group-system-events.test.ts only set mention_read_by to null. Add component tests covering an author with readers, the non-author/null case, and the rendered X/Y count and tooltip names.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/frontend/src/features/layouts/components/thread-view/components/thread-event/index.tsx`
around lines 313 - 328, Add component-test coverage for the read-status
rendering in the thread-event component: verify an author with populated
mention_read_by renders the X/Y count and tooltip containing reader names, while
non-authors and null mention_read_by do not render the status. Extend the
relevant assignment-message and group-system-events fixtures or tests without
changing the component behavior.

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.

1 participant