Close 12 audit-driven platform-compliance gaps on a single branch. - D4 dispatch: app/integrations/dispatch_client.py participant `legacyhub`, emits LegacyhubDocumentIndexed + AssetDerivativeReady after the indexing commit (idempotent uuid5), http_inbox route (reindex/tombstone) with audit-based dedupe; docs/dispatch-contract.md. Celery+Redis stays intra-module. - D2 SSO: app/integrations/identity.py validates X-TeamHub-* + role/scope mapper; security.py adds trusted-header enforcement (AUTH_REQUIRE_IDENTITY) and a scope check on /search; docker-compose.teamhub.yml (external teamhub_net + internal db net, api not host-published); RUNBOOK network/firewall section. - Asset standard: SearchHit/Citation carry asset_id/owner_module; buckets renamed teamhub-legacyhub-* (+quarantine/tmp/exports); purge-by-asset_id with legal-hold guard (app/indexing/projection.py); OCR-markdown derivative event. - audit_log model + Alembic 0003 + record_audit on writes (same transaction). - Secret masking: app/common/json_logger.py recursive mask wired into structlog (+ensure_ascii=False); event payloads redacted before persistence. - Service X-API-Key mandatory on ingest endpoints (defence-in-depth). - Port: host API 8000->8050 (collision with SalesHUB/MailHUB resolved), container still listens on 8000. - Config: no plaintext secret defaults; fail-loud in non-dev (no value leak). - Docs drift: README PG 5440, layered-auth note, 5173 removed from CORS; ingest/folder gated by ENABLE_FOLDER_INGEST (410 by default). - ADRs: layers mapping, shared-core extraction, UI locale (RU-first). Tests: 78 passing (ruff, compileall, pytest, tsc, vite build, compose config). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
141 lines
6.3 KiB
Markdown
141 lines
6.3 KiB
Markdown
# LegacyHUB · Frontend
|
||
|
||
React + TypeScript + Vite frontend for **LegacyHUB**, the legacy-document
|
||
indexing and AI search module of the **TeamHUB Suite**.
|
||
|
||
This package ships:
|
||
|
||
- the application shell (collapsible sidebar, top toolbar, breadcrumb nav,
|
||
global ⌘K command palette, light/dark theme, notification center,
|
||
user/profile menu);
|
||
- nine pages: Dashboard, Documents, Ingestion Jobs, Search, Document Viewer,
|
||
Tables & Figures, Quality Control, System Health, Settings;
|
||
- a hybrid AI search workspace with semantic / lexical / hybrid modes, live
|
||
suggestions, expandable filters, highlighted matches, reranker score
|
||
visualization and side-by-side chunk preview;
|
||
- typed service layer (`src/services/*`) with Axios + TanStack Query and a
|
||
mock data backend you can toggle off when the backend is reachable.
|
||
|
||
## Stack
|
||
|
||
| Concern | Library |
|
||
|----------------|-----------------------------------------|
|
||
| Bundler | Vite 5 |
|
||
| Language | TypeScript 5.6 |
|
||
| UI | React 18 |
|
||
| Styling | TailwindCSS 3 + custom design tokens |
|
||
| Components | shadcn/ui primitives (Radix + cva) |
|
||
| Animation | Framer Motion |
|
||
| Charts | Recharts |
|
||
| Server state | TanStack Query |
|
||
| Client state | Zustand |
|
||
| Routing | React Router v6 |
|
||
| HTTP | Axios |
|
||
| Icons | lucide-react |
|
||
| Toasts | sonner |
|
||
| Virtualization | @tanstack/react-virtual |
|
||
|
||
## Quick start
|
||
|
||
```bash
|
||
cd frontend
|
||
cp .env.example .env # VITE_USE_MOCK=true for offline UI development
|
||
npm install
|
||
npm run dev # http://localhost:5273
|
||
```
|
||
|
||
When the FastAPI backend is running, set `VITE_USE_MOCK=false` (or simply
|
||
`VITE_API_BASE_URL=/api/v1` and let the Vite dev proxy at port 8050 handle
|
||
routing). All API calls are isolated through `src/services/*.ts`.
|
||
|
||
## Architecture
|
||
|
||
```
|
||
frontend/src/
|
||
app/ RouterProvider, QueryClient, TooltipProvider, theme bootstrap
|
||
pages/ One file per route — composed of widgets + primitives
|
||
layouts/ AppShell, Sidebar (collapsible), Topbar, Breadcrumbs, ⌘K palette
|
||
widgets/ Domain-specific composite components (KpiCard, Charts, Result cards,
|
||
PdfPreviewPane, ChunkPreview, ServiceHealthCard, Timeline)
|
||
components/
|
||
ui/ shadcn-style primitives — Button, Card, Tabs, Dialog, Select,
|
||
Tooltip, Popover, ScrollArea, Command, Skeleton, Progress, …
|
||
common/ Domain primitives — Logo, StatusChip, ConfidenceMeter,
|
||
QualityFlag, BlockTypeIcon, Highlight, EmptyState, PageHeader,
|
||
ThemeToggle
|
||
services/ Typed API layer (Axios) + TanStack hooks (one file per resource)
|
||
mock/ Deterministic mock data + simulated latency
|
||
hooks/ Wrappers around services exposing TanStack Query hooks
|
||
stores/ Zustand stores: uiStore (theme, sidebar, palette), searchStore
|
||
styles/ Tailwind layer + design tokens (HSL CSS variables)
|
||
lib/ cn(), formatBytes/Number/Percent/Duration, relativeTime, etc.
|
||
```
|
||
|
||
### Design system
|
||
|
||
- **Palette** — white / light-gray surfaces with a single restrained green
|
||
accent (`--primary: 158 64% 32%`) matching QMS Hub.
|
||
- **Surfaces** — three tiers: sunken (page background), default card, raised
|
||
(popovers / dialogs). Glass surfaces via `backdrop-blur` for the topbar.
|
||
- **Corners** — `--radius: 14px` produces soft, premium edges across every
|
||
component.
|
||
- **Shadows** — `shadow-soft` and `shadow-elevated` only. No harsh drop
|
||
shadows.
|
||
- **Typography** — Inter variable, optical sizes, tabular numbers for data
|
||
cells, JetBrains Mono for IDs / paths / hashes.
|
||
- **Motion** — Framer Motion `layoutId` for the active sidebar pill,
|
||
`fade-in-up` for KPI cards, animated tabs and result expansion.
|
||
- **States** — skeleton shimmer instead of spinners wherever possible.
|
||
|
||
### Key flows
|
||
|
||
- **Hybrid search (`/search`)** — Debounced query → TanStack hook hits the
|
||
backend (or mock). Results are virtualized, scored, optionally reranked.
|
||
Picking a result hydrates a side-by-side ChunkPreview with the highlighted
|
||
excerpt, a page thumbnail, citation metadata, and quality flags.
|
||
- **Documents (`/documents`)** — Virtualized table (TanStack Virtual)
|
||
supports thousands of rows. Filters: status, OCR threshold, "needs review",
|
||
free-text search. Clicking a row opens the viewer.
|
||
- **Document Viewer (`/viewer/:id`)** — Split layout. Left pane: PDF page
|
||
thumbnails + synchronized large page preview with highlighted OCR blocks.
|
||
Right pane: extracted chunks / tables / figures / metadata, kept in lock-step
|
||
with the active page. Below: full pipeline timeline.
|
||
- **Ingestion (`/ingestion`)** — Submit a folder path with `recursive` /
|
||
`force` toggles → optimistic queue, run history table with live progress
|
||
bars.
|
||
- **Quality control (`/quality`)** — Three review queues (low confidence,
|
||
handwriting, failed extraction) with reviewer actions and an audit log.
|
||
|
||
### Mock vs real backend
|
||
|
||
`src/services/apiClient.ts` exports a constant `USE_MOCK`. When `true`, every
|
||
service module short-circuits to `src/services/mock/mockData.ts` which
|
||
generates deterministic, seeded data: 280 documents, dashboards, ingestion
|
||
runs, search results, health and queue snapshots, and per-document detail
|
||
(pages, chunks, tables, figures, timeline events).
|
||
|
||
This lets the frontend be developed and demoed without the Python services
|
||
running.
|
||
|
||
### Accessibility
|
||
|
||
- All interactive elements use `ring-focus` (visible 2px primary ring).
|
||
- Sidebar nav exposes tooltips when collapsed.
|
||
- Keyboard: `Ctrl/Cmd + K` opens the global command palette.
|
||
|
||
### Responsive layout
|
||
|
||
- ≥ 1280 px (xl, ultrawide) — three-column dashboards, side-by-side search.
|
||
- 1024–1280 px (laptop) — two-column dashboards, stacked search.
|
||
- < 1024 px — single column; sidebar collapses to icons only.
|
||
|
||
## Scripts
|
||
|
||
```bash
|
||
npm run dev # Vite dev server with /api proxy → :8050
|
||
npm run build # type-check + production bundle
|
||
npm run preview # preview build
|
||
npm run lint
|
||
npm run format
|
||
```
|