-
Notifications
You must be signed in to change notification settings - Fork 9
Feature: Threaded Comments (1-level) + @mentions with Realtime Notifications #24
Description
Summary
Add first-level threaded comments on posts and support @username mentions. When a user is mentioned or receives a reply, send a realtime in-app notification (and optional web-push later). Keep the scope tight: 1 nesting level (comment → reply), no arbitrary deep threads.
Motivation
Replies and mentions are core social behaviors. This improves conversation quality, boosts engagement, and creates clear notification events without overhauling the feed.
Scope
-
Comment on a post.
-
Reply to a comment (single level).
-
Parse and store
@mentionsin comments/replies. -
Realtime in-app notifications for:
- replies to my post
- replies to my comment
- direct
@mentionin a comment/reply
-
Pagination + optimistic UI.
-
RLS-safe, index-backed queries.
Out of scope (follow-ups)
- Deeply nested threads (>1 level).
- Web-push and email digests.
- Moderation/reporting.
Data Model (Supabase / Postgres)
New table comments:
id uuid primary key default gen_random_uuid(),
post_id uuid not null references posts(id) on delete cascade,
author_id uuid not null references profiles(id) on delete cascade,
parent_comment_id uuid null references comments(id) on delete cascade,
content text not null check (length(trim(content)) > 0),
mentions text[] not null default '{}', -- parsed @handles → normalized usernames
created_at timestamptz not null default now(),
updated_at timestamptz not null default now()Indexes:
create index on comments (post_id, created_at desc);
create index on comments (parent_comment_id, created_at asc);
create index on comments using gin (mentions); -- for mention lookupsNotifications table notifications:
id uuid primary key default gen_random_uuid(),
user_id uuid not null references profiles(id) on delete cascade, -- recipient
type text not null check (type in ('reply_to_post','reply_to_comment','mention')),
actor_id uuid not null references profiles(id) on delete cascade, -- who triggered
post_id uuid not null references posts(id) on delete cascade,
comment_id uuid not null references comments(id) on delete cascade,
read_at timestamptz null,
created_at timestamptz not null default now()RLS (sketch):
-
comments:selectforauthenticated(public comments)insert:author_id = auth.uid()update/delete:author_id = auth.uid()
-
notifications:select:user_id = auth.uid()update(mark read):user_id = auth.uid()
API/Queries (client utils)
getComments(postId)→ top-level comments (no parent), paginated.getReplies(parentCommentId)→ replies, oldest-first.addComment({ postId, content })addReply({ postId, parentCommentId, content })listNotifications({ unreadOnly?, limit, cursor })markNotificationRead(id)/markAllRead()
Realtime:
- Subscribe to
commentsbypost_id. - Subscribe to
notificationsbyuser_id.
UI/UX
-
Under each post:
-
Comment composer (placeholder: “Write a comment…”).
-
List top-level comments (newest first), each with:
- author, timestamp, content (with linkified mentions)
- “Reply” action → inline reply composer
- “View replies (n)” toggle → expands replies (oldest first)
-
-
Mentions autocomplete: type
@to fetch usernames (debounced query). -
Notifications bell in header:
-
badge count (unread)
-
dropdown list with items:
- “X replied to your post”
- “X replied to your comment”
- “X mentioned you”
-
click → route to
post/[id]#comment-{commentId}
-
-
Optimistic posting; fallback toast on error.
Mention Parsing (client)
- On submit: extract
@(\w{2,30})(match your username rules). - Resolve to canonical usernames (and store into
mentions[]). - If resolution fails, drop unknown mention(s) silently.
Performance & Limits
- Page comments in chunks (e.g., 20).
- Cap comment length (e.g., 1,000 chars).
- Prevent N+1: fetch authors via single
inquery. - Add basic rate-limit (client cooldown + server constraint idea: one comment per 2s per author via trigger or defer to future).
Tasks
- DB: create
comments, indexes, RLS. - DB: create
notifications, indexes, RLS. - Client: comment + reply composers with optimistic insert.
- Client: comments list (top-level) with pagination; replies expand/collapse.
- Client: mentions autocomplete + parsing + storage of
mentions[]. - Client: notifications bell, list, mark-read.
- Realtime: subscribe
commentsbypost_id;notificationsby currentuser_id. - Linkification of
@username→/profile/[id or handle]. - Tests: unit (parsing, reducers), integration (posting flow), e2e happy path.
- Docs: README section + migration notes.
Acceptance Criteria
- Can post a top-level comment and a single-level reply.
@mentionin a comment/reply creates a notification for mentioned users.- Replying to my post/comment notifies me once per action.
- Notifications are visible in the bell menu and can be marked read.
- Realtime: new comments/replies and notifications appear without reload.
- All operations succeed with RLS enabled; unauthenticated users cannot post.
Rollout
- Ship behind
feature.comments_v1config flag (default: ON). - Safe migration with rollback SQL.
- Seed data script for local dev (a few posts/comments to demo UI).
Metadata
Metadata
Assignees
Labels
Projects
Status