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.
_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.
## 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)
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
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):@[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).collaboration.admincan moderate.canRead.Follow (
FollowService):followActionTables.collaborationSendFollowDigestsprocess.Timeline (
TimelineService) merges core audit (with the user's audit permissions and field visibility) andcollaboration_activity, newest first, with a cursor. Attachments now write FILE_ADDED and FILE_REMOVED activity.People:
collaboration_useris filled lazily (throttledtouch) 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 aQAlerts.notifyadapter when #1125 ships.OtherUserAccess, plus an optionalUserSessionSupplier. These become core'sRecordAccessCheckerInterfaceandUserSessionProviderInterface(#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.test_only.🤖 Generated with Claude Code