feat: add POST /api/cases/parties to store UYAP taraf bilgileri

The UYAP extension now captures the davaci/davali/sanik + vekil data
from the "Taraf Bilgileri" tab and sends it once per case. This
endpoint finds/creates the matching case by title (same lookup used
by registerLocalDocument, now shared via lib/caseLookup.ts) and stores
it in a new cases.parties column - a much more reliable source for
the case detail screen's "Taraflar" info than the AI's own guess from
OCR'd document text.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
mstfyldz
2026-08-09 19:29:53 +03:00
co-authored by Claude Sonnet 5
parent 9f5c5c1e45
commit 99d4d770d5
4 changed files with 59 additions and 22 deletions
+31
View File
@@ -2,6 +2,7 @@ import { Response } from 'express';
import { supabase } from '../lib/supabase';
import { AuthenticatedRequest } from '../middleware/auth';
import { runDocumentAnalysis } from './document.controller';
import { findOrCreateCaseByTitle } from '../lib/caseLookup';
export const createCase = async (req: AuthenticatedRequest, res: Response) => {
try {
@@ -72,6 +73,36 @@ export const summarizeCase = async (req: AuthenticatedRequest, res: Response) =>
}
};
// UYAP Evrak İndirici eklentisinin "Taraf Bilgileri" sekmesinden yakaladığı
// davacı/davalı/sanık + vekil bilgisini kaydeder. AI'nin OCR metninden tahmin
// ettiği "Taraflar" alanından çok daha güvenilir — doğrudan UYAP'ın yapılandırılmış
// verisi. case_title ile eşleştirme registerLocalDocument ile aynı mantık.
export const updateCaseParties = async (req: AuthenticatedRequest, res: Response) => {
try {
const userId = req.user?.id;
const { case_title, parties } = req.body || {};
if (!case_title || !Array.isArray(parties) || parties.length === 0) {
return res.status(400).json({ error: 'case_title ve parties zorunludur.' });
}
const caseId = await findOrCreateCaseByTitle(userId as string, case_title);
const { data, error } = await supabase
.from('cases')
.update({ parties })
.eq('id', caseId)
.select('id, title, parties')
.single();
if (error) throw error;
res.json({ case: data });
} catch (error: any) {
console.error('Update Case Parties Error:', error);
res.status(500).json({ error: error.message || 'Internal Server Error' });
}
};
export const deleteCase = async (req: AuthenticatedRequest, res: Response) => {
try {
const { caseId } = req.params;
+2 -21
View File
@@ -3,6 +3,7 @@ import { supabase } from '../lib/supabase';
import { AuthenticatedRequest } from '../middleware/auth';
import * as officeParser from 'officeparser';
import Tesseract from 'tesseract.js';
import { findOrCreateCaseByTitle } from '../lib/caseLookup';
const heicConvert = require('heic-convert');
const ANALYSIS_SYSTEM_PROMPT = `
@@ -65,27 +66,7 @@ export const registerLocalDocument = async (req: AuthenticatedRequest, res: Resp
return res.status(400).json({ error: 'case_title, filename ve extracted_text zorunludur.' });
}
// Dava başlığına göre mevcut case'i bul (case-insensitive), yoksa oluştur.
const { data: existing } = await supabase
.from('cases')
.select('id, title')
.eq('user_id', userId)
.ilike('title', case_title)
.limit(1)
.maybeSingle();
let caseId: string;
if (existing) {
caseId = existing.id;
} else {
const { data: newCase, error: caseError } = await supabase
.from('cases')
.insert([{ title: String(case_title).slice(0, 200), user_id: userId }])
.select('id')
.single();
if (caseError) throw caseError;
caseId = newCase.id;
}
const caseId = await findOrCreateCaseByTitle(userId as string, case_title);
const { data: documentRecord, error: docError } = await supabase
.from('documents')
+24
View File
@@ -0,0 +1,24 @@
import { supabase } from './supabase';
// UYAP'tan gelen dava başlığına göre (case-insensitive) kullanıcının mevcut case'ini
// bulur, yoksa oluşturur. registerLocalDocument ve updateCaseParties'in ortak kullandığı
// eşleştirme mantığı — ikisi de aynı case_title string'iyle çalışıyor.
export async function findOrCreateCaseByTitle(userId: string, caseTitle: string): Promise<string> {
const { data: existing } = await supabase
.from('cases')
.select('id')
.eq('user_id', userId)
.ilike('title', caseTitle)
.limit(1)
.maybeSingle();
if (existing) return existing.id;
const { data: newCase, error } = await supabase
.from('cases')
.insert([{ title: String(caseTitle).slice(0, 200), user_id: userId }])
.select('id')
.single();
if (error) throw error;
return newCase.id;
}
+2 -1
View File
@@ -1,11 +1,12 @@
import { Router } from 'express';
import { requireAuth } from '../middleware/auth';
import { createCase, deleteCase, summarizeCase } from '../controllers/case.controller';
import { createCase, deleteCase, summarizeCase, updateCaseParties } from '../controllers/case.controller';
const router = Router();
router.post('/', requireAuth, createCase);
router.delete('/:caseId', requireAuth, deleteCase);
router.post('/:caseId/summarize', requireAuth, summarizeCase);
router.post('/parties', requireAuth, updateCaseParties);
export default router;