feat: comments with mentions, follow and activity timeline #4

Merged
KofTwentyTwo merged 1 commits from feature/comments-follow-timeline into develop 2026-10-13 21:44:35 +00:00
KofTwentyTwo commented 2026-10-13 21:42:31 +00:00 (Migrated from github.com)

Summary

Phase (e), qbit side, of QRun-IO/qqq#1136 (spec §4 rows 2 and 10 to 14, §7.1, §7.2, §8.3): comments with mentions, follow/watch and the activity timeline.

Comments (CommentsService):

  • Threads are one level deep; a reply to a reply attaches to the root.
  • Bodies are markdown, up to 20,000 characters.
  • @[Name](user:<id>) mentions are recorded with whether the person could read the record. Only readers are notified and made followers. When access is unknown, nobody is notified (spec §8.3).
  • Authors edit their own comments, and every edit keeps a revision. Delete is soft: authors delete their own, and collaboration.admin can moderate.
  • Threads can be resolved and reopened.
  • Lists page by cursor.
  • Mention candidates are ranked followers-first and carry canRead.

Follow (FollowService):

  • Defaults per §7.2.
  • Follow and Unfollow are standard streamed-ETL table actions for the tables listed in followActionTables.
  • Change notifications are batched per record and follower over 5 minutes, using the released RC.5 record change listener and after-commit callbacks, plus the hidden collaborationSendFollowDigests process.
  • The actor is never notified, and recipient access is re-checked at send time.

Timeline (TimelineService) merges core audit (with the user's audit permissions and field visibility) and collaboration_activity, newest first, with a cursor. Attachments now write FILE_ADDED and FILE_REMOVED activity.

People: collaboration_user is filled lazily (throttled touch) and searchable.

Tables:

  • collaboration_comment, _comment_revision, _mention, _follow, _activity;
  • _follow_digest, a visible queue table holding pending change batches.

All are restricted to rows whose parent table the user can READ, through the shared ParentTableRestriction. Direct API writes are refused; the services do the writes.

Stand-ins until core and alerts are released:

  • CollaborationNotifier: no-op by default, with a recording implementation for tests. It becomes a QAlerts.notify adapter when #1125 ships.
  • OtherUserAccess, plus an optional UserSessionSupplier. These become core's RecordAccessCheckerInterface and UserSessionProviderInterface (#1138, now merged) in the next RC.

Not in this PR: the endpoints, which wait for #1128.

Test plan

  • ./mvnw -o verify: 54 tests, 96.8% instruction and 100% class coverage, checkstyle clean.
  • CircleCI test_only.

🤖 Generated with Claude Code

## Summary Phase (e), qbit side, of QRun-IO/qqq#1136 (spec §4 rows 2 and 10 to 14, §7.1, §7.2, §8.3): comments with mentions, follow/watch and the activity timeline. **Comments** (`CommentsService`): - Threads are one level deep; a reply to a reply attaches to the root. - Bodies are markdown, up to 20,000 characters. - `@[Name](user:<id>)` mentions are recorded with whether the person could read the record. Only readers are notified and made followers. When access is unknown, nobody is notified (spec §8.3). - Authors edit their own comments, and every edit keeps a revision. Delete is soft: authors delete their own, and `collaboration.admin` can moderate. - Threads can be resolved and reopened. - Lists page by cursor. - Mention candidates are ranked followers-first and carry `canRead`. **Follow** (`FollowService`): - Defaults per §7.2. - **Follow** and **Unfollow** are standard streamed-ETL table actions for the tables listed in `followActionTables`. - Change notifications are batched per record and follower over 5 minutes, using the released RC.5 record change listener and after-commit callbacks, plus the hidden `collaborationSendFollowDigests` process. - The actor is never notified, and recipient access is re-checked at send time. **Timeline** (`TimelineService`) merges core audit (with the user's audit permissions and field visibility) and `collaboration_activity`, newest first, with a cursor. Attachments now write FILE_ADDED and FILE_REMOVED activity. **People:** `collaboration_user` is filled lazily (throttled `touch`) and searchable. **Tables:** - `collaboration_comment`, `_comment_revision`, `_mention`, `_follow`, `_activity`; - `_follow_digest`, a visible queue table holding pending change batches. All are restricted to rows whose parent table the user can READ, through the shared `ParentTableRestriction`. Direct API writes are refused; the services do the writes. **Stand-ins until core and alerts are released:** - `CollaborationNotifier`: no-op by default, with a recording implementation for tests. It becomes a `QAlerts.notify` adapter when #1125 ships. - `OtherUserAccess`, plus an optional `UserSessionSupplier`. These become core's `RecordAccessCheckerInterface` and `UserSessionProviderInterface` (#1138, now merged) in the next RC. **Not in this PR:** the endpoints, which wait for #1128. ## Test plan - [x] `./mvnw -o verify`: 54 tests, 96.8% instruction and 100% class coverage, checkstyle clean. - [ ] CircleCI `test_only`. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Sign in to join this conversation.