Comment Responder – Comments
- Path:
/account/comments - Shell nav section: Comment Responder
- Shell nav label: Comments
- Parent:
README.md
Purpose (business goal)
Section titled “Purpose (business goal)”Monitor, moderate, and act on inbound social comments across connected profiles. Enable operators to:
- identify comments requiring moderation or business action
- distinguish engagement, risk, and conversion opportunities
- review AI actions already taken on each comment
- query, filter, sort, and inspect large volumes of comments efficiently
User roles & permissions
Section titled “User roles & permissions”- Manager, Agent
- Permissions:
comment_responder.view,comment_responder.reply,comment_responder.moderate(TBD)
Reference: Roles & Permissions Model
Layout structure
Section titled “Layout structure”Two-panel list + detail, consistent with the Conversations page pattern:
Zone 1 — Page header (fixed, never scrolls)
Section titled “Zone 1 — Page header (fixed, never scrolls)”- Page title: Comments + total count chip
- Row 1: primary filter controls
- Platform filter (dropdown: All platforms, Facebook, Instagram, LinkedIn, Threads)
- Filters toggle button (shows active filter count badge)
- Row 2: expanded filter panel (shown when Filters is toggled)
- Date range (from / to)
- Moderation state (All, Visible, Hidden, Deleted)
- Response state (All, Unreplied, Replied)
- Attention state (All, Requires attention, No attention)
- Opportunity state (All, Opportunity, Not opportunity)
- Sentiment (All, Very positive, Positive, Neutral, Negative, Very negative)
- Reset button
Zone 2 — Metrics bar (fixed, never scrolls)
Section titled “Zone 2 — Metrics bar (fixed, never scrolls)”Clickable chips that act as quick filters. Each chip shows a count and label. Active chip is visually highlighted.
Chips (in order):
- total —
comments.length - requires attention — amber highlight, only shown when count > 0
- opportunities — only shown when count > 0
- favorites — only shown when count > 0
- hidden — count of
moderation_state === 'hidden' - replied — count of
response_state === 'replied' - deleted — count of
moderation_state === 'deleted'
Sentiment breakdown (display-only, not clickable filters — too granular for chips):
- very positive / positive / neutral / negative / very negative counts shown as a compact inline row
Zone 3 — Two-panel body (fills remaining height)
Section titled “Zone 3 — Two-panel body (fills remaining height)”Left panel — comment list (fixed width ~380px, scrollable)
Section titled “Left panel — comment list (fixed width ~380px, scrollable)”- List header: comment count + sort toggle (newest / oldest, by
created_at) - Search input (debounced, searches: content, author name, profile name)
- Scrollable comment list
- Each row: platform icon, author avatar/initials, author name, relative time, comment content (truncated), status badges (moderation state, sentiment, opportunity, favorite)
- Attention indicator: left border accent (amber) when
attention_state === 'requires_attention' - Selected state: background highlight
- Empty state when no comments match filters
Right panel — comment detail (fills remaining width)
Section titled “Right panel — comment detail (fills remaining width)”- No selection state: prompt to select a comment
- Active selection:
- Detail header:
- Author identity (avatar, name, platform icon, profile name)
- Source post context (post caption, media type)
- Meta row: platform, profile, created at, sentiment badge, moderation state badge
- AI response section (if
ai_responsepresent): shows generated_by, text, timestamp; read-only - Action toolbar: favorite, hide/unhide, mark opportunity/remove, flag, delete, reply (AI), reply (manual)
- Reply composer (shown when reply action is triggered): textarea + send button
- Assignment control: assign to reviewer dropdown
- Detail header:
Data model
Section titled “Data model”Comment
Section titled “Comment”type Comment = { id: string external_id?: string platform: 'facebook' | 'instagram' | 'linkedin' | 'threads' | 'unknown' profile: { id: string name: string handle?: string avatar_url?: string } author: { id?: string name?: string handle?: string avatar_url?: string } | null source_post: { id: string caption?: string media_type?: 'image' | 'video' | 'carousel' | 'text' | 'unknown' thumbnail_url?: string published_at?: string } | null content: string created_at: string updated_at: string moderation_state: 'visible' | 'hidden' | 'deleted' response_state: 'unreplied' | 'replied' attention_state: 'requires_attention' | 'no_attention' opportunity_state: 'opportunity' | 'not_opportunity' sentiment: 'very_positive' | 'positive' | 'neutral' | 'negative' | 'very_negative' | 'unknown' is_favorite: boolean assigned_to?: string | null last_action: { type: 'replied_by_ai' | 'replied_by_agent' | 'hidden' | 'deleted' | 'flagged' | 'favorited' | 'none' actor?: 'ai' | 'agent' | 'system' timestamp?: string } ai_response?: { generated_by: 'Chatti™' | 'agent' | 'system' text?: string timestamp?: string } | null}SocialProfile
Section titled “SocialProfile”type SocialProfile = { id: string platform: 'facebook' | 'instagram' | 'linkedin' | 'threads' | 'unknown' name: string handle?: string avatar_url?: string status?: 'connected' | 'disconnected'}SourcePost
Section titled “SourcePost”type SourcePost = { id: string profile_id: string platform: 'facebook' | 'instagram' | 'linkedin' | 'threads' | 'unknown' caption?: string media_type?: 'image' | 'video' | 'carousel' | 'text' | 'unknown' thumbnail_url?: string published_at?: string}State dimensions
Section titled “State dimensions”Each comment carries independent state across six dimensions. These must never be collapsed into a single status field.
| Dimension | Values |
|---|---|
moderation_state | visible | hidden | deleted |
response_state | unreplied | replied |
attention_state | requires_attention | no_attention |
opportunity_state | opportunity | not_opportunity |
sentiment | very_positive | positive | neutral | negative | very_negative | unknown |
is_favorite | boolean |
Derived metrics
Section titled “Derived metrics”All metrics computed dynamically from the current (unfiltered) comment dataset.
total_comments = comments.lengthrequires_attention = comments.filter(c => c.attention_state === 'requires_attention').lengthhidden = comments.filter(c => c.moderation_state === 'hidden').lengthreplied = comments.filter(c => c.response_state === 'replied').lengthdeleted = comments.filter(c => c.moderation_state === 'deleted').lengthvery_positive = comments.filter(c => c.sentiment === 'very_positive').lengthpositive = comments.filter(c => c.sentiment === 'positive').lengthneutral = comments.filter(c => c.sentiment === 'neutral').lengthnegative = comments.filter(c => c.sentiment === 'negative').lengthvery_negative = comments.filter(c => c.sentiment === 'very_negative').lengthopportunities = comments.filter(c => c.opportunity_state === 'opportunity').lengthfavorites = comments.filter(c => c.is_favorite).lengthQuery system
Section titled “Query system”Search
Section titled “Search”- Debounced (200ms), case-insensitive, partial match
- Searchable fields:
content,author.name,profile.name,source_post.caption
Filtering
Section titled “Filtering”Primary (always visible):
- Platform:
facebook|instagram|linkedin|threads| all
Expandable panel:
- Date range:
created_atfrom / to moderation_stateresponse_stateattention_stateopportunity_statesentiment
Metrics bar quick filters (single-select, toggleable):
- requires attention
- opportunities
- favorites
- hidden
- replied
- deleted
Sorting
Section titled “Sorting”created_atnewest first (default) / oldest first- Toggle button in list header
Selection model
Section titled “Selection model”selectedCommentId: string | null- Only one comment selected at a time
- Selecting a comment loads full detail in the right panel
- When filters change and the selected comment is no longer in the filtered set, auto-select the first result (or clear if empty)
Actions (MVP scope)
Section titled “Actions (MVP scope)”Moderation
Section titled “Moderation”- Favorite / unfavorite — toggles
is_favorite - Hide — sets
moderation_statetohidden; button label changes to “Unhide” when already hidden - Delete — sets
moderation_statetodeleted; requires confirmation - Flag for review — sets
last_action.typetoflagged
Engagement
Section titled “Engagement”- Reply with AI — triggers AI reply generation (demo: shows placeholder response); sets
response_statetoreplied,last_action.typetoreplied_by_ai - Reply manually — opens reply composer; on send sets
response_statetoreplied,last_action.typetoreplied_by_agent - Mark as opportunity / remove flag — toggles
opportunity_state - Assign to reviewer — sets
assigned_to(dropdown of available reviewers)
System states
Section titled “System states”| State | Condition |
|---|---|
| Empty dataset | comments.length === 0 |
| No selection | selectedCommentId == null |
| Active selection | selectedCommentId != null |
| No results from query | comments.length > 0 && filteredComments.length === 0 |
| Loading | data fetch in progress |
| Error | fetch failed / permission denied |
Business logic
Section titled “Business logic”Opportunity detection signals
Section titled “Opportunity detection signals”- Purchase intent, booking interest, pricing intent, request for contact, strong positive response to offer
Attention detection signals
Section titled “Attention detection signals”- Negative sentiment, trust concerns, escalation risk, policy/brand risk, unanswered direct question
Moderation logic
Section titled “Moderation logic”- Hide or delete when: abusive, misleading, brand-damaging, spam, or policy-violating
Demo dataset
Section titled “Demo dataset”~20 comments across Facebook, Instagram, LinkedIn, and Threads. Multiple profiles and source posts. Distribution covers all sentiment values, moderation states, attention states, and opportunity states. Includes both AI-replied and unreplied comments, and a mix of favorites.
See implementation: src/app/account/comments/_lib/demo-comments.ts
Architecture constraints
Section titled “Architecture constraints”- Business logic isolated from UI layer
- State dimensions must not be collapsed into a single status field
- Source platform and source post context must remain attached to each comment
- System must remain extensible for additional platforms and classifiers
- UI consumes the system through clean interfaces; no business logic embedded in view components
- Demo data module follows the same pattern as
src/app/account/conversations/_lib/demo-conversations.ts
API dependencies (future)
Section titled “API dependencies (future)”GET /comment-responder/commentsGET /comment-responder/comments/{id}POST /comment-responder/comments/{id}/hidePOST /comment-responder/comments/{id}/deletePOST /comment-responder/comments/{id}/favoritePOST /comment-responder/comments/{id}/flagPOST /comment-responder/comments/{id}/opportunityPOST /comment-responder/comments/{id}/assignPOST /comment-responder/comments/{id}/generate-replyPOST /comment-responder/comments/{id}/send-reply
Performance constraints
Section titled “Performance constraints”- Support high-volume comment streams
- Minimize unnecessary re-rendering (memoized filtering and metrics)
- Support lazy loading / pagination / windowing (future)
- Remain responsive under large datasets
Edge cases & risks
Section titled “Edge cases & risks”- Comment deleted on platform mid-session (show stale indicator)
- Author data missing (show “Unknown” fallback)
ai_response.textmay be null even whengenerated_byis set (show “Response pending” fallback)- All comments filtered out (show empty-query state, not empty-dataset state)
- Attention chip hidden when count is 0 (avoid visual noise)
- Moderation action on already-deleted comment (disable actions gracefully)
Security & compliance considerations
Section titled “Security & compliance considerations”- Pre-send compliance checks before reply actions
- Audit trail: generate, approve, send
- No PII in analytics events
Reference: Security & Compliance
Analytics events
Section titled “Analytics events”comment_responder.comment.viewedcomment_responder.comment.hiddencomment_responder.comment.deletedcomment_responder.comment.favoritedcomment_responder.comment.flaggedcomment_responder.comment.opportunity_markedcomment_responder.reply.generatedcomment_responder.reply.sent
Reference: Analytics Events (MVP)
Future extensions
Section titled “Future extensions”- Confidence scores for opportunity classification
- Moderation rule builder
- Suggested response quality scoring
- Duplicate / spam cluster detection
- Escalation queues
- Reviewer workload balancing
- Per-profile moderation policies
- Post-level performance overlays
- Conversion attribution from comment to lead
- Inspect source post (link out to platform or post detail view)