Add case_delete: MCP tool + DELETE endpoint + DB helper

Wires a new case-deletion path across the three layers that needed it:

- db.delete_case(case_id) — single SQL DELETE; documents, chunks, and
  qa_results cascade via existing schema FKs, audit_log nullifies.
- cases_tools.case_delete(case_number, remove_files=False) — MCP tool
  wrapper. File tree on disk is kept by default (audit trail); pass
  remove_files=True for a hard delete.
- DELETE /api/cases?case_number=... — FastAPI endpoint taking the case
  number as a QUERY param rather than a path segment. Case numbers
  like "1000/0426" can't be passed through a path parameter because
  FastAPI routing decodes %2F before matching, so a query param is
  the only shape that works for historical data.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-11 16:47:50 +00:00
parent 26d09d648f
commit 8989ad9a9b
4 changed files with 67 additions and 0 deletions

View File

@@ -1135,6 +1135,22 @@ async def api_case_update(case_number: str, req: CaseUpdateRequest):
raise HTTPException(404, result)
@app.delete("/api/cases")
async def api_case_delete(case_number: str, remove_files: bool = False):
"""Delete a case, identified by case_number in the query string.
Uses a query param (not a path segment) because case numbers may contain
characters like `/` that FastAPI path routing cannot capture even when
URL-encoded (%2F). Dependent documents/chunks/qa_results cascade via
FK ON DELETE CASCADE; audit_log rows nullify their case_id.
Pass `remove_files=true` to also rm -rf the on-disk case directory."""
result = await cases_tools.case_delete(case_number, remove_files)
data = json.loads(result)
if not data.get("deleted"):
raise HTTPException(404, data.get("reason", f"תיק {case_number} לא נמצא"))
return data
@app.get("/api/cases/{case_number}/status")
async def api_case_status(case_number: str):
"""Get full workflow status for a case."""