Skip to main content

AI Quality Feedback (AQF) Loop

Author: ChainAlign Engineering Status: โœ… Implemented Date: November 17, 2025 Feature Owner: Product Priority: High Implementation Date: November 17, 2025


1. ๐ŸŽฏ Executive Summaryโ€‹

This document outlines the AI Quality Feedback (AQF) Loop, an internal system for capturing real-time user sentiment on AI-generated insights. This is not a generic "feedback" tool; it is a core mechanism for generating a labeled dataset to enable Reinforcement Learning from Human Feedback (RLHF).

Its purpose is to directly correlate user satisfaction (e.g., "4 - Excellent") with specific AI reasoning chains, allowing us to programmatically fine-tune models and improve the "Judgment OS."

Why We Built This (Buy vs. Build Decision)โ€‹

Decision: Build Internally

Third-party tools like Pendo, Hotjar, or Sprig are excellent for generic product analytics, but they create "black boxes" that prevent us from:

  1. Linking feedback to AI state: We need to know which specific reasoningId (CoT chain) a user rated
  2. Creating training datasets: External tools don't export data in formats suitable for model fine-tuning
  3. Real-time model adaptation: We need programmatic access to feedback for our RLHF pipeline

By building internally, we maintain 100% control over the data and can create a high-quality labeled dataset: (reasoning_chain, user_score).


2. ๐Ÿ“ˆ Goals & Objectivesโ€‹

Primary Goalโ€‹

Create a high-quality, labeled dataset of (reasoning_chain, user_score) pairs for RLHF training.

Objectivesโ€‹

  1. Capture User Sentiment: Record a user's sentiment (1-4 score) in the context of a specific AI interaction
  2. Non-Intrusive UX: Provide a lightweight UI inspired by Claude Code's feedback mechanism
  3. Analytics & Insights: Feed data into analytics to identify high/low-performing AI prompts and models
  4. Auto-Flagging: Automatically flag low-rated content (score โ‰ค 2) for human review

Non-Goalsโ€‹

  • โŒ This is not a "Contact Support" or bug-reporting feature
  • โŒ This is not a generic NPS survey
  • โŒ This is not for gathering text-based feedback (use existing feedbackRoutes.js for that)

3. ๐Ÿ›๏ธ Architectural Overviewโ€‹

Build vs. Buy: Internal Implementationโ€‹

Architecture Pattern: Three-Layer Pattern (Routes โ†’ Services โ†’ DAL)

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ Frontend (React) โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ FeedbackContext (Global State) โ”‚
โ”‚ โ””โ”€โ”€ MicroFeedback Component (shadcn/ui Dialog) โ”‚
โ”‚ โ”œโ”€โ”€ 1: Bad (ThumbsDown) โ”‚
โ”‚ โ”œโ”€โ”€ 2: Fine (Meh) โ”‚
โ”‚ โ”œโ”€โ”€ 3: Good (ThumbsUp) โ”‚
โ”‚ โ””โ”€โ”€ 4: Excellent (Star) โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
โ”‚
โ–ผ POST /api/ai-feedback/rating
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ Backend (Node.js/Express) โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ Routes: aiFeedbackRoutes.js โ”‚
โ”‚ โ””โ”€โ”€ POST /api/ai-feedback/rating โ”‚
โ”‚ โ””โ”€โ”€ GET /api/ai-feedback/analytics?days=30 โ”‚
โ”‚ โ””โ”€โ”€ GET /api/ai-feedback/reasoning/:reasoningId โ”‚
โ”‚ โ”‚
โ”‚ Service: AiFeedbackService.js โ”‚
โ”‚ โ”œโ”€โ”€ recordFeedback(user, score, context) โ”‚
โ”‚ โ”œโ”€โ”€ flagReasoningForReview(reasoningId, score) [async] โ”‚
โ”‚ โ”œโ”€โ”€ getFeedbackAnalytics(user, daysAgo) โ”‚
โ”‚ โ””โ”€โ”€ getFeedbackForReasoning(user, reasoningId) โ”‚
โ”‚ โ”‚
โ”‚ Repository: AiFeedbackRatingsRepository.js โ”‚
โ”‚ โ””โ”€โ”€ Extends BaseRepository (tenant-scoped) โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
โ”‚
โ–ผ
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ Database (PostgreSQL + pgvector) โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ Table: ai_feedback_ratings โ”‚
โ”‚ โ”œโ”€โ”€ id (UUID) โ”‚
โ”‚ โ”œโ”€โ”€ tenant_id (UUID, FK) โ”‚
โ”‚ โ”œโ”€โ”€ user_id (UUID, FK) โ”‚
โ”‚ โ”œโ”€โ”€ score (SMALLINT, 1-4) โ”‚
โ”‚ โ”œโ”€โ”€ context (JSONB) โ† The key to RLHF โ”‚
โ”‚ โ””โ”€โ”€ created_at (TIMESTAMPTZ) โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

