From 8b07a59da0241a05e0231a9bcc79b182a5350c26 Mon Sep 17 00:00:00 2001 From: DJP Date: Fri, 10 Apr 2026 16:54:49 -0400 Subject: [PATCH] fix: persist feedback/comments across page reloads on review page Feedback was saving to DB but never loaded back on page revisit. Three-point fix: - Backend schema: add feedback list to OutputRowResponse - Backend service: eagerly load feedback relationship in preview query - Frontend mapper: map latest feedback entry to OutputRow.feedback Co-Authored-By: Claude Opus 4.6 --- backend/app/schemas/output.py | 13 +++++++++++++ backend/app/services/output_service.py | 3 ++- frontend/src/lib/api.ts | 20 ++++++++++++++++++++ 3 files changed, 35 insertions(+), 1 deletion(-) diff --git a/backend/app/schemas/output.py b/backend/app/schemas/output.py index b562736..35f5ebd 100644 --- a/backend/app/schemas/output.py +++ b/backend/app/schemas/output.py @@ -1,3 +1,4 @@ +from datetime import datetime from typing import Any from uuid import UUID @@ -6,6 +7,17 @@ from pydantic import BaseModel from app.models.output import ConfidenceTier +class FeedbackSummary(BaseModel): + """Lightweight feedback info embedded in output row responses.""" + id: UUID + flag_type: str + comment: str | None = None + user_id: UUID + created_at: datetime + + model_config = {"from_attributes": True} + + class OutputRowResponse(BaseModel): id: UUID instance_id: UUID @@ -26,6 +38,7 @@ class OutputRowResponse(BaseModel): character_count_option_1: int | None = None character_count_option_2: int | None = None character_count_option_3: int | None = None + feedback: list[FeedbackSummary] = [] model_config = {"from_attributes": True} diff --git a/backend/app/services/output_service.py b/backend/app/services/output_service.py index 78ef99f..c293403 100644 --- a/backend/app/services/output_service.py +++ b/backend/app/services/output_service.py @@ -47,11 +47,12 @@ class OutputService: for sl in source_result.scalars().all() ] - # Get output rows + # Get output rows with feedback eagerly loaded output_result = await db.execute( select(OutputRow) .where(OutputRow.instance_id == instance.id) .order_by(OutputRow.row_order) + .options(selectinload(OutputRow.feedback)) ) output_rows = [ OutputRowResponse.model_validate(row) diff --git a/frontend/src/lib/api.ts b/frontend/src/lib/api.ts index 3be5e5c..87792d2 100644 --- a/frontend/src/lib/api.ts +++ b/frontend/src/lib/api.ts @@ -357,6 +357,18 @@ export async function getOutputPreview( }); } + // Map feedback - take the most recent entry if any exist + const feedbackList = row.feedback || []; + const latestFeedback = feedbackList.length > 0 + ? feedbackList[feedbackList.length - 1] + : null; + + const STATUS_MAP: Record = { + approved: "APPROVED", + needs_revision: "NEEDS_REVISION", + comment: "COMMENTED", + }; + return { id: String(row.id), locale_instance_id: String(row.instance_id), @@ -368,6 +380,14 @@ export async function getOutputPreview( options, rationale: row.rationale_1 || "", is_flagged: row.confidence_tier === "low", + feedback: latestFeedback ? { + id: String(latestFeedback.id), + output_row_id: String(row.id), + status: STATUS_MAP[latestFeedback.flag_type] || "COMMENTED", + comment: latestFeedback.comment || undefined, + reviewer: String(latestFeedback.user_id), + created_at: latestFeedback.created_at, + } : undefined, }; });