import { Elysia } from 'elysia'; import type { ReviewDiagnosisRequest } from '@zeavis/shared'; import { isDiseaseSlug } from '@zeavis/shared'; import { and, desc, eq } from 'drizzle-orm'; import { createDbClient } from '../db/client'; import { diagnoses, expertReviews } from '../db/schema'; import { badRequest, forbidden, notFound, serviceUnavailable, unauthorized } from '../lib/http-errors'; import { getCurrentUser } from '../lib/auth'; import { loadDiagnosisRecord } from './diagnoses'; type DiagnosisRecord = Awaited>; function isDiagnosisRecordOrNull(record: unknown): record is DiagnosisRecord { return record !== null; } export const expertRoutes = new Elysia({ prefix: '/api/v1/expert' }) .get('/reviews', async ({ request }) => { const user = await getCurrentUser(request.headers.get('cookie'), request.headers); if (!user) return unauthorized('Authentication required'); if (user.role !== 'expert') return forbidden('Expert role required'); try { const db = createDbClient(); const rows = await db .select({ id: diagnoses.id }) .from(diagnoses) .where(eq(diagnoses.status, 'needs_review')) .orderBy(desc(diagnoses.createdAt)) .limit(50); const records = await Promise.all(rows.map((row) => loadDiagnosisRecord(row.id, null, true))); return records.filter(isDiagnosisRecordOrNull); } catch (error) { return serviceUnavailable('Database unavailable'); } }) .post('/reviews/:diagnosisId', async ({ params, body, request }) => { const user = await getCurrentUser(request.headers.get('cookie'), request.headers); if (!user) return unauthorized('Authentication required'); if (user.role !== 'expert') return forbidden('Expert role required'); const req = body as Partial | undefined; if (!req || (req.verdict !== 'verified' && req.verdict !== 'corrected')) { return badRequest('Verdict must be verified or corrected'); } const notes = typeof req.notes === 'string' ? req.notes.trim() : ''; if (!notes) return badRequest('Review notes are required'); if (req.verdict === 'corrected') { if (!req.correctedDiseaseSlug || !isDiseaseSlug(req.correctedDiseaseSlug)) { return badRequest('Corrected disease slug is required for corrected reviews'); } } try { const db = createDbClient(); const existing = await db .select() .from(diagnoses) .where(eq(diagnoses.id, params.diagnosisId)) .limit(1); const diagnosis = existing[0]; if (!diagnosis) return notFound('Diagnosis not found'); const verdict = req.verdict as 'verified' | 'corrected'; const correctedSlug = verdict === 'corrected' ? req.correctedDiseaseSlug : null; // Wrap update and insert in a transaction for atomicity const result = await db.transaction(async (tx) => { // Perform conditional update first to determine if this review should proceed const updated = await tx .update(diagnoses) .set({ status: verdict === 'corrected' ? 'expert_corrected' : 'expert_verified', predictedDiseaseSlug: verdict === 'corrected' ? correctedSlug : diagnosis.predictedDiseaseSlug, updatedAt: new Date(), }) .where(and(eq(diagnoses.id, diagnosis.id), eq(diagnoses.status, 'needs_review'))) .returning(); if (updated.length === 0) { throw new Error('DIAGNOSIS_NOT_PENDING_REVIEW'); } // Only insert expert review after successful update const reviewValues = { diagnosisId: diagnosis.id, expertId: user.id, verdict, correctedDiseaseSlug: correctedSlug, notes, }; await tx.insert(expertReviews).values(reviewValues); return updated[0]; }); return await loadDiagnosisRecord(diagnosis.id, null, true); } catch (error) { if (error instanceof Error && error.message === 'DIAGNOSIS_NOT_PENDING_REVIEW') { return badRequest('Diagnosis is not pending review'); } return serviceUnavailable('Database unavailable'); } });