generateDraft now inserts into a new drafts table (case_id, content,
petition_type, template_id) so drafts survive navigating away, and
show up in both the "Dilekçelerim" list and the originating case's own
"Dilekçeler" section. Read/update/delete go straight through Supabase
from the frontend (same pattern as events/clients).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The draft prompt didn't say anything about output format, so the model
would sometimes emit **bold**/## headers like it does elsewhere -
wrong for a document meant to go straight into a court filing. Now
explicitly instructed to use plain text with conventional Turkish
petition section labels (AÇIKLAMALAR:, SONUÇ VE İSTEM: etc.) instead.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
chatMessage() was auto-generating and overwriting cases.title from the
first chat message for ANY case_id, including real UYAP-imported dava
dosyaları (kind='case') — not just the chat-only "Yeni Sohbet" threads
(kind='chat') this was built for. Asking a real case a single question
in Sohbet silently destroyed its court-derived title. Now gated on
kind === 'chat'.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Belge Şablonları uploads now also get extracted_text (same OCR/office
pipeline as documents), and a new POST /api/drafting/generate builds
a real AI draft from the case's actual data (title, UYAP parties,
latest Dosya Özeti) — if the lawyer picks one of their own templates,
its extracted text is passed as a style/format reference only (the
prompt explicitly forbids copying the template's old case facts).
Dilekçe Hazırlama no longer fakes a draft with setTimeout.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
summarizeCase now produces a full Markdown narrative report (Olayın
Özeti, Yargılama Süreci ve Kararlar, Taraf İddia/Savunmaları, Önemli
Bulgular ve Belgeler, Sonuç) instead of short structured fields - the
iddianame pre-analysis (when found) still runs first and is fed in as
context. The raw AI text is stored as {ozet: string} rather than
JSON-parsed, since asking the model to escape a multi-paragraph report
inside JSON was fragile.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- summarizeCase: if an iddianame is among the case's documents, run a
narrow first-pass analysis on it alone (isnatEdilenSuc, iddiaOzeti,
onemliTarihler), then feed that as context into the general
case-wide evaluation instead of treating every document equally.
- ANALYSIS_SYSTEM_PROMPT no longer asks the AI to guess "taraflar" -
that now comes from real UYAP data (cases.parties) instead.
- Removed the hardcoded RunPod proxy URL fallback from every call
site (document/chat/precedent controllers + lib/openai.ts) - it was
a real infra endpoint checked into source. New lib/aiConfig.ts
throws if RUNPOD_API_BASE_URL isn't set rather than silently
falling back to it.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Belge Şablonları now stores real files: POST /api/templates/upload
(multer -> Supabase Storage under templates/<user>/, then a templates
row), GET /api/templates/:id/download-url (short-lived signed URL),
and DELETE /api/templates/:id. Mounted at /api/templates.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
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>
POST /api/cases/:caseId/summarize combines extracted text from all of
a case's documents and runs the existing AI analysis prompt, storing
the result as a case-level analysis (document_id: null). Powers the
"Özet Hazırla" button on the case detail screen.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
New chat threads created from the Sohbet screen were creating rows in
the same cases table that Dava Dosyaları lists, so every new chat
showed up there too. createCase now accepts an optional kind
('case'|'chat', default 'case') so chat-only threads can be excluded.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Accepts pre-extracted text (no raw file) from the AyrisLegal Electron
app's local OCR pipeline, matches/creates a case by title, and runs
the existing AI analysis flow. Also fixes a bug in uploadDocument:
officeparser@7.x's parseOffice() now returns a result object with
.toText() instead of a plain string, which was breaking PDF/DOCX
manual uploads.
Takes the user's described situation plus the top search results and
asks the AI model for a short legal assessment. Auth-protected since
it's a paid AI call.
POST /api/cases lets the frontend actually create a new dava dosyası
(no working "Yeni Dosya" flow existed before). chatMessage now
generates a short title from a case's first message (like Claude/
ChatGPT auto-titling) and renames the case, returned as `newTitle`.
Chat panel's trash icon should remove the whole case (not just clear
its chat history) — documents/analyses/chat_messages cascade-delete
via the existing ON DELETE CASCADE foreign keys.
Frontend's chat history trash icon was calling this endpoint but it
didn't exist yet, causing a JSON-parse error on the default 404 page.
Also renames the LegalOS health-check message to AyrisLegal.
requireAuth treated every chat caseId as a real cases row and rejected
"general" (the no-file chat sentinel) with 403. general chat now skips
the ownership check and is answered without touching chat_messages,
since that table's case_id is a NOT NULL FK to cases.