refactor(cases): צמצום תפריט-סטטוס 17→10 + מקור-אמת יחיד (UI-B1/G2)
All checks were successful
G12 Leak-Guard / leak-guard (pull_request) Successful in 4s
Lint — undefined names / undefined-names (pull_request) Successful in 11s

תפריט הסטטוס-הידני הכיל 17 סטטוסים שמתוכם ~9 דקורציה טהורה — שלבי-ביניים
שאף קוד בפייפליין לא קבע ושום לוגיקה לא הסתעפה לפיהם, עם רשימות כפולות
לא-עקביות ב-6+ קבצים (UI-B1) ו-exported כסטטוס-רפאים (באג agent-audit).

הליבה (10): new, processing, documents_ready, outcome_set, direction_approved,
qa_review, drafted, exported, reviewed, final.

- SSoT חדש web-ui/src/lib/api/case-status.ts (רשימה/שלבים/תוויות/statusLabel);
  כל הצרכנים (badge/changer/timeline/guide/donut/kpi/compose) מייבאים משם.
- statusLabel() מבטיח תווית עברית תמיד — גם לערך-מורשת (נפילה עברית, לא סלאג).
- בקאנד: STATUS_ORDER 10, models.CaseStatus מיושר, set_outcome קובע
  outcome_set/direction_approved (במקום in_progress) כמו endpoint ה-web.
- exported מוקשח אחרי export-DOCX מוצלח (forward-only); widget "נכשל ב-QA"
  עודכן ל-qa_review (הסטטוס שנקבע בפועל בכשל-QA).
- scripts/backfill_case_status_trim.py: מיפוי שורות-מורשת לסטטוס-הליבה הקודם.

Invariants: UI-B1 (מקור-אמת יחיד)  · G2 (אין מסלול מקביל)  · GAP-42 (חלקי).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-17 09:47:13 +00:00
parent 5370ada37c
commit ba542f9c21
16 changed files with 316 additions and 190 deletions

View File