4. ๐Ÿ“‹ Functional Requirementsโ€‹

FR1: UI Component (MicroFeedback.jsx)โ€‹

Location: frontend/src/components/MicroFeedback.jsx

Requirements:

  • โœ… Non-blocking modal using shadcn/ui Dialog component
  • โœ… Simple question: "How was this insight?"
  • โœ… Four clickable options with icons and colors:
    • 1 (Bad) - ThumbsDown icon, red color, "Not helpful"
    • 2 (Fine) - Meh icon, yellow color, "Somewhat helpful"
    • 3 (Good) - ThumbsUp icon, blue color, "Helpful"
    • 4 (Excellent) - Star icon, green color, "Very helpful"
  • โœ… Clicking an option fires the API request and dismisses the modal
  • โœ… Visual feedback during submission (loading state)

Implementation:

<MicroFeedback
isOpen={isOpen}
onClose={closeFeedback}
onSubmit={submitFeedback}
context={currentContext}
/>

FR2: Triggering Logicโ€‹

V1 (Implemented - Manual Trigger):

import { useFeedback } from '../context/FeedbackContext.jsx';

const MyComponent = () => {
const { showFeedback } = useFeedback();

return (
<button onClick={() => showFeedback({
page: '/dashboard/sop',
componentId: 'critical_insight_001',
reasoningId: 'cot_uuid_abc123',
})}>
How was this insight?
</button>
);
};

V2 (Future - Proactive Trigger):

  • Trigger after user engagement (e.g., "user expands CoT panel for >5 seconds")
  • Random sampling (e.g., "show to 10% of users on each insight")
  • Smart timing (e.g., "after user completes a decision workflow")

FR3: Backend Endpointโ€‹

Endpoint: POST /api/ai-feedback/rating

Authentication: Bearer Token (Firebase JWT via verifyToken middleware)

Request Schema (Zod Validation):

{
score: number (1-4, required),
context: {
page?: string,
componentId?: string,
reasoningId?: string,
insightId?: string,
decisionId?: string,
scenarioId?: string,
}
}

Response:

{
"message": "Feedback received. Thank you!",
"feedbackId": "uuid-here"
}

Status Code: 202 Accepted (async processing)

Implementation Details:

  • โœ… Protected by verifyToken middleware
  • โœ… Zod schema validation
  • โœ… Tenant-scoped data storage
  • โœ… Async background processing for low-rated feedback
  • โœ… Non-blocking response (< 100ms p99)

Critical Requirement: The frontend MUST send a context object to link the score to specific AI outputs.

Example Payload:

{
"score": 4,
"context": {
"page": "/dashboard/sop",
"componentId": "critical_insight_001",
"reasoningId": "cot_uuid_abc123", // โ† The KEY link for RLHF
"insightId": "insight_456",
"decisionId": "decision_789"
}
}

Context Fields:

  • page: Current page URL or identifier
  • componentId: UI component that triggered feedback
  • reasoningId: CRITICAL - UUID of the CoT reasoning chain
  • insightId: UUID of the insight being rated
  • decisionId: UUID of the decision being rated
  • scenarioId: UUID of the scenario being rated

Why This Matters: Without reasoningId, we cannot:

  • Identify which AI prompt generated the output
  • Fine-tune models based on user feedback
  • A/B test different reasoning approaches
  • Build a labeled dataset for RLHF

5. ๐Ÿ”’ Non-Functional Requirements (NFRs)โ€‹

NFR-1: Performanceโ€‹

  • โœ… API Response Time: < 100ms (p99)
  • โœ… Non-Blocking: Async background processing for flagging
  • โœ… Database Indexing: GIN index on JSONB context field

NFR-2: Multi-Tenancyโ€‹

  • โœ… All data is tenant-scoped via BaseRepository
  • โœ… Queries automatically filtered by tenant_id
  • โœ… No cross-tenant data leakage

NFR-3: Data Retentionโ€‹

  • โœ… Feedback stored indefinitely for RLHF training
  • ๐Ÿ”„ Phase 2: Implement data retention policies (e.g., 2 years)

NFR-4: GDPR Compliance (Phase 2 - Not Yet Implemented)โ€‹

Status: โš ๏ธ To Be Implemented

