04. Frontend Deep Dive¶
App structure¶
| Piece | Detail |
|---|---|
| Framework | React 19 + TypeScript strict |
| Bundler | Vite 8, base: '/browser-rag/' |
| Routing | TanStack Router file routes + generated routeTree.gen.ts |
| Server state | TanStack Query |
| Styling | Tailwind CSS v4, shadcn/ui (Radix), Lucide icons |
| Fonts | Fraunces + Source Sans 3 variable fonts |
Entrypoint: src/main.tsx → ThemeProvider → SystemInitProvider → App (QueryClientProvider + RouterProvider).
Routing and layout¶
| Route | File | Purpose |
|---|---|---|
/ |
src/routes/index.tsx |
Chat + citations + debug |
/documents |
src/routes/documents.tsx |
Upload, list, retry, chunk explorer |
/history |
src/routes/history.tsx |
Past Q&A |
/projects |
src/routes/projects.tsx |
Project CRUD |
/settings |
src/routes/settings.tsx |
Models, chunk/hybrid, diagnostics, backup |
__root |
src/routes/__root.tsx |
AppShell |
Basepath /browser-rag matches Vite base and GitHub Pages project site layout.
Layout components: app-shell, sidebar, top-bar, project-switcher.
State management¶
graph TD
classDef default fill:#1e293b,stroke:#38bdf8,stroke-width:2px,color:#f8fafc
classDef highlight fill:#065f46,stroke:#34d399,stroke-width:2px,color:#f0fdf4
LS["localStorage preferences"]
Ctx["SystemInitProvider"]:::highlight
Hooks["useGemma4 / useWebLLM / useLfm2 / useQwen35"]
TQ["TanStack Query caches"]
Local["Chat message React state"]
DB["PGlite projects/docs/history"]
LS --> Ctx
Ctx --> Hooks
Ctx --> DB
TQ --> DB
Local --> Ctx
linkStyle default stroke:#64748b,stroke-width:2px
SystemInitProvider owns active project, preference updates, LLM/embedding load progress, and exposes engine handles to the chat orchestrator.
Prefs quirk (Confirmed): defaults use llmModelId: 'qwen-3.5-0.8b' / llmVariantId: 'transformers-js', which do not match catalog ids (qwen35-0.8b). getLLMVariant falls back when unknown.
API and streaming clients¶
No REST client. UI imports service modules and consumes async generators:
generateRAGAnswer→ chat event loopindexDocument→ upload/retry mutationsexportDb/importDb→ settings backup UI
Markdown rendering: marked.parse into dangerouslySetInnerHTML on chat and history.
Component system¶
- shadcn primitives under
src/components/ui/ - Domain:
retrieval-debug-panel,upload-panel,chunk-explorer,logo - Theme via
theme-provider
Chat / artifact / debug UX¶
| Feature | Behavior |
|---|---|
| Streaming answer | Appends text_delta |
| Thinking | Collapsible “Thinking Process” from thinking_delta |
| Citations | Interactive source references from retrieval results |
| Debug panel | Query rewrite, hit lists, RRF scores, timings |
| Empty retrieval | Inline notice without LLM generation |
Loading, error, empty states¶
- Model load progress from context (
llmProgress,embeddingProgress) - Document statuses: pending/processing/completed/failed with retry
- Settings capability probes: WebGPU, Workers, IndexedDB,
SharedArrayBuffer - Import errors surfaced in settings UI
Type safety and build quality¶
pnpm build=tsc -b && vite buildpnpm typecheck,pnpm lint, Prettier with Tailwind plugin- Path alias
@→./src
Frontend interview questions¶
Q: How do you keep the UI responsive during indexing?
A: Extract/chunk run in indexing.worker; embeddings in embedding.worker; status callbacks update the UI without blocking parse work on the main thread.
Q: How is global model state shared?
A: One SystemInitProvider instantiates all four engine hooks and exposes a unified load/switch API used by chat and settings.
Q: Why TanStack Router file routes?
A: Colocated route modules with typed createFileRoute, generated route tree, and basepath support for project Pages hosting.