@@ -1,105 +1,48 @@
import { Badge } from "@/components/ui/badge";
import {
FilePlus2, Upload, Loader2, FileCheck, Target,
Lightbulb, Compass, PenLine, SearchCheck, FileText,
FileOutput, CheckCircle2, Award, ShieldCheck, BookOpen,
Microscope, PlayCircle, Hammer, AlertTriangle,
FilePlus2, Loader2, FileCheck, Target,
Compass, SearchCheck, FileText,
FileOutput, CheckCircle2, Award,
} from "lucide-react";
import type { CaseStatus } from "@/lib/api/cases";
import {
STATUS_LABELS, STATUS_DESCRIPTIONS, statusLabel, type CaseStatus,
} from "@/lib/api/case-status";
import type { LucideIcon } from "lucide-react";
const STATUS_LABELS: Record<CaseStatus, string> = {
new: "חדש",
in_progress: "בעבודה",
uploading: "מעלה",
processing: "בעיבוד",
documents_ready: "מסמכים מוכנים",
analyst_verified: "ניתוח אומת",
research_complete: "מחקר הושלם",
outcome_set: "תוצאה נקבעה",
brainstorming: "סיעור מוחות",
direction_approved: "כיוון אושר",
analysis_enriched: "ניתוח הועמק",
ready_for_writing: "מוכן לכתיבה",
drafting: "בכתיבה",
qa_review: "בדיקת איכות",
qa_failed: "בדיקת איכות נכשלה",
drafted: "טיוטה",
exported: "יוצא",
reviewed: "נבדק",
final: "סופי",
};
/* Labels + descriptions come from the SSoT (@/lib/api/case-status).
* Icons + color tones are view-layer concerns and live here, keyed off the
* same 10 core statuses. */
const STATUS_ICONS: Record<CaseStatus, LucideIcon> = {
new: FilePlus2,
in_progress: Hammer,
uploading: Upload,
processing: Loader2,
documents_ready: FileCheck,
analyst_verified: ShieldCheck,
research_complete: BookOpen,
outcome_set: Target,
brainstorming: Lightbulb,
direction_approved: Compass,
analysis_enriched: Microscope,
ready_for_writing: PlayCircle,
drafting: PenLine,
qa_review: SearchCheck,
qa_failed: AlertTriangle,
drafted: FileText,
exported: FileOutput,
reviewed: CheckCircle2,
final: Award,
};
const STATUS_DESCRIPTIONS: Record<CaseStatus, string> = {
new: "התיק נוצר וממתין להעלאת מסמכים",
in_progress: "התיק בעבודה",
uploading: "מסמכים בתהליך העלאה לשרת",
processing: "המערכת מעבדת ומנתחת את המסמכים",
documents_ready: "כל המסמכים עובדו ומוכנים לעבודה",
analyst_verified: "ניתוח ראשוני אומת — ממתין למחקר תקדימים",
research_complete: "מחקר תקדימים הושלם — ממתין לבחירת תוצאה",
outcome_set: "נקבעה תוצאה צפויה לערר",
brainstorming: "ניתוח כיוונים אפשריים להחלטה",
direction_approved: "כיוון ההחלטה אושר — בהעמקת ניתוח",
analysis_enriched: "ניתוח הועמק ופסיקה אומתה — מוכן לכתיבה",
ready_for_writing: "הכל מוכן — ממתין לכותב ההחלטה",
drafting: "טיוטת ההחלטה בתהליך כתיבה",
qa_review: "הטיוטה בבדיקת איכות אוטומטית",
qa_failed: "בדיקת האיכות נכשלה — נדרש תיקון",
drafted: "טיוטה מוכנה לעיון",
exported: "ההחלטה יוצאה לקובץ DOCX",
reviewed: "ההחלטה נבדקה ע\"י היו\"ר",
final: "החלטה סופית — מוכנה להגשה",
};
/* Status color groups:
* intake → new, uploading, processing (muted parchment)
* prep → documents_ready, outcome_set (info blue)
* thinking→ brainstorming, direction_approved (gold)
* writing → drafting, qa_review, drafted (warn amber)
* done → exported, reviewed, final (success green) */
* intake → new, processing (muted parchment / info)
* prep → documents_ready (info blue)
* thinking→ outcome_set, direction_approved (gold)
* writing → qa_review, drafted (warn amber)
* done → exported, reviewed, final (success green) */
const STATUS_TONE: Record<CaseStatus, string> = {
new: "bg-rule-soft text-ink-muted border-rule",
in_progress: "bg-warn-bg text-warn border-warn/40",
uploading: "bg-rule-soft text-ink-muted border-rule",
processing: "bg-info-bg text-info border-info/30",
documents_ready: "bg-info-bg text-info border-info/40",
analyst_verified: "bg-info-bg text-info border-info/40",
research_complete:"bg-info-bg text-info border-info/40",
outcome_set: "bg-info-bg text-info border-info/40",
brainstorming: "bg-gold-wash text-gold-deep border-gold/40",
new: "bg-rule-soft text-ink-muted border-rule",
processing: "bg-info-bg text-info border-info/30",
documents_ready: "bg-info-bg text-info border-info/40",
outcome_set: "bg-gold-wash text-gold-deep border-gold/40",
direction_approved:"bg-gold-wash text-gold-deep border-gold/50",
analysis_enriched:"bg-gold-wash text-gold-deep border-gold/50",
ready_for_writing:"bg-gold-wash text-gold-deep border-gold/50",
drafting: "bg-warn-bg text-warn border-warn/40",
qa_review: "bg-warn-bg text-warn border-warn/40",
qa_failed: "bg-danger-bg text-danger border-danger/40",
drafted: "bg-warn-bg text-warn border-warn/50",
exported: "bg-success-bg text-success border-success/40",
reviewed: "bg-success-bg text-success border-success/50",
final: "bg-success-bg text-success border-success/60 font-semibold",
qa_review: "bg-warn-bg text-warn border-warn/40",
drafted: "bg-warn-bg text-warn border-warn/50",
exported: "bg-success-bg text-success border-success/40",
reviewed: "bg-success-bg text-success border-success/50",
final: "bg-success-bg text-success border-success/60 font-semibold",
};
export function StatusBadge({ status }: { status: CaseStatus }) {
@@ -110,7 +53,7 @@ export function StatusBadge({ status }: { status: CaseStatus }) {
className={`rounded-full px-2.5 py-0.5 text-[0.72rem] font-medium inline-flex items-center gap-1 ${STATUS_TONE[status] ?? ""}`}
>
{Icon && <Icon className="w-3 h-3 shrink-0" />}
{STATUS_LABELS[status] ?? status}
{statusLabel(status)}
</Badge>
);
}