Requirements:

  1. This feature constitutes "profiling" under GDPR as it tracks user behavior to adapt the service
  2. Must be disabled by default for all users
  3. Can only be enabled if user has given explicit consent via Consent Management System
  4. Must check ConsentService.checkConsent(userId, 'profiling') before triggering modal
  5. Users must be able to withdraw consent and request data deletion

Implementation Plan:

  • Integrate with Consent Management System (Phase 2.1 of Unified Compliance Plan)
  • Add consent check in FeedbackContext.showFeedback()
  • Add data deletion endpoint for GDPR Right to Erasure
  • Add consent banner for "AI Quality Improvement" purpose

Current Workaround:

  • Feature is opt-in (user must click to trigger)
  • No automatic/proactive triggering without consent

6. ๐Ÿ—„๏ธ Database Schemaโ€‹

Table: ai_feedback_ratingsโ€‹

Migration: 20251117000001_create_ai_feedback_ratings_table.cjs

CREATE TABLE "public"."ai_feedback_ratings" (
"id" UUID PRIMARY KEY DEFAULT gen_random_uuid(),
"tenant_id" UUID NOT NULL REFERENCES "public"."tenants"("id") ON DELETE CASCADE,
"user_id" UUID NOT NULL REFERENCES "public"."users"("id") ON DELETE CASCADE,
"score" SMALLINT NOT NULL CHECK (score >= 1 AND score <= 4),
"context" JSONB,
"created_at" TIMESTAMPTZ DEFAULT now()
);

-- Indexes for performance
CREATE INDEX "idx_feedback_user" ON "public"."ai_feedback_ratings" ("user_id");
CREATE INDEX "idx_feedback_tenant" ON "public"."ai_feedback_ratings" ("tenant_id");
CREATE INDEX "idx_feedback_created_at" ON "public"."ai_feedback_ratings" ("created_at");

-- GIN index for JSONB queries
CREATE INDEX "idx_feedback_context_gin" ON "public"."ai_feedback_ratings" USING GIN ("context");

-- Comment for clarity
COMMENT ON COLUMN "public"."ai_feedback_ratings"."context" IS
'Stores the UI/AI state when feedback was given. E.g., { "page": "/dashboard", "componentId": "critical_insight_001", "reasoningId": "cot_uuid_abc123" }';

Key Design Decisions:

  1. JSONB for Context: Flexible schema for different feedback types
  2. GIN Index: Fast queries on context->>'reasoningId'
  3. Cascade Deletion: Feedback deleted if user/tenant is deleted
  4. Check Constraint: Ensures score is always 1-4

7. ๐Ÿ”Œ API Specificationโ€‹

Endpoint 1: Submit Feedback Ratingโ€‹

Method: POST Path: /api/ai-feedback/rating Auth: Bearer Token (Firebase JWT)

Request Body:

{
"score": 4,
"context": {
"page": "/dashboard/sop",
"componentId": "critical_insight_001",
"reasoningId": "cot_uuid_abc123",
"insightId": "insight_456"
}
}

Response (202 Accepted):

{
"message": "Feedback received. Thank you!",
"feedbackId": "550e8400-e29b-41d4-a716-446655440000"
}

Error Responses:

  • 400 Bad Request: Invalid score or missing required fields
  • 401 Unauthorized: Missing or invalid auth token
  • 500 Internal Server Error: Server error

Endpoint 2: Get Feedback Analyticsโ€‹

Method: GET Path: /api/ai-feedback/analytics?days=30 Auth: Bearer Token

Query Parameters:

  • days (optional): Number of days to look back (default: 30)

Response (200 OK):

{
"totalCount": 127,
"avgScore": 3.45,
"npsScore": 68.5,
"distribution": [
{ "score": 1, "count": 5 },
{ "score": 2, "count": 12 },
{ "score": 3, "count": 45 },
{ "score": 4, "count": 65 }
],
"promoters": 65,
"passives": 45,
"detractors": 17
}

Metrics Explained:

  • avgScore: Average rating (1.0 - 4.0)
  • npsScore: Net Promoter Score-like metric (% promoters - % detractors)
  • promoters: Users who rated 4 (Excellent)
  • passives: Users who rated 3 (Good)
  • detractors: Users who rated 1-2 (Bad/Fine)

Endpoint 3: Get Feedback for Reasoning Chainโ€‹

Method: GET Path: /api/ai-feedback/reasoning/:reasoningId Auth: Bearer Token

Response (200 OK):

