Skip to content

fix(notifications): mark only the notifications the filter shows as read - #678

Open
younes-io wants to merge 3 commits into
dev-null-sh:productionfrom
younes-io:fix/notifications-read-scope
Open

younes-io wants to merge 3 commits into
dev-null-sh:productionfrom
younes-io:fix/notifications-read-scope

Conversation

@younes-io

@younes-io younes-io commented Oct 19, 2026 •

Copy link
Copy Markdown
Contributor

Why

Opening the inbox marks every notification as read, whatever filter is on. If you filter to Replies, your unseen stars and follows are marked read too. You never see them as new, and the badge drops them. Now the inbox marks as read only the types the filter shows.

What changed

  • UpdateNotificationsReadAt takes the active filter and marks only the matching types as read, on the web and in the API.
  • The type-to-category mapping moves into NotificationBuilder::ofType(), so grouping, the unread count and marking read use one rule.
  • rememberedType() reads a filter cookie queued in the same response, so the badge counts under the filter the inbox just applied.

Scope

  • Covers the web inbox and GET /api/notifications.
  • Notifications hidden by the filter stay unread until you open the inbox with a filter that shows them.

Blast Radius

The change touches only the notification read path and the badge count. With no filter (all), the behavior is the same as before.

Verification

  • New tests show that opening the inbox under a filter leaves the hidden types unread, on the web and in the API.
  • The full suite passes except TomTest, which fails the same way on production. Pint, Rector and PHPStan pass.

Summary by CodeRabbit

  • New Features
    • Notification lists and unread counts now respect selected categories, including combined filters.
    • The inbox remembers the selected notification filter.
  • Bug Fixes
    • Viewing a filtered inbox marks only matching notifications as read; notifications in other categories remain unread until their category is viewed.
    • An unfiltered view still marks all matching notifications as read.

Signed-off-by: Younes <git@younes.io>
…ns-read-scope

Signed-off-by: Younes <git@younes.io>

# Conflicts:
#	app/Http/Controllers/NotificationController.php
@coderabbitai

coderabbitai Bot commented Oct 26, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

No actionable comments were generated in the recent review.

Recent review info
Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 03defeb3-722d-4bbb-90de-af2b250d9f13
Commits

Reviewing files that changed from the base of the PR and between dcf4a6a and 026eb41.

Files selected for processing: 9
  • app/Actions/UpdateNotificationsReadAt.php
  • app/Http/Controllers/Api/NotificationController.php
  • app/Http/Controllers/NotificationController.php
  • app/Http/Requests/ListNotificationsRequest.php
  • app/Queries/NotificationBuilder.php
  • app/Queries/NotificationGroupsQuery.php
  • tests/Feature/Controllers/Api/NotificationControllerTest.php
  • tests/Feature/NotificationInboxTest.php
  • tests/Unit/Actions/UpdateNotificationsReadAtTest.php

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 7 remain after this review.

Walkthrough

Notification read timestamps now apply only to unread notifications that match the active type filter. Notification grouping and unread counts use the same type filter. The request checks a queued filter cookie before the request cookie.

Changes: Notification type filtering

Layer / File(s) Summary
Apply filters to notification queries
app/Http/Requests/ListNotificationsRequest.php, app/Queries/NotificationBuilder.php, app/Queries/NotificationGroupsQuery.php
The request checks the queued filter cookie before the request cookie. NotificationBuilder::ofType maps categories to notification types. Grouped results and unread counts now apply the selected filter.
Mark filtered notifications as read
app/Actions/UpdateNotificationsReadAt.php, app/Http/Controllers/Api/NotificationController.php, app/Http/Controllers/NotificationController.php, tests/Feature/Controllers/Api/NotificationControllerTest.php, tests/Feature/NotificationInboxTest.php, tests/Unit/Actions/UpdateNotificationsReadAtTest.php
The controllers pass the resolved type to the read-timestamp action. The action updates only unread relevant notifications of that type. Tests cover filtered and unfiltered views, including notifications beyond the first page.

Priority: Normal

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

Change: Bug fix

Possibly related PRs

  • dev-null-sh/dev-null.sh#997: Adds EventCancelled notifications to the relevant notification flow that this PR filters when updating read timestamps.

Suggested reviewers: xheaven, simonhamp

Merge Risk: Minimal · up to 026eb

Filtered inbox views leave hidden notifications unread, and no merge-blocking issue remains after normal checks.

Security architecture risk: Minimal · up to 026eb

The change narrows read acknowledgments to the selected notification categories while preserving recipient ownership and existing visibility controls. No material security risk introduced or worsened by this change was identified.

Retained concerns
No architecture-level concerns identified.

Security review details

Security Blast Radius

  • inferred — Through the inspected entrypoints, caller-controlled filters select categories within the current user's relevant notifications; they do not select another recipient or increase update authority. The affected persistent state is the read timestamp of matching unread notifications.

Security Findings and Attack Paths

  • inferred — No introduced cross-recipient read mutation or visibility bypass was identified in the inspected paths. Compared with the base, the new predicate narrows acknowledgment while retaining the ownership and visibility predicates used before this PR.

Trust Boundaries and Controls

  • observed — The request type is constrained to named categories, all, or none. Remembered cookie values pass the same allowlist and fall back to all when invalid. Category values are mapped into a whereIn predicate rather than interpreted as query structure.

Resilience and Maintainability Implications

  • observed — Acknowledgment still precedes pagination and rendering, without a surrounding transaction in these methods. A later request failure can therefore leave notifications acknowledged without successful delivery. This ordering predates the PR; the change limits the affected categories rather than introducing or broadening that failure window.
Pre-merge checks: Passed 4 · Failed 1

Failed Failed checks: 1 warning

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 8 functions across 9 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
Passed Passed checks: 4 passed
Check name Status Explanation
Description Check Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check Passed The title "fix(notifications): mark only the notifications the filter shows as read" matches the main change. The PR changes the web inbox and GET /api/notifications so opening them marks only the not…
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.
Full details: Title check

Explanation

The title "fix(notifications): mark only the notifications the filter shows as read" matches the main change. The PR changes the web inbox and GET /api/notifications so opening them marks only the notification types shown by the active filter as read. Hidden types stay unread. The title is specific, uses the conventional commit prefix, and names the behavior change. It is not vague, and it does not describe anything absent from the changeset.

Finishing Touches
🧪 Generate unit tests (beta)
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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

@younes-io

Copy link
Copy Markdown
Contributor Author

@brendt could you review this one too? Opening a filtered inbox now marks only the notifications that filter shows as read, and the unread count follows the same filter. It touches NotificationGroupsQuery alongside #680, so reviewing them together may be easiest.

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