Extends the system spec beyond the core pipeline to the 8 surfaces outside it: - X6 UI↔API contract + design rules (INV-UI1..6) - X7 Paperclip client & connection params (INV-INT4..8) - X8 field-population & extraction provenance (INV-FP1..5) - X9 MCP tool contract — 71 tools (INV-TOOL1..6) - X10 deploy/env/secrets (INV-ENV1..5) - ui-audit.md — page-by-page UI audit (13 pages) - 02-data-model: derived-entity invariants (INV-DM4..6) - X4-agents: tool-grant map + INV-AG3 - gap-audit: GAP-24..62 → FU-9..15; cycle-1 (FU-1..8b) marked done - constitution §7 + README index (X1..X10) Planning/spec artifacts only — no application code. All engineering invariants backed by ≥3 sources; every finding carries verified file:line. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
11 KiB
X6 — חוזה UI↔API וכללי-עיצוב הממשק (UI↔API Contract & Design Rules)
קובץ-תחום זה כפוף ל-חוקת המערכת והוא ה-deep-dive על הממשק (web-ui) וחוזה ה-API בינו לבקאנד — שלא היה מכוסה בספ עד כה. הוא מגדיר: (א) חוזה-הקשר פרונט↔בק (OpenAPI כ-SSoT, מודלי-תשובה, envelope, SSE, טיפול-שגיאות); (ב) כללי-עיצוב הממשק — מקור-אמת יחיד ל-enums/תוויות, helpers משותפים, וחוזה-טופס לכל סוג-מסמך. הממצאים בפועל מתועדים ב-ui-audit.md.
שני סוגי invariant כאן. UI1–UI5 הם הנדסיים (חוזה-API/קליינט כללי — ≥3 מקורות + סטטוס). UI6 (חוזה-טופס) הוא פרויקטלי-תפעולי, נגזר מ-X8, ומשרת G9.
1. ארכיטקטורה קיימת
- web-ui — Next.js 16 + TS + Tailwind v4 + shadcn + TanStack Query. 13 דפים (ראה ui-audit.md).
- Proxy — next.config.ts:
/api/*→NEXT_PUBLIC_API_ORIGIN(ברירת-מחדלhttp://127.0.0.1:8000);/openapi.json→ schema של ה-FastAPI. - לקוח — client.ts:
apiRequest<T>+ApiError+makeQueryClient. 18 מודולי-API. - טיפוסים — types.ts (auto-gen
openapi-typescript, 124 operations).npm run api:types. - SSE — sse.ts:
openSSE(progress של העלאות/עיבוד). - בקאנד — web/app.py: 143 endpoints, מונוליטי, ~60% ללא Pydantic response model.
2. Invariants של התחום
INV-UI1: ה-OpenAPI schema הוא ה-SSoT לחוזה — טיפוסי-לקוח נגזרים, לא ידניים-סוטים
כלל: חוזה ה-API מוגדר פעם אחת ב-OpenAPI (שמופק מהבקאנד); טיפוסי-ה-frontend נגזרים ממנו
(openapi-typescript), ואינם מתוחזקים ידנית במקביל. אין "טיפוס-מראה" מקומי שמשכפל endpoint וסוטה ממנו.
מופע של G2 (מקור-אמת יחיד).
מקורות: OpenAPI Specification 3.1 (single contract / source of truth; JSON-Schema 2020-12)
(https://spec.openapis.org/oas/latest.html) · Pact — consumer-driven contract testing
(https://docs.pact.io/) · Speakeasy — Pact vs OpenAPI (provider-driven SSoT)
(https://www.speakeasy.com/blog/pact-vs-openapi) | סטטוס: verified
אכיפה: npm run api:types ב-CI; איסור טיפוסי-מראה ידניים. כיום אין — ה-frontend מתחזק טיפוסים ידניים.
הפרה ידועה: cases.ts:1-9 מתעד מפורשות שה-/api/cases מחזיר unknown
ולכן מוחזק טיפוס CaseDetail ידני; PracticeArea מוגדר ב-3 מקומות עם ערכים שונים (ui-audit.md, gap-audit GAP-30/31).
INV-UI2: לכל endpoint נצרך — response model מפורש (חוזה-שלמות API)
כלל: כל endpoint שה-UI צורך נושא response model מפורש (Pydantic), כך ש-OpenAPI מפיק טיפוס אמיתי
(לא unknown/object). זהו פאֶט של G4 (שלמות-חוזה לפני צריכה).
מקורות: OpenAPI 3.1 (schema objects) · Zalando RESTful API Guidelines (explicit schemas)
(https://opensource.zalando.com/restful-api-guidelines/) · FastAPI Response Model docs
(https://fastapi.tiangolo.com/tutorial/response-model/) | סטטוס: verified
אכיפה: linter/CI שמסמן endpoint נצרך ללא response_model. כיום אין — ~60% מהendpoints ללא מודל.
הפרה ידועה: רוב ה-endpoints ב-app.py מחזירים dict חופשי → unknown ב-types.ts (gap-audit GAP-30).
INV-UI3: envelope-תשובה ושגיאה עקבי על-פני ה-API
כלל: כל ה-endpoints חולקים מבנה-תשובה ומבנה-שגיאה אחיד (לא string-לפעמים-JSON-לפעמים). שגיאות
לפי תבנית סטנדרטית (Problem Details). מופע של G2.
מקורות: RFC 9457 — Problem Details for HTTP APIs
(https://www.rfc-editor.org/rfc/rfc9457) · Zalando RESTful API Guidelines (consistent responses) ·
Microsoft REST API Guidelines (error structure)
(https://github.com/microsoft/api-guidelines) | סטטוס: verified
אכיפה: envelope משותף ב-app.py + handler-שגיאות גלובלי. כיום אין — מעורב string/JSON/{error}/{detail}.
הפרה ידועה: search.py מחזיר "לא נמצאו תוצאות." או JSON; חלק מהכלים {error:...}, חלק raise (gap-audit GAP-32, X9 INV-TOOL1).
INV-UI4: אין בליעת-שגיאה ב-UI
כלל: כל מצב-שגיאה (fetch/mutation) מוצג או מטופל מפורשות — error boundary ו/או טיפול ב-error
של useQuery/useMutation. אין כשל שקט שמשאיר את המשתמש בלי משוב. תואם כלל "אין בליעה שקטה"
(חוקה §6).
מקורות: React docs — Error Boundaries
(https://react.dev/reference/react/Component#catching-rendering-errors-with-an-error-boundary) ·
TanStack Query — Error handling (https://tanstack.com/query/latest/docs/framework/react/guides/query-functions#handling-and-throwing-errors) ·
Nielsen Norman Group — Error-Message Guidelines (https://www.nngroup.com/articles/error-message-guidelines/) | סטטוס: verified
אכיפה: error boundary ברמת-האפליקציה + רכיב-שגיאה משותף; code-review. כיום חלקי — חלק מהדפים אינם
מטפלים ב-error; כרטיסי-שגיאה משוכפלים ולא-עקביים.
הפרה ידועה: ui-audit.md — כרטיס-שגיאה משוכפל ×3, fallback של SSE שמסתיר כישלון כ-"completed" (gap-audit GAP-32/33).
INV-UI5: חוזה-SSE/progress עם terminal states מוגדרים
כלל: ערוץ ה-progress (SSE) נושא terminal states מפורשים (completed/failed/timeout). אין הנחת-השלמה
שקטה על timeout; אי-התאמות-TTL (frontend↔backend) נמנעות. נקשר ל-freshness (G6).
מקורות: WHATWG HTML — Server-Sent Events / EventSource (https://html.spec.whatwg.org/multipage/server-sent-events.html) ·
MDN — Using server-sent events (https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events) ·
TanStack Query — Important Defaults (staleTime/refetch) (https://tanstack.com/query/latest/docs/framework/react/guides/important-defaults) | סטטוס: verified
אכיפה: סכמת-אירוע SSE עם terminal state מפורש; יישור TTL. כיום: fallback של 10ש' מניח completed.
הפרה ידועה: documents.ts:226-232 — timeout→{status:"completed"}; TTL 5ש' front מול 300ש' redis (gap-audit GAP-33).
INV-UI6: חוזה-טופס מוצהר לכל סוג-מסמך + שיקוף מקור-המילוי
כלל: לכל סוג-מסמך (מסמך-תיק / פסיקה חיצונית / החלטה פנימית) יש חוזה-טופס מוצהר — אילו שדות,
חובה/רשות/אוטו/pending/editable — נגזר מ-X8; וה-UI משקף את מקור-המילוי
(מסמן מה חולץ אוטומטית/ע"י-Opus מול מה שהיו"ר הזין), כדי שהיו"ר ידע מה לאמת. מופע של
G9 (שקיפות-מקור). invariant פרויקטלי-תפעולי.
מקור-סמכות: X8-field-provenance.md (טבלת-ה-provenance); feedback היו"ר.
אכיפה: רכיב-טופס נגזר-X8 + אינדיקציית "מולא-ע"י-Opus"/"ממתין"/searchable. כיום אין — שדות-Opus
מוצגים כשדות-עריכה רגילים ללא סימון.
הפרה ידועה: precedents/[id]/page.tsx — summary/headnote/key_quote ללא חיווי-מקור; אין חיווי searchable (gap-audit GAP-36).
3. כללי-עיצוב (Design Rules) — נגזרים מה-invariants
- SSoT ל-enums/תוויות/tones: כל enum (CaseStatus, PracticeArea, AppealSubtype, DocType, outcome) + תוויותיו + צבעיו מוגדרים פעם אחת ונצרכים מיבוא — לא משוכפלים בין דפים/רכיבים (מופע UI1/G2).
- helpers משותפים: פירמוט-תאריך, builder ל-FormData (העלאות), רכיב-שגיאה, query-config (intervals) — משותפים, לא מועתקים.
- חוזי-טופס: ראה INV-UI6 (X8).
הממצאים הקונקרטיים (כפילויות, הגדרות-שגויות, redundancy) ב-ui-audit.md; התיקון — FU-10.
4. הפניות-אחיות
- ui-audit.md — audit דף-אחר-דף (13 דפים) בתבנית-ה-gap.
- X8-field-provenance.md — מקור-מילוי-שדות (בסיס ל-INV-UI6).
- X7-paperclip-client-params.md — חוזה-ה-API שהפלאגין צורך.
- X9-mcp-tool-contract.md — חוזה-envelope מקביל בכלי-ה-MCP.
- 00-constitution.md — G2, G4, G9, כלל "אין בליעה שקטה" (§6).
- web-ui/next.config.ts, client.ts, types.ts, sse.ts.