{
"reasoningId": "cot_uuid_abc123",
"feedbackCount": 8,
"avgScore": "3.75",
"feedback": [
{
"id": "uuid-1",
"score": 4,
"context": { "page": "/dashboard", "componentId": "insight_001" },
"created_at": "2025-11-17T10:30:00Z"
},
{
"id": "uuid-2",
"score": 3,
"context": { "page": "/dashboard", "componentId": "insight_001" },
"created_at": "2025-11-17T11:15:00Z"
}
]
}

8. ๐ŸŽจ User Experience Flowโ€‹

Manual Trigger Flow (V1 - Implemented)โ€‹

1. User views an AI-generated insight
โ””โ”€> ReasoningPanel renders with "How was this insight?" button

2. User clicks "How was this insight?"
โ””โ”€> showFeedback({ reasoningId, componentId, page }) triggered

3. MicroFeedback modal appears
โ””โ”€> User sees 4 options: Bad, Fine, Good, Excellent

4. User clicks "Excellent" (score: 4)
โ””โ”€> POST /api/ai-feedback/rating { score: 4, context: {...} }

5. Modal shows "Submitting feedback..."
โ””โ”€> API responds 202 Accepted

6. Modal closes after 500ms
โ””โ”€> User returns to their workflow (uninterrupted)

7. [Background] AiFeedbackService processes the feedback
โ””โ”€> If score โ‰ค 2: Flag reasoning chain for review
โ””โ”€> Update analytics dashboard

Proactive Trigger Flow (V2 - Future)โ€‹

1. User expands CoT reasoning panel
โ””โ”€> Timer starts: 5 seconds

2. After 5 seconds of engagement
โ””โ”€> showFeedback() automatically triggered

3. MicroFeedback modal appears (same as above)
โ””โ”€> User rates or dismisses

4. User consent check
โ””โ”€> if (!ConsentService.checkConsent(userId, 'profiling'))
โ””โ”€> Do NOT trigger (GDPR compliance)

9. ๐Ÿ“Š Analytics & RLHF Use Casesโ€‹

Use Case 1: Fine-Tuning AI Modelsโ€‹

Goal: Improve AI reasoning quality using RLHF

Process:

  1. Export feedback data: SELECT reasoning_id, AVG(score) FROM ai_feedback_ratings GROUP BY reasoning_id
  2. Identify high-performing reasoning chains (avg score โ‰ฅ 3.5)
  3. Extract prompts and parameters from reasoning_bank table
  4. Use as positive examples for model fine-tuning
  5. Identify low-performing chains (avg score โ‰ค 2.0)
  6. Analyze failure patterns and adjust prompts

Dataset Format:

[
{
"reasoning_chain": "...",
"prompt": "...",
"parameters": {...},
"avg_score": 3.8,
"feedback_count": 15
}
]

Use Case 2: Identifying Weak Spotsโ€‹

Query: Which types of insights are performing poorly?

SELECT
context->>'componentId' AS component,
AVG(score) AS avg_score,
COUNT(*) AS feedback_count
FROM ai_feedback_ratings
WHERE created_at > NOW() - INTERVAL '30 days'
GROUP BY context->>'componentId'
ORDER BY avg_score ASC;

Example Output:

component                | avg_score | feedback_count
-------------------------|-----------|---------------
critical_insight_001 | 2.1 | 45
bottleneck_analysis | 3.8 | 30
scenario_suggestion | 3.5 | 22

Action: Improve "critical_insight_001" logic


Use Case 3: A/B Testing AI Modelsโ€‹

Scenario: Testing two different reasoning approaches

Setup:

  • 50% of users get Model A (prompt_v1)
  • 50% of users get Model B (prompt_v2)

Query:

SELECT
context->>'modelVersion' AS model,
AVG(score) AS avg_score,
COUNT(*) AS feedback_count
FROM ai_feedback_ratings
WHERE context->>'experimentId' = 'cot_ab_test_001'
GROUP BY context->>'modelVersion';

Result:

model     | avg_score | feedback_count
----------|-----------|---------------
prompt_v1 | 3.2 | 50
prompt_v2 | 3.8 | 48

Decision: Roll out prompt_v2 to all users


Use Case 4: NPS Tracking Over Timeโ€‹

Goal: Track overall AI satisfaction as a KPI

Metric: NPS Score = (% Promoters - % Detractors) ร— 100

Implementation:

const analytics = await AiFeedbackService.getFeedbackAnalytics(user, 30);
console.log(`NPS Score: ${analytics.npsScore}%`);
// NPS Score: 68.5%

Benchmark:

  • NPS > 70: Excellent
  • NPS 50-70: Good
  • NPS 30-50: Needs improvement
  • NPS < 30: Critical issue

10. ๐Ÿš€ Implementation Statusโ€‹

