Files
legal-ai/web-ui
Chaim 1e4c5c1518
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 3m16s
Add Paperclip agent activity mirror to case detail page
New "Agents" tab in case detail shows all Paperclip agent comments,
issue status, and agent status for each case — eliminating the need
to switch between Legal-AI and Paperclip UIs.

Backend: 4 new DB query functions in paperclip_client.py (issues,
comments, agents, post_comment) + 2 new API endpoints (GET/POST
/api/cases/{case_number}/agents). Comment posting uses Board API
with DB+wakeup fallback to ensure CEO routing.

Frontend: agents.ts hooks (10s polling), AgentActivityFeed component
(markdown timeline + comment input), AgentStatusWidget (sidebar),
4th tab in case detail page.

Also includes new-company-setup-guide.md documenting the process
for setting up the betterment levy (CMPA) company.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 10:44:42 +00:00
..

עוזר משפטי — Web UI (Next.js rewrite)

The Next.js 16 rewrite of legal-ai.nautilus.marcusgroup.org, currently hosted side-by-side with the legacy vanilla index.html at:

The rewrite talks to the existing FastAPI via proxy rewrites in next.config.ts — no CORS setup, no duplicated backend.

Stack

  • Next.js 16.2.3 (App Router, Turbopack, output: "standalone")
  • React 19.2 · TypeScript · Tailwind v4 · shadcn/ui (radix-nova preset)
  • TanStack Query v5 + TanStack Table v8
  • react-hook-form + zod for mutations
  • react-dropzone for uploads; EventSource for SSE progress
  • Heebo via next/font/google; design tokens in src/app/globals.css

Local development

npm install
npm run dev        # http://localhost:3000
npm run build      # full type check + production build
npm run lint
npm run api:types  # regenerate src/lib/api/types.ts from FastAPI's OpenAPI

API connection

