Feature Owner: scorevi (Sean Patrick Caintic)
Module: Review Workflow
Priority: P0
Sprint #12: Fully Implemented & Deployed
Date: 2026-06-29
EXECUTIVE SUMMARY
What is this feature?
Canvas-integrated threaded commenting system for content review. Reviewers and authenticated users attach comments to specific canvas nodes. Threaded replies, resolution tracking, bulk operations, content sanitization, and audit logging via deletion trigger. Powered by CommentingContext (components/context/CommentingContext.tsx, 47 lines) exposing useCommenting() and useCommentingOptional() hooks.
Why does it matter?
Text feedback on specific content elements is the core of the review workflow. A reviewer must be able to click a quiz node and say "Question 3 has the wrong answer." Without node-level commenting, feedback is disconnected from the content.
What's the MVP scope?
Fully deployed. Threaded comments on canvas nodes. Resolution tracking. Bulk resolve/delete. CSV/JSON export. Per-node comment analytics. Content sanitization. Audit trail via comment_deletion_log. Fire-and-forget notifications. Approximately 16+ API routes.
1. USER PAIN POINT & SOLUTION
Current State (Without Feature)
Reviewers have no way to leave feedback on specific content elements. Feedback is given via email, Slack, or spreadsheets — disconnected from the actual quest nodes.
Pain Point
Emotional: "I reviewed this quest but my feedback is scattered across emails. Did they fix question 3?"
Functional: No in-platform feedback mechanism.
Business Impact: Review cycles are slow and disorganized; feedback is lost or ignored.
Future State (With Feature)
Reviewer clicks a node → opens comment panel → writes feedback → creator is notified → creator resolves comment → reviewer approves. All feedback tracked per node.
Marketing Hook
"Click a node. Leave a comment. Resolve it. Every piece of feedback lives where it matters."
2. 4D FRAMEWORK MAPPING
Diagnose
Comment analytics (per-node heatmap) help diagnose content trouble spots.
Design
Node-level comments guide the content revision process.
Develop
Creators address comments during the Design/Develop loop.
Deliver
Comment export (CSV/JSON) provides an auditable feedback trail for compliance.
3. USER FLOWS
Entry Point
Reviewer opens a claimed quest in read-only canvas mode. CommentPanel.tsx available as floating panel.
Success Criteria
Comments created, replied to, resolved, and optionally exported.
Main Flow (Happy Path)
Reviewer opens quest in canvas →
CommentPanel.tsx(479 lines) appearsClicks a node → CommentPanel filters to that node's comments
CommentThread.tsx(296 lines) shows threaded discussion withnode_idmappingWrites comment via
CommentForm.tsx(209 lines) →POST /api/reviewer/comments/createContent sanitized by
sanitizeCommentContent()— strips HTML/script tagsNode IDs mapped to human names via
lib/utils/node-display-name.ts(122 lines)
Creator notified: fire-and-forget notification via
notifyCreatorOfNewCommentCreator replies →
notifyParentAuthorOfReplyfires if parent existsAfter revision, comment marked
is_resolved = TRUEviaPATCH /api/reviewer/comments/[commentId]Export available:
POST /api/reviewer/comments/export(CSV or JSON)
Edge Cases
No data: No comments on node → "Be the first to leave feedback" prompt.
API error: Content sanitization rejects HTML tags → stripped automatically.
Permission denied: Non-author trying to delete → "Only the comment author can delete this."
Rate limited: Guest exceeding 20 comments/hour limit → 429 response.
Decision Points
Unresolved comments block quest approval (enforced in review workflow).
4. INFORMATION ARCHITECTURE
Primary Information (Always visible)
CommentPanel: Comment threads organized by node, unresolved count badge.
CommentThread: Node name (e.g., "TEXT 4"), author avatar/name, content, timestamp.
Secondary Information
Resolution status indicator.
"Go to Node" button (spotlights node on canvas).
Analytics tab via
CommentAnalyticsView.tsx(230 lines) — resolution summary + per-node breakdown.
Actions
Primary CTA: "Add Comment", "Resolve".
Secondary Actions: "Reply", "Delete", "Export Feedback", "Bulk Resolve/Delete".
5. WIREFRAMES
Excluded — UI is fully developed (10+ components, 16+ API routes).
6. WIREFLOWS
Excluded.
7. PROTOTYPE
Excluded — production deployed.
8. BACKEND SCHEMA
Database Tables
-- Core comments tableCREATE TABLE quest_comments ( id UUID PK, quest_id FK→quests ON DELETE CASCADE, node_id TEXT NOT NULL, app_user_id FK→app_users ON DELETE SET NULL, -- NULL for guests guest_invite_id FK→quest_invites ON DELETE SET NULL, -- NULL for authenticated content TEXT NOT NULL, is_resolved BOOLEAN DEFAULT FALSE, parent_comment_id FK→quest_comments ON DELETE SET NULL, -- Threading created_at TIMESTAMPTZ, updated_at TIMESTAMPTZ);-- Constraint: chk_author_exists: app_user_id IS NOT NULL OR guest_invite_id IS NOT NULL -- Comment deletion audit log (trigger-based)CREATE TABLE comment_deletion_log ( id UUID PK, comment_id UUID NOT NULL, quest_id UUID NOT NULL, node_id TEXT NOT NULL, content_hash TEXT NOT NULL, -- SHA-256 deleted_by_user FK→app_users, deleted_by_role TEXT, deleted_by_guest UUID, deletion_reason TEXT, deleted_at TIMESTAMPTZ);-- Trigger: log_comment_deletion() BEFORE DELETE on quest_comments (SECURITY DEFINER)-- RLS: ADMIN/AGENCY only
RLS History
Initial RLS was service_role-only (migration
20260326)Replaced by fine-grained per-user RLS (migration
202604140001):SELECT: quest creators, admins, comment authors
INSERT: authenticated users + guests
UPDATE/DELETE: comment author or admin/agency
9. API ENDPOINTS (Core Commenting)
Authenticated Comments
GET /api/reviewer/comments?quest_id=&node_id=&page=&limit=POST /api/reviewer/comments/create (content max 5000 chars, sanitized)PATCH /api/reviewer/comments/[commentId] (resolve/unresolve)DELETE /api/reviewer/comments/[commentId] (author or admin — triggers deletion log)
Bulk Operations
PATCH /api/reviewer/comments/bulk-resolve (CREATOR/ADMIN/AGENCY)DELETE /api/reviewer/comments/bulk-delete (ADMIN/AGENCY only)POST /api/reviewer/comments/export (CSV or JSON)
Analytics
GET /api/reviewer/analytics/node-feedback (per-node heatmap)GET /api/reviewer/analytics/resolution (rate, avg time, oldest)GET /api/reviewer/analytics/activity (per-reviewer stats)GET /api/reviewer/analytics/personal (current user)
Schemas
Defined in lib/schemas/commenting.schema.ts (216 lines, core CRUD), commenting-bulk.schema.ts (59 lines), analytics.schema.ts (47 lines).
10. DATA REQUIREMENTS
Frontend Needs
CommentPanel.tsx(479 lines) +CommentThread.tsx(296 lines) +CommentForm.tsx(209 lines).CommentingContextfromcomponents/context/CommentingContext.tsxprovidingselectedNodeId,isPanelOpen,questIdvia React context.CommentNodeWrapper.tsx(61 lines) wraps canvas nodes.Node display names via
getNodeDisplayNames()fromlib/utils/node-display-name.ts.
Caching Strategy
Comments fetched fresh on panel open/close (no stale cache).
11. PERFORMANCE CONSIDERATIONS
Database Optimization
Indexes on
quest_comments(quest_id),(node_id),(parent_comment_id).Batched user name lookups (single query for all comment authors).
API Response Time
Target: <300ms for comment list (<100 comments per quest typical).
Who can access this feature?
Creators: view + resolve comments on their quests.
Reviewers: full CRUD on claimed quests.
Admins/Agency: view all, delete any.
Guests: create only (token-based, see [7.2]).
RLS Policies
Fine-grained per-user RLS (migration 202604140001): SELECT for quest creators/admins/comment authors, INSERT for authenticated users + guests, UPDATE/DELETE for comment author or admin/agency. comment_deletion_log restricted to ADMIN/AGENCY only.
Content Moderation
sanitizeCommentContent()strips HTML/script tags before storage.Content validation via Zod schemas in
lib/schemas/commenting.schema.ts.
13. ERROR HANDLING
Error | Response |
|---|---|
5000-char limit exceeded | 400: "Comment exceeds maximum length" |
Content sanitization triggered | Content cleaned silently (HTML tags stripped) |
Non-author delete attempt | 403: "Only the comment author can delete this" |
Invalid node_id | 400: Validation error |
14. TESTING CHECKLIST
Happy Path
□ Create comment → appears in panel → creator notified (fire-and-forget)
□ Reply to comment → thread displayed with indentation
□ Resolve comment → marked resolved, resolution rate updated
□ Export as CSV/JSON → all comments included
Edge Cases
□ Empty comment → validation error
□ HTML injection → sanitized
□ Delete parent comment → replies survive (SET NULL on FK)
□ Non-author delete → 403
□ deletion_log trigger fires → content_hash + metadata logged
15. OPEN QUESTIONS
"Action Items (Feedback)" in ReviewSidebar is currently a placeholder — should pull real comment data.
CommentNotification component integration with
CommentingContext.
16. OUT OF SCOPE (v1.1+)
Rich text formatting in comments.
@mentions within comments.
Comment reactions/upvotes.
Real-time (WebSocket) comment updates.
17. SUCCESS METRICS
Average comments per review: 5+.
Resolution rate: >80%.
All comment deletions logged via
comment_deletion_logtrigger.
18. DEPENDENCIES
This feature depends on:
[5.4] Reviewer Queue Backend — review pipeline.
[7.2] Guest Access & Invitations — guest comment auth.
[7.3] Notification System — fire-and-forget comment notifications.
[W1.5] Canvas Schema — node-level attachment.
[W1.4] ApiResponse — standardized responses.
These features depend on this:
Reviewer approval workflow (must resolve comments before approving).
Creator revision workflow (comments guide changes).
19. TIMELINE & OWNERSHIP
Sprint #12: Already deployed.
Backend: scorevi
Frontend: scorevi
Estimated Completion: Complete.
Document Version
1.0 - Initial version - 2026-06-29 08:23 UTC
1.1 - Added Document Version section and update author to have full name - 2026-06-29 08:48 UTC