2 Commits

Author SHA1 Message Date
82ded005a4 fix: add days>0 guard and limit param to stale/feedback endpoints
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 8s
2026-05-16 17:38:34 +00:00
c7ed1110f8 feat: add /api/cases/stale and /api/chair-feedback/weekly-summary endpoints
GET /api/cases/stale?days=N — returns cases not updated in N days (default 3)
  that are not in 'final' or 'new' status, with days_stale count.
GET /api/chair-feedback/weekly-summary?days=N — returns chair feedback from
  the last N days (default 7) as a Hebrew bullet-list summary for CEO agent.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-16 17:36:12 +00:00

View File

@@ -1135,6 +1135,36 @@ async def list_cases(
return result
@app.get("/api/cases/stale")
async def api_stale_cases(days: int = 3):
"""Return cases that haven't been updated in N days and are not in 'final' or 'new' status."""
if days <= 0:
return {"cases": [], "total": 0}
pool = await db.get_pool()
async with pool.acquire() as conn:
rows = await conn.fetch(
"""
SELECT case_number, title, status,
EXTRACT(DAY FROM (now() - updated_at))::int AS days_stale
FROM cases
WHERE status NOT IN ('final', 'new')
AND updated_at < now() - make_interval(days => $1)
ORDER BY updated_at ASC -- oldest stale first (longest overdue = highest priority)
""",
days,
)
cases = [
{
"case_number": r["case_number"],
"title": r["title"],
"status": r["status"],
"days_stale": r["days_stale"],
}
for r in rows
]
return {"cases": cases, "total": len(cases)}
@app.post("/api/cases/{case_number}/archive")
async def api_archive_case(case_number: str):
"""Move a case to the archive. Also archives the matching Paperclip project."""
@@ -4015,6 +4045,34 @@ async def api_resolve_feedback(feedback_id: str, body: dict):
return {"status": "resolved"}
@app.get("/api/chair-feedback/weekly-summary")
async def api_chair_feedback_weekly_summary(days: int = 7, limit: int = 100):
"""Return chair feedback from the last N days as a text summary for the CEO agent."""
if days <= 0:
return {"summary": "", "entry_count": 0}
pool = await db.get_pool()
async with pool.acquire() as conn:
rows = await conn.fetch(
"""
SELECT cf.feedback_text, c.case_number, c.title
FROM chair_feedback cf
LEFT JOIN cases c ON c.id = cf.case_id
WHERE cf.created_at >= now() - make_interval(days => $1)
ORDER BY cf.created_at DESC
LIMIT $2
""",
days,
limit,
)
if not rows:
return {"summary": "", "entry_count": 0}
lines = [
f"- תיק {r['case_number'] or ''} ({r['title'] or ''}): {r['feedback_text']}"
for r in rows
]
return {"summary": "\n".join(lines), "entry_count": len(rows)}
# ── Background Processing ─────────────────────────────────────────