By default the dev server proxies to production FastAPI (https://legal-ai.nautilus.marcusgroup.org). To point at a different backend, set:

export NEXT_PUBLIC_API_ORIGIN=http://localhost:8000
npm run dev

Project layout

src/
├── app/                    # Route segments (App Router)
│   ├── layout.tsx          # Root: Providers + RTL html + fonts
│   ├── page.tsx            # Home: KPIs + status donut + cases table
│   ├── error.tsx           # Route-segment error boundary
│   ├── global-error.tsx    # Root crash fallback
│   ├── not-found.tsx       # 404
│   ├── cases/
│   │   ├── new/            # 3-step create wizard
│   │   └── [caseNumber]/
│   │       ├── page.tsx    # Case detail (tabs + workflow timeline)
│   │       └── compose/    # Research analysis + chair-position editor
│   ├── training/           # Style portrait + corpus + compare (3 tabs)
│   ├── skills/             # Paperclip skills inventory
│   └── diagnostics/        # DB health + failed/stuck docs
├── components/
│   ├── app-shell.tsx       # Header + nav with aria-current
│   ├── cases/              # Home + detail screens
│   ├── compose/            # Research analysis editor
│   ├── documents/          # UploadSheet
│   ├── training/           # Style report / corpus / compare panels
│   ├── wizard/             # Case create wizard + parties-field
│   └── ui/                 # shadcn primitives
├── lib/
│   ├── api/                # Typed hooks per domain (cases, documents, research,
│   │                       #   system, skills, training)
│   ├── schemas/            # zod schemas (case create / update)
│   ├── practice-area.ts    # Multi-tenant axis enum + deriveSubtype()
│   ├── sse.ts              # EventSource wrapper
│   ├── providers.tsx       # QueryClient + Toaster
│   └── utils.ts            # cn()

Smoke test (run after every deploy)

Use any browser at the staging URL. Every step should be doable without console errors and each mutation should produce a visible toast.

1. Home · /

  • Header nav shows 5 items; the current page is underlined in gold
  • 4 KPI cards render real numbers (סה״כ · בהכנה · בכתיבה · מוכנים)
  • Cases table lists existing cases; search filters by case number or title
  • "פיזור סטטוסים" donut renders with a legend
  • "+ תיק חדש" button in the top-left navigates to /cases/new

2. Create case · /cases/new

  • 3-step wizard: פרטי יסוד → צדדים → השלמות
  • Type 1500-25 → appeal_subtype auto-fills to "רישוי ובנייה"
  • Type 8500-25 → subtype auto-fills to "היטל השבחה"
  • Manually pick a different subtype → auto-fill stops
  • Submitting with invalid case number shows a zod field error (no crash)
  • Successful create → toast "תיק חדש נוצר" → router pushes to /cases/{number}

3. Case detail · /cases/[caseNumber]

  • Header shows status badge + gold "ועדת ערר · X" practice-area badge
  • Tabs switch cleanly: סקירה / מסמכים / פעולות
  • Workflow timeline on the right shows the current phase highlighted in gold
  • פעולות tab → "עריכת פרטי תיק" dialog opens; submitting updates the header without full reload (optimistic cache patch)
  • "העלאת מסמכים" sheet opens from the tab row; drag-drop fires a POST and a live progress bar appears via SSE

4. Compose · /cases/[caseNumber]/compose

  • If analysis-and-research.md exists: threshold claims + issues render as collapsible cards
  • Chair-position textarea auto-saves on blur with "✓ נשמר {time}" indicator
  • If 404 (no analysis yet): empty state card renders, no error toast

5. Training · /training

  • Report tab: headline card, 4 KPIs, subject donut, anatomy bars, top-12 signature phrases
  • Corpus tab: table of corpus decisions with a trash icon per row (aria-label present)
  • Deleting a decision refreshes both the corpus table and the report KPIs
  • Compare tab: two Selects, pick 2 different decisions, side-by-side panels + shared/only-A/only-B pattern lists

6. Skills · /skills

  • Card grid of Paperclip skills with sync-status badges (מסונכרן / DB בלבד / לא סונכרן)
  • Chars + file counts render; "לא ידוע" doesn't appear for installed skills

7. Diagnostics · /diagnostics

  • DB status card shows "מחובר" in green
  • Table counts populate for cases / documents / chunks / corpus / patterns
  • Failed + stuck document lists render (empty states OK)
  • Page self-refreshes every 10s — check the network tab for recurring calls

8. Error boundary

  • Visit /cases/NOT-REAL-999-99 → case detail shows an error card with the FastAPI message and "חזרה לרשימת התיקים" button (no white screen)
  • Visit /anything-broken-xyz → custom 404 page with "חזרה לבית" button

9. Keyboard + RTL

  • Tab through the home page — focus rings are gold, visible
  • Wizard progresses via Enter on the "הבא" button
  • Screen reader announces nav items with "עמוד נוכחי" on the active one

Deploy

git push  # → Coolify auto-build on branch ui-rewrite (~90 s)

Known issue: the Gitea → Coolify webhook is not firing at the time of writing. Trigger a manual deploy via the Coolify MCP (mcp__coolify__deploy with app UUID l146g36mtlp0k03vrwkyrgkk) or the Coolify UI until the webhook is fixed.

Phase tracking

See ~/.claude/plans/joyful-marinating-sutton.md for the 7-phase rewrite plan and ~/legal-ai-ui-rewrite/.taskmaster/tasks/tasks.json for the task board.

Phase Scope Status
1 Scaffold + Coolify staging
2 API client + typed hooks + probe
3 Read views (home, case detail, compose)
4 Mutations (wizard, edit, upload+SSE)
4.5 Practice-area integration
5 Secondary screens (training, skills, diagnostics)
6 Polish, a11y, error boundaries, smoke test
7 DNS cutover to production pending

Backend contract

The new UI consumes the existing FastAPI at legal-ai/web/app.py. Key endpoints currently relied on:

Endpoint Hook Used by
GET /api/cases?detail=true useCases home table, KPIs
GET /api/cases/{n}/details useCase case detail
POST /api/cases/create useCreateCase wizard
PUT /api/cases/{n} useUpdateCase inline edit
DELETE /api/cases?case_number=... (MCP only so far) admin cleanup
POST /api/cases/{n}/documents/upload-tagged useUploadDocument upload sheet
GET /api/progress/{task_id} (SSE) useProgress upload progress
GET /api/cases/{n}/research/analysis useResearchAnalysis compose
PATCH .../chair-position useSaveChairPosition chair editor
GET /api/training/style-report useStyleReport training/report tab
GET /api/training/corpus useCorpus training/corpus tab
GET /api/training/compare useCompare training/compare tab
DELETE /api/training/corpus/{id} useDeleteCorpusEntry corpus tab
GET /api/system/diagnostics useDiagnostics diagnostics page
GET /api/admin/skills useSkills skills page

Any new endpoint should get a typed hook in src/lib/api/ — do not reach into fetch from component code.