โœ… Completed (Phase 1)โ€‹

Backend:

  • Database migration (ai_feedback_ratings table)
  • Repository layer (AiFeedbackRatingsRepository.js)
  • Service layer (AiFeedbackService.js)
  • API routes (aiFeedbackRoutes.js)
  • Auto-flagging for low-rated feedback
  • Analytics endpoints
  • Tenant scoping

Frontend:

  • MicroFeedback component (shadcn/ui)
  • FeedbackContext (global state)
  • useFeedback() hook
  • Integration into App.jsx

Documentation:

  • Implementation guide (docs/MICRO_FEEDBACK_SYSTEM.md)
  • Functional specification (this document)

๐Ÿ”„ Planned (Phase 2)โ€‹

GDPR Compliance:

  • Integrate with Consent Management System
  • Add consent check before triggering modal
  • Implement data deletion endpoint
  • Add consent banner for "AI Quality Improvement"

Proactive Triggering:

  • Smart trigger based on user engagement
  • Random sampling (10% of users)
  • Cooldown period (don't spam users)

Advanced Analytics:

  • Feedback trends dashboard
  • Correlation analysis (feedback vs. user retention)
  • Automated model retraining based on feedback

Review Queue:

  • Admin interface for reviewing low-rated feedback
  • Automated alerts for score < 2
  • Integration with Linear for task creation

11. ๐Ÿงช Testing Strategyโ€‹

Unit Testsโ€‹

# Backend service tests
npm test --workspace=backend -- AiFeedbackService.test.js

# Repository tests
npm test --workspace=backend -- AiFeedbackRatingsRepository.test.js

Integration Testsโ€‹

# API endpoint tests
npm test --workspace=backend -- aiFeedbackRoutes.test.js

Manual Testing Checklistโ€‹

  • Run migration: npx knex migrate:latest --env development
  • Submit feedback via UI modal
  • Verify data in database: SELECT * FROM ai_feedback_ratings;
  • Test analytics endpoint: GET /api/ai-feedback/analytics?days=7
  • Test reasoning endpoint: GET /api/ai-feedback/reasoning/:id
  • Verify low-score flagging in logs (score โ‰ค 2)
  • Test tenant isolation (create feedback from 2 different tenants)

12. ๐Ÿ“š Referencesโ€‹

  • Backend:

    • backend/src/routes/aiFeedbackRoutes.js
    • backend/src/services/AiFeedbackService.js
    • backend/src/dal/AiFeedbackRatingsRepository.js
    • backend/migrations/20251117000001_create_ai_feedback_ratings_table.cjs
  • Frontend:

    • frontend/src/components/MicroFeedback.jsx
    • frontend/src/context/FeedbackContext.jsx
    • frontend/src/App.jsx

External Resourcesโ€‹


13. ๐ŸŽฏ Success Metricsโ€‹

KPIs (30-day rolling window)โ€‹

  1. Participation Rate: % of users who submit at least 1 feedback

    • Target: > 20%
  2. Average NPS Score: (% Promoters - % Detractors)

    • Target: > 60
  3. Low-Score Flag Rate: % of feedback with score โ‰ค 2

    • Target: < 10%
  4. Feedback Coverage: % of AI insights that receive feedback

    • Target: > 30%
  5. Time to Improvement: Days from low-score flag to prompt fix

    • Target: < 7 days

14. ๐Ÿ” Security Considerationsโ€‹

Authentication & Authorizationโ€‹

  • โœ… All endpoints protected by Firebase JWT
  • โœ… Tenant-scoped queries (no cross-tenant access)
  • โœ… User must be authenticated to submit feedback

Data Privacyโ€‹

  • โœ… No PII stored in context field (only IDs and metadata)
  • โš ๏ธ GDPR consent required before triggering (Phase 2)
  • โœ… Feedback is user-specific (can be deleted on user request)

Rate Limitingโ€‹

  • ๐Ÿ”„ Phase 2: Implement rate limiting (max 10 feedback/user/minute)
  • ๐Ÿ”„ Phase 2: Add cooldown period (1 feedback per insight per user)

15. ๐Ÿ“ Changelogโ€‹

DateVersionAuthorChanges
2025-11-171.0ChainAlign EngineeringInitial implementation and documentation
2025-11-171.1ChainAlign EngineeringUpdated FSD based on actual implementation

16. โœ… Approval & Sign-Offโ€‹

RoleNameStatusDate
Engineering LeadTBDโณ Pending-
Product OwnerTBDโณ Pending-
Legal/ComplianceTBDโณ Pending-
SecurityTBDโณ Pending-

End of Document