Skip to content

๐Ÿ—ฃ๏ธ User Feedback

๐Ÿ“‹ Overview

Architecture of the Give Feedback feature powered by QuackBack.

Secure SSO token-based authentication, automatic theme sync, responsive design, and outside-click dismissal. Migration-ready architecture using internal user IDs instead of vendor-specific identifiers.


๐Ÿ—๏ธ Architecture

Design Principles

  1. Migration-Proof Identity โ€” Internal ULID-based user IDs (not Clerk IDs)
  2. Secure SSO Authentication โ€” HMAC-SHA256 signed JWT tokens
  3. Zero UI Changes โ€” Single "Give Feedback" button interface
  4. Progressive Enhancement โ€” Graceful degradation if SDK unavailable
  5. Theme Consistency โ€” Auto-syncs with app light/dark mode

System Flow

Frontend (Clerk) โ†’ Backend (/api/widget-sso) โ†’ QuackBack Widget
Get JWT โ†’ Request SSO โ†’ Sign Token โ†’ Identify User โ†’ Pre-fill Form


๐Ÿ” SSO Authentication

Why SSO?

Benefit Description
Security Prevents user impersonation via cryptographic signatures
Trust Backend-signed tokens verified by QuackBack
No Tampering Browser cannot fake user identity

Token Format

HMAC-SHA256 signed JWT with 5-minute expiration containing internal userId (not Clerk ID)


๐Ÿ”„ How It Works

1. SDK Initialization

  • SDK loaded asynchronously from https://together.visualli.ai/api/widget/sdk.js
  • Widget initializes with hidden default launcher (custom button used)
  • Initial theme detected from localStorage or system preference
  • Responsive sizing: 450ร—500px desktop, 70dvh mobile drawer

2. SSO Token Request

  • QuackbackIdentify monitors Clerk authentication state
  • On login, requests SSO token from /api/widget-sso
  • Backend validates Clerk JWT, fetches user from MongoDB
  • Returns signed token with internal userId, email, name

3. User Authentication

  • Frontend authenticates widget with SSO token
  • QuackBack verifies HMAC signature using shared secret
  • Widget pre-fills user data (email, name)
  • Feedback submissions automatically associated with user

4. Theme & UI Sync

  • QuackbackIdentify watches ThemeContext changes
  • Updates widget via DOM class manipulation + CSS overrides
  • Responsive sizing enforced via CSS + MutationObserver
  • Outside-click handler closes widget when clicking outside bounds

5. Feedback Submission

  • User clicks "Give Feedback" button
  • Widget opens with user context pre-filled (if authenticated)
  • User submits text feedback through QuackBack interface
  • QuackBack backend handles storage and processing

๐Ÿ—„๏ธ Database & Identity

Dual ID System

ID Type Purpose Format
Clerk ID Authentication only (not sent to QuackBack) Standard Clerk format
Internal ID Canonical identifier, migration-ready ULID format

Name Resolution Strategy

MongoDB user record โ†’ Clerk API โ†’ Email prefix โ†’ "User" fallback

This decoupling enables migration to different auth providers without changing QuackBack data.


๐Ÿ—๏ธ Responsibilities

Component Responsibilities
Frontend Loads SDK asynchronously
Renders "Give Feedback" button
Requests SSO tokens from backend
Authenticates widget
Syncs theme via DOM classes
Enforces responsive sizing
Handles outside-click dismissal
Backend Validates Clerk JWT (Bearer auth)
Fetches user from MongoDB
Resolves user name
Signs SSO tokens with HMAC-SHA256
Requires QUACKBACK_WIDGET_SECRET env variable
QuackBack Verifies SSO token signatures
Stores feedback submissions
Associates feedback with internal user IDs
Provides dashboard and analytics

โš™๏ธ Key Design Decisions

Decision Reason Trade-off
Internal User IDs Decouples from auth provider, migration-ready None
SSO Token Authentication Prevents user impersonation, secure identity verification Requires backend endpoint
Database Call for userId Need internal ID for migration-proof identity One query per session
Name from Clerk API No schema change needed, OAuth has latest data Extra API call (~100ms)
Hidden Default Launcher Uses custom button for consistent UI/UX None
CSS + MutationObserver Robust responsive sizing, works if SDK changes markup Slightly more complex
DOM Class Theme Sync SDK may not support runtime config updates Requires !important CSS rules
Async SDK Loading Non-blocking, doesn't impact initial page render Must check availability

๐ŸŽจ UI Customization

Feature Desktop Mobile Implementation
Theme Sync Light/Dark Light/Dark DOM classes + CSS !important rules
Widget Size 450ร—500px bottom-right 70dvh full-width drawer CSS + MutationObserver
Outside Click Closes on outside click Closes on outside click Click handler checks bounds

๐Ÿ“ฆ Integration Components

Backend

/api/widget-sso/route.js โ€” SSO token generation endpoint

Frontend

File Purpose
global.d.ts TypeScript declarations for QuackBack SDK
index.html SDK loader + CSS overrides
QuackbackIdentify.tsx SSO authentication, theme sync, sizing, outside-click handler
FeedbackButton.tsx Widget trigger with availability checks

๐Ÿ”’ Security

Trust Model: Backend signs โ†’ QuackBack verifies โ†’ Trusts data

Concern Mitigation
User impersonation HMAC-SHA256 signed tokens verified by QuackBack
Token expiry 5-minute expiration window
Secret exposure Server-side secret, never sent to client
Unauthorized API access Clerk JWT Bearer auth required
Data exposure Only email, name, and internal userId sent
SDK availability Defensive checks, graceful degradation
Script injection SDK loaded from trusted domain

๐Ÿš€ Migration Path

Switching Auth Providers: Update auth middleware only โ€” no QuackBack data migration needed (internal IDs remain stable).

Example: Clerk โ†’ Auth0 migration requires updating backend token validation, but all existing feedback remains associated with same internal user IDs.


๐Ÿ” User Flows

Authenticated Flow

User logs in via Clerk โ†’ QuackbackIdentify detects authentication โ†’ Requests SSO token โ†’ Backend validates & signs token โ†’ Frontend authenticates widget โ†’ User clicks "Give Feedback" โ†’ Widget opens with email/name pre-filled โ†’ Feedback submitted with internal userId

Anonymous Flow

User not logged in โ†’ Clicks "Give Feedback" โ†’ Widget opens without pre-filled data โ†’ Submits feedback anonymously

Theme Change Flow

User toggles theme โ†’ ThemeContext updates โ†’ QuackbackIdentify detects change โ†’ Applies DOM classes โ†’ CSS overrides enforce visual consistency


๐Ÿ“Š Performance

Total Latency: ~200ms first call

Component Time Notes
SDK Load ~50ms Async, non-blocking
MongoDB Query ~20ms Fetch user by Clerk ID
Clerk API Call ~100ms Resolve name (if not in DB)
Token Signing ~5ms HMAC-SHA256
Widget Auth ~25ms Verify signature

Optimization: Name stored in MongoDB eliminates Clerk API call (~100ms savings)


๐Ÿ“š Configuration

Setting Value
Environment Variable QUACKBACK_WIDGET_SECRET (required in all .env.* files)
Dashboard https://together.visualli.ai

๐Ÿ“ Implementation Files

Backend: /api/widget-sso/route.js

Frontend: index.html, global.d.ts, QuackbackIdentify.tsx, FeedbackButton.tsx, App.tsx