Backend
- HealthResponse exposes inspectModeEnabled / chunksModeEnabled /
askModeEnabled (additive; defaults true). main.py /api/health
populates them from settings.
- infra/settings.py: three new env-var-driven booleans (defaults true)
parsed in from_env() like the existing reasoning_enabled flag.
- tests/test_api_endpoints.py: extra assertion that /api/health
surfaces the three new fields with their defaults.
Frontend — flag store
- features/feature-flags/store.ts: FeatureFlag union extended with
inspectMode / chunksMode / askMode. New entries in featureRegistry
are gated on context fields populated from health. Missing fields
fall back to true so a frontend pointed at an older backend keeps
every mode visible.
- store gains a modeFlags() helper returning Record<DocMode, boolean>
so the routing guard does not need to know the FeatureFlag union.
Frontend — routing
- shared/routing/resolveMode.ts: pure resolver. If the requested mode
is enabled, return it; else first enabled in priority ask > chunks
> inspect; else null.
- app/router/index.ts: beforeEach guard scoped to ROUTES.DOC_WORKSPACE.
Disabled mode → rewrite ?mode= to the first enabled one. All three
off → redirect to /docs?reason=no-mode-enabled.
Frontend — flash
- pages/DocsLibraryPage.vue: shows a banner when ?reason=no-mode-enabled
is set. #211 will move this into the proper library page banner.
- i18n flags.allModesDisabled added in fr + en.
Tests
- shared/routing/resolveMode.test.ts (6 cases): every (requested,
enabled) combination including all-disabled, priority order,
missing requested.
- features/feature-flags/store.test.ts: three new cases covering the
new fields in /api/health, fall-back-to-true on missing fields, and
modeFlags() shape.
Refs #210
Adds the breadcrumb anchoring the user across modes on the doc
workspace. Empty / hidden on routes that don't opt in.
Components
- shared/breadcrumb/AppBreadcrumb.vue: data-driven, accessible
(<nav aria-label>, <ol>, aria-current=page on the leaf).
Renders nothing when crumbs.length === 0.
- shared/breadcrumb/types.ts: Crumb = LinkCrumb | LeafCrumb
discriminated union.
- shared/breadcrumb/store.ts: Pinia store + useCrumbs(source)
composable that auto-clears on unmount. Accepts a static array
OR a reactive ref/computed so pages with async doc fetches can
rebuild crumbs as data lands.
- shared/breadcrumb/text.ts: truncate(text, max) helper.
Wiring
- App.vue main outlet now sits below <AppBreadcrumb>; the shell
reads from useBreadcrumbStore so pages don't need teleports.
- DocWorkspacePage provides Studio > <id-truncated> > <mode-label>;
once the doc is fetched (#216 / E4), the id placeholder will
swap for the truncated filename.
i18n
- breadcrumb.aria, breadcrumb.studio, breadcrumb.mode.{ask,inspect,
chunks} added in fr + en.
Tests
- shared/breadcrumb/text.test.ts: 5 cases on truncate.
- shared/breadcrumb/store.test.ts: store actions + useCrumbs reactive/
static seeding (the lifecycle-clear path is covered end-to-end by
the integration tests landing in #211 / #216 — the project doesn't
use @vue/test-utils so a unit test for onBeforeUnmount is overkill).
Refs #208
Adds the routing scaffold for the doc-centric pivot. Each new route
renders a placeholder page until E3/E4/E5 implement them; legacy
routes (/studio, /documents, /history, /search, /reasoning) keep
working in parallel.
New routes (Vue Router, history mode):
/docs library (placeholder, #211)
/docs/new import (placeholder, #214)
/docs/:id?mode= workspace (placeholder, #216)
/index stores list (placeholder, 0.7.0)
/index/:store store detail (placeholder)
/index/:store/query RAG playground (placeholder)
/runs run history (placeholder)
/runs/:id run detail (placeholder)
Mode parsing
- shared/routing/modes.ts: DocMode union ('ask'|'inspect'|'chunks'),
parseMode() returns the default ('ask') for missing or unknown
values. #210 will layer feature-flag-aware redirection on top.
Route names
- shared/routing/names.ts: ROUTES typed const so callers do
router.push({ name: ROUTES.DOC_WORKSPACE, ... }) instead of
stringly-typed names.
Pages
- ComingSoonShell shared component: card + back-home link, themed
with existing CSS tokens.
- 8 thin placeholder pages (one per new route) that compose the shell
and forward route params.
- i18n keys under comingSoon.* added in fr + en.
Tests
- shared/routing/modes.test.ts (10 cases): isDocMode + parseMode +
ALL_MODES invariants.
- app/router/router.test.ts (5 cases): every doc-centric route
resolves to a component, legacy routes still work, doc workspace
receives id and parsed mode as props, unknown mode falls back to
ask, unknown path redirects to home.
Routes table extracted to routes.ts so tests build a router with
createMemoryHistory() (no window required) instead of needing the
production createWebHistory() router.
Refs #207
Adds the `docling-agent` reasoning-trace viewer as a Studio tunnel, per
`docs/design/reasoning-trace.md`. Users pick an analyzed document, import
a RAGResult JSON, and the iterations are overlaid on the document graph.
Graph source is decoupled from Neo4j: a new pure builder
(`infra/docling_graph.build_graph_payload`) reads `document_json` from
SQLite and emits the same Cytoscape-shaped payload that `fetch_graph`
returns from Neo4j. Neo4j stays exclusive to the Maintain ingestion
pipeline. Shared DoclingDocument helpers live in `infra/docling_tree.py`
so TreeWriter and the builder can't drift on label taxonomy or tree walks.
Also removes the Cytoscape minimap (cytoscape-navigator) from GraphView:
second render instance hurt perf on large documents for no UX win.
Backend
- new `GET /api/documents/:id/reasoning-graph` (SQLite-only)
- new `infra/docling_tree.py`, `infra/docling_graph.py`
- `analysis_repo.find_latest_completed_by_document`
- tests: `test_docling_graph.py` (builder), `test_graph_api.py` (endpoint)
Frontend
- `features/reasoning/` — store, overlay, types, panel, import dialog,
workspace, doc picker
- new `ReasoningPage` + `/reasoning` and `/reasoning/:docId` routes
- `GraphView` gains a `fetcher` prop so reasoning can inject the
SQLite-backed fetcher while Maintain keeps using the Neo4j one
- drops minimap (nav container, dep, CSS)
- legend filters + section parenting extracted for reuse
- i18n base strings (FR + EN)
Move chunk search from DocumentsPage into a new Search bounded context
(features/search/) with its own store, API layer, page and route.
Clean search state out of the ingestion module.
Closes#159
Replace hardcoded 5 MB upload limit with a configurable setting.
Backend exposes the value via /api/health, frontend reads it
dynamically for validation and UI messages.
Closes#48
Replace generic orange "D" placeholders with the duck mascot logo
in all branding touchpoints: navbar header, home page hero, studio
import view, and browser favicon.
Introduce a feature-flags module in the frontend that detects
the backend conversion engine via /health and exposes typed
feature flags. Chunking is enabled only in local engine mode.