Skip to content

feat(feedback): feedback button, per-message thumbs, PostHog events#3623

Open
rafavalls wants to merge 6 commits into
mainfrom
rafavalls/feedback-button-modal
Open

feat(feedback): feedback button, per-message thumbs, PostHog events#3623
rafavalls wants to merge 6 commits into
mainfrom
rafavalls/feedback-button-modal

Conversation

@rafavalls
Copy link
Copy Markdown
Collaborator

@rafavalls rafavalls commented Jun 1, 2026

What is this contribution about?

Adds two feedback surfaces to Studio: a Feedback item in the account popover menu that opens a general feedback modal, and thumbs up / thumbs down buttons on each assistant chat message. Thumbs up tracks a positive signal (togglable); thumbs down opens a structured "Share feedback" modal with reason chips (Incorrect or incomplete, Not what I asked for, etc.) and an optional details field. All PostHog events include `message_id`, `thread_id`, `message_content` snippet, and a `session_replay_url` timestamped to the exact moment of feedback. Terms of Use and Privacy Policy were removed from the account menu to reduce clutter.

Screenshots/Demonstration

  • Account menu now shows: Preferences → Feedback → decocms/studio → Community → Homepage → Sign out
  • Chat messages show copy · 👍 · 👎 on hover; thumbs up fills and hides thumbs down on click (clickable again to undo)
  • Thumbs down opens a modal with selectable reason chips + optional text

How to Test

  1. Open the account popover and click Feedback — modal should appear with a textarea and send via PostHog on submit
  2. Send a chat message, hover the assistant response — copy, thumbs up, and thumbs down buttons should appear
  3. Click thumbs up — icon fills, thumbs down vanishes; click again to undo
  4. Click thumbs down — "Share feedback" modal opens; select reasons and submit
  5. Check PostHog Events for user_feedback, chat_message_feedback_positive, and chat_message_feedback_negative with expected properties

Migration Notes

No migrations required. Requires POSTHOG_KEY to be set for events to be captured (no-op on self-hosted installs without it).

Review Checklist

  • PR title is clear and descriptive
  • Changes are tested and working
  • Documentation is updated (if needed)
  • No breaking changes

Summary by cubic

Adds a Feedback button in the account menu and per‑message thumbs to collect chat feedback. Free‑text is posted to a new, org‑scoped POST /api/:org/feedback route and PostHog receives safe events with session replay links.

  • New Features

    • Account menu now has Feedback. Opens a modal, posts to POST /api/:org/feedback (pluggable FeedbackSink, default structured log), and sends user_feedback_submitted.
    • Assistant messages show thumbs up/down. Up toggles (with undo); down opens a modal with reasons and optional details. Negative details are posted to the backend. Sends chat_message_feedback_positive, chat_message_feedback_positive_undone, and chat_message_feedback_negative.
    • Events include message_id, thread_id, and a timestamped session replay URL.
  • Bug Fixes

    • Hardened API: require auth and org membership, cap body at 65 KB (413), return 400 on invalid JSON, return 401 JSON when unauthenticated, and 502 on sink failures.
    • Free‑text (including negative details) is handled server‑side; message_content removed from negative events; session replay URL captured at submit time.
    • UI reliability: prevent empty negative feedback (incl. Cmd/Ctrl+Enter), await POST with disabled submit and error toasts; restored Terms of Use and Privacy Policy links; added unit and E2E tests for the route and UI.

Written for commit 67dbfa8. Summary will update on new commits.

Review in cubic

Adds a Feedback menu item to the account popover that opens a general
feedback modal. Adds thumbs up/thumbs down actions on each assistant
chat message — thumbs up tracks a positive signal, thumbs down opens a
structured "Share feedback" modal with reason chips and optional details.
All events are sent to PostHog with thread_id, message_id, message
content snippet, and a session_replay_url for direct recording links.
Removes Terms of Use and Privacy Policy from the account menu.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jun 1, 2026

🧪 Benchmark

Should we run the Virtual MCP strategy benchmark for this PR?

React with 👍 to run the benchmark.

Reaction Action
👍 Run quick benchmark (10 & 128 tools)

Benchmark will run on the next push after you react.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jun 1, 2026

Release Options

Suggested: Minor (2.381.0) — based on feat: prefix

React with an emoji to override the release type:

Reaction Type Next Version
👍 Prerelease 2.380.12-alpha.1
🎉 Patch 2.380.12
❤️ Minor 2.381.0
🚀 Major 3.0.0

Current version: 2.380.11

Note: If multiple reactions exist, the smallest bump wins. If no reactions, the suggested bump is used (default: patch).

Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

4 issues found across 5 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="apps/mesh/src/web/components/chat/message/parts/text-part.tsx">

<violation number="1" location="apps/mesh/src/web/components/chat/message/parts/text-part.tsx:46">
P2: Positive feedback events miss `message_content`. Add snippet like negative flow so analytics stays consistent per message.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread apps/mesh/src/web/components/chat/message-feedback-dialog.tsx Outdated
Comment thread apps/mesh/src/web/components/feedback-dialog.tsx
const handleThumbsUp = () => {
if (feedback === "positive") {
setFeedback(null);
track("chat_message_feedback_positive_undone", {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Positive feedback events miss message_content. Add snippet like negative flow so analytics stays consistent per message.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/mesh/src/web/components/chat/message/parts/text-part.tsx, line 46:

<comment>Positive feedback events miss `message_content`. Add snippet like negative flow so analytics stays consistent per message.</comment>

<file context>
@@ -35,8 +40,30 @@ export function MessageTextPart({
+  const handleThumbsUp = () => {
+    if (feedback === "positive") {
+      setFeedback(null);
+      track("chat_message_feedback_positive_undone", {
+        message_id: id,
+        thread_id: threadId,
</file context>

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Disagree — omitting message_content from the positive event is intentional, not an oversight.

The negative flow originally included it but it was removed because chat messages in this MCP control plane regularly contain API keys, OAuth tokens, and connection strings. Sending raw message content to PostHog (a third-party SaaS) is a data leak risk regardless of whether the feedback is positive or negative.

Both flows use message_id + thread_id for correlation. Full content can be retrieved internally from those IDs. Keeping the two events symmetric means both are safe, not both are unsafe.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the feedback! I've saved this as a new learning to improve future reviews.

Comment thread apps/mesh/src/web/components/chat/message/parts/text-part.tsx Outdated
…ity and UX issues

- Add POST /api/:org/feedback backend route; free-text is logged server-side
  instead of being sent verbatim to PostHog (chat messages may contain secrets)
- Remove message_content from chat_message_feedback_negative PostHog event;
  message_id + thread_id are sufficient for correlation
- Move getSessionReplayUrl() call to inside handleSubmit (was captured at
  render time, now captured at submission time)
- Remove dead sending state from FeedbackDialog
- Fix Ctrl/Cmd+Enter keyboard shortcut bypassing empty-feedback guard in
  MessageFeedbackDialog
- Restore Terms of Use and Privacy Policy links to account popover
- Revert showCopyButton to copyable && !!extraActions (last part only)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

4 issues found across 6 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="apps/mesh/src/web/components/chat/message/parts/text-part.tsx">

<violation number="1" location="apps/mesh/src/web/components/chat/message/parts/text-part.tsx:46">
P2: Positive feedback events miss `message_content`. Add snippet like negative flow so analytics stays consistent per message.</violation>
</file>

<file name="apps/mesh/src/web/components/feedback-dialog.tsx">

<violation number="1" location="apps/mesh/src/web/components/feedback-dialog.tsx:35">
P2: Event name changed from expected contract. Analytics keyed on `user_feedback` will miss these submissions.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread apps/mesh/src/web/components/feedback-dialog.tsx Outdated
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ message: message.trim() }),
});
track("user_feedback_submitted", {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Event name changed from expected contract. Analytics keyed on user_feedback will miss these submissions.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/mesh/src/web/components/feedback-dialog.tsx, line 35:

<comment>Event name changed from expected contract. Analytics keyed on `user_feedback` will miss these submissions.</comment>

<file context>
@@ -15,20 +15,26 @@ import { track, getSessionReplayUrl } from "@/web/lib/posthog-client";
+      headers: { "Content-Type": "application/json" },
+      body: JSON.stringify({ message: message.trim() }),
+    });
+    track("user_feedback_submitted", {
       session_replay_url: getSessionReplayUrl(),
     });
</file context>

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Intentional. The old user_feedback event carried the raw message field in the PostHog payload — sending free-text user input to a third-party SaaS. The rename signals a schema break: user_feedback_submitted carries only session_replay_url, no message content. Any dashboards on the old event were reading PII-containing data and need to be updated to the new event name and schema regardless.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the feedback! I've saved this as a new learning to improve future reviews.

Comment thread apps/mesh/src/api/routes/feedback.ts Outdated
Comment thread apps/mesh/src/api/routes/feedback.ts Outdated
rafavalls and others added 4 commits June 2, 2026 00:33
- FeedbackDialog.handleSubmit is now async: awaits the fetch, closes and
  shows success only on res.ok, shows error toast on failure; sending state
  disables the button and keyboard shortcut during the in-flight request
- feedback.ts: wrap c.req.json() in try/catch so malformed bodies return
  400 instead of 500

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Free-text feedback no longer hardcodes a destination. Introduce a typed
FeedbackSink that the route awaits; default to a structured log line, and let
operators swap in their own (Linear, Slack, DB, webhook) at the mount site.
Final destination is still being decided.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Require auth, cap payload size, handle sink failures, and send negative
chat details through POST /feedback instead of PostHog. Add unit and e2e tests.

Co-authored-by: Cursor <cursoragent@cursor.com>
The root app onError handler maps thrown HTTPException to 500, breaking
the unauthenticated e2e assertion.

Co-authored-by: Cursor <cursoragent@cursor.com>
Copy link
Copy Markdown
Collaborator

@pedrofrxncx pedrofrxncx left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this cant ship, we need to do another way. i'll elaborate

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants