3.9 KiB
3.9 KiB
08. Feedback API Endpoint for Accuracy Ratings and Storage Consent
meta: id: multi-image-user-feedback-08 feature: multi-image-user-feedback priority: P1 depends_on: [multi-image-user-feedback-01] tags: [api, backend, database]
objective:
- Create a POST endpoint at
/api/feedbackthat accepts diagnosis feedback submissions (accuracy rating, notes, image storage consent) and persists them to the database.
deliverables:
src/app/api/feedback/route.ts— new API routesrc/app/api/feedback/feedback.test.ts— test file
steps:
-
Create
src/app/api/feedback/route.ts:Route:
POST /api/feedbackAccepts JSON body matching
FeedbackRequest:{ sessionId: string; imageIds: string[]; userSpecies?: string; predictedDiseaseId: string; accuracyRating: "correct" | "incorrect" | "unsure"; consentToStoreImages: boolean; userCorrectedSpecies?: string; notes?: string; }Handler logic:
- Parse and validate request body
- Generate UUID for
id - Get
modelVersionfrom model loader'sgetStatus() - Set
createdAtto current timestamp - Insert into
diagnosisFeedbacktable via Drizzle - Return
FeedbackResponse:{ success: true, id: string } - Handle validation errors with 400 status
- Handle DB errors with 500 status
Validation rules:
sessionId— required, non-empty stringimageIds— required, array of non-empty strings, min length 1accuracyRating— required, must be one of "correct", "incorrect", "unsure"consentToStoreImages— required, booleanuserSpecies— optional stringuserCorrectedSpecies— optional string, only meaningful when accuracy is not "correct"notes— optional string, max 500 characters (with error message if exceeded)
-
Create
src/lib/api/feedback.ts— client-side helper:submitFeedback(data: FeedbackRequest): Promise<FeedbackResponse>- POST to
/api/feedbackwith JSON body - 15-second timeout
- Handle network errors gracefully
-
Handle edge cases:
- Invalid JSON body → 400 with descriptive error
- Missing required fields → 400 listing missing fields
- Invalid accuracyRating value → 400 with allowed values
- Database unreachable → 500 with error message
- Duplicate sessionId → allowed (user can submit multiple times for different predictions)
-
CORS and caching:
- Add
Cache-Control: no-storeheader - No authentication required (public endpoint for feedback)
- Add
tests:
- Unit: valid feedback submission returns 200 with success
- Unit: missing required fields return 400
- Unit: invalid accuracyRating returns 400
- Unit: notes over 500 chars returns 400
- Unit: empty imageIds array returns 400
- Unit: client helper
submitFeedback()makes correct fetch call - Unit: client helper handles network error gracefully
- Integration: submit feedback and verify it exists in database
acceptance_criteria:
- POST /api/feedback accepts valid feedback and stores it
- Invalid requests return appropriate 400 errors with descriptive messages
- Database stores all fields correctly
- Client helper function is usable from any feedback component
- Endpoint returns
{ success: true, id }on success
validation:
npx tsc --noEmitpasses- Unit tests pass:
npx vitest run src/app/api/feedback/ - Manual test:
curl -X POST http://localhost:3000/api/feedback -H 'Content-Type: application/json' -d '{"sessionId":"test","imageIds":["img1"],"predictedDiseaseId":"early-blight","accuracyRating":"correct","consentToStoreImages":false}' - Verify stored data with direct DB query
notes:
- No auth needed for MVP — feedback is public and anonymous
- imageIds reference images in the uploads directory; no automatic cleanup
- A future task could add a review/admin dashboard for browsing feedback entries
- Rate limiting could be added later if needed (by sessionId or IP)