Adds technical design docs for the navigation epic of the doc-centric pivot: - 207 — Document-centric routing (/docs, /docs/:id?mode=, /index/:store, /runs) - 208 — Doc workspace breadcrumb (Studio > <doc> > <mode>) - 209 — Sidebar nav rework (Home / Docs / Stores / Runs / Settings) - 210 — Feature flag mode gating (deep-link redirect + flag exposure) Status: Accepted on all four. Each doc spells out the contract, alternatives considered, risks per audit dimension, and testing strategy. Backwards-compatibility is preserved throughout: legacy routes and pages keep working until E3/E4/E5 explicitly replace them. Refs #207 #208 #209 #210
175 lines
7.6 KiB
Markdown
175 lines
7.6 KiB
Markdown
# Design: Navigation rework — Home / Docs / Stores / Runs / Settings
|
|
|
|
- **Issue:** #209
|
|
- **Title on issue:** [ENHANCEMENT] Rework top navigation (Home / Docs / Stores / Runs / Settings)
|
|
- **Author:** Pier-Jean Malandrino
|
|
- **Date:** 2026-04-29
|
|
- **Status:** Accepted
|
|
- **Target milestone:** 0.6.0 — Doc-centric ingest
|
|
- **Impacted layers:** frontend: shared/ui · app
|
|
- **Audit dimensions likely touched:** Clean Code · Tests · Documentation
|
|
- **ADR spawned?:** no
|
|
|
|
---
|
|
|
|
## 1. Problem
|
|
|
|
The existing nav is a **left sidebar** (`AppSidebar.vue`) with seven entries: `Home`, `Studio`, `Documents`, `Search`, `Reasoning`, `History`, `Settings`. It mirrors the current execution-centric IA: `Studio` (an analysis), `Documents` (a list), `History` (past runs).
|
|
|
|
The doc-centric pivot wants a tighter five-entry nav reflecting the new IA: **Home, Docs, Stores, Runs, Settings**. `Docs` is the new primary action (replaces `Documents` + `Studio`). `Stores` is new. `Runs` replaces `History` (same data, new framing). `Search` and `Reasoning` collapse into the doc workspace modes (#216 + #224).
|
|
|
|
The original PM sitemap called this a "top nav" — the project's actual nav is a **sidebar**. We keep the sidebar (existing convention, established interaction) and rework its entries.
|
|
|
|
## 2. Goals
|
|
|
|
- [ ] `AppSidebar.vue` shows five entries in this order: Home, Docs (★ primary), Stores, Runs, Settings.
|
|
- [ ] `Docs` visually emphasised — bold label or accent colour token.
|
|
- [ ] Active state correctly highlights `Docs` on `/docs`, `/docs/new`, `/docs/:id`.
|
|
- [ ] Active state for `Stores` on `/index`, `/index/:store`, `/index/:store/query`.
|
|
- [ ] Active state for `Runs` on `/runs`, `/runs/:id`.
|
|
- [ ] Legacy entries (`Studio`, `Documents`, `Search`, `Reasoning`, `History`) removed from the sidebar.
|
|
- [ ] Legacy URLs still functional (we did not redirect in #207).
|
|
|
|
## 3. Non-goals
|
|
|
|
- Removing the legacy *pages* — they keep working; this issue removes them only from the sidebar.
|
|
- Mobile hamburger redesign — the existing burger toggle stays.
|
|
- Sidebar collapse animation — unchanged.
|
|
- Top breadcrumb — that is **#208**.
|
|
- A "what's new" tooltip explaining the change — out of scope; release notes cover it.
|
|
|
|
## 4. Context & constraints
|
|
|
|
### Existing code surface
|
|
|
|
- `frontend/src/shared/ui/AppSidebar.vue` — the file to edit. Currently 145 lines.
|
|
- `frontend/src/app/App.vue` — embeds `<AppSidebar>`.
|
|
- `frontend/src/shared/i18n.ts` — flat keys under `nav.*`.
|
|
- `frontend/src/features/feature-flags/store.ts` — flags currently gating `Search` and `Reasoning`.
|
|
|
|
### Hard constraints
|
|
|
|
- No new dependencies.
|
|
- TypeScript strict — every nav item is typed.
|
|
- Existing burger / collapse interaction stays untouched.
|
|
|
|
## 5. Proposed design
|
|
|
|
### 5.1 Nav model
|
|
|
|
A typed array driving the render:
|
|
|
|
```ts
|
|
type NavItem = {
|
|
key: string // for v-for and active match
|
|
to: RouteLocationRaw // typed via ROUTES
|
|
labelKey: string // i18n key
|
|
iconKey: string // icon name token
|
|
primary?: boolean // visual emphasis (Docs)
|
|
matchPrefixes: string[] // prefixes for active-state match
|
|
}
|
|
|
|
const items: NavItem[] = [
|
|
{ key: 'home', to: { name: ROUTES.HOME }, labelKey: 'nav.home', iconKey: 'home', matchPrefixes: ['/'] },
|
|
{ key: 'docs', to: { name: ROUTES.DOCS_LIBRARY }, labelKey: 'nav.docs', iconKey: 'docs', primary: true, matchPrefixes: ['/docs'] },
|
|
{ key: 'stores', to: { name: ROUTES.STORES_LIST }, labelKey: 'nav.stores', iconKey: 'stores', matchPrefixes: ['/index'] },
|
|
{ key: 'runs', to: { name: ROUTES.RUNS }, labelKey: 'nav.runs', iconKey: 'runs', matchPrefixes: ['/runs'] },
|
|
{ key: 'settings', to: { name: ROUTES.SETTINGS }, labelKey: 'nav.settings', iconKey: 'settings', matchPrefixes: ['/settings'] },
|
|
]
|
|
```
|
|
|
|
### 5.2 Active match
|
|
|
|
`isActive(item, route)`:
|
|
|
|
- For `/`, the home entry is active only on exact match.
|
|
- For all other items, active when the route path **starts with** any of `item.matchPrefixes`.
|
|
- Implemented in a tiny pure helper, tested.
|
|
|
|
### 5.3 Primary emphasis
|
|
|
|
The `primary: true` item gets an extra CSS class `nav-item--primary` adding a subtle accent (left bar in the sidebar's accent colour, bolder label). No new colour tokens.
|
|
|
|
### 5.4 i18n
|
|
|
|
New keys (fr + en):
|
|
|
|
- `nav.docs`
|
|
- `nav.stores`
|
|
- `nav.runs`
|
|
|
|
Removed (or kept around for the legacy pages that still exist): `nav.studio`, `nav.documents`, `nav.history`, `nav.search`, `nav.reasoning`. We **keep** them in `i18n.ts` since the legacy pages still render headings using them. They are no longer surfaced in the sidebar.
|
|
|
|
### 5.5 Footer
|
|
|
|
The sidebar footer (OpenSearch dot, GitHub stars, version) stays. The OpenSearch dot moves to be visible regardless of `ingestion` flag — it now reflects the default store's reachability (#203's seed). For 0.6.0 we keep the existing wiring (gated by `ingestion` flag) and revisit when stores get their own page (#231 in 0.7.0).
|
|
|
|
## 6. Alternatives considered
|
|
|
|
### Alternative A — Keep all old entries, add the new ones
|
|
|
|
- **Summary:** Show 10 entries; let the user discover.
|
|
- **Why not:** Defeats the point. The pivot is about reducing cognitive load, not adding entries.
|
|
|
|
### Alternative B — Move the nav to the top bar
|
|
|
|
- **Summary:** Implement the design doc's literal "top nav".
|
|
- **Why not:** The shell is sidebar-driven; switching layout is a much bigger lift and out of scope for E2.
|
|
|
|
## 7. API & data contract
|
|
|
|
No backend change. No env vars.
|
|
|
|
### Breaking changes
|
|
|
|
None at the API level. UX-level: legacy entries disappear from the sidebar. Their URLs remain valid.
|
|
|
|
## 8. Risks & mitigations
|
|
|
|
| Risk | Audit dimension | Likelihood | Impact | How we notice | Mitigation / rollback |
|
|
|------|-----------------|------------|--------|---------------|------------------------|
|
|
| Users of legacy pages think the app removed features | Documentation | Medium | Medium | Support tickets | Release notes; legacy pages still work via direct URL; eventually #211/#216 replace them entirely |
|
|
| Active state misfires because two entries match the same prefix | Clean Code | Low | Low | Visual regression | `matchPrefixes` is explicit, longest-prefix wins via simple precedence in the helper |
|
|
| Missing icons for Docs / Stores / Runs in the existing icon set | Clean Code | Medium | Low | Visible during review | Audit `iconKey` strings against the icon component before merge; fall back to a sane default if missing |
|
|
|
|
## 9. Testing strategy
|
|
|
|
### Frontend — Vitest
|
|
|
|
- `shared/ui/AppSidebar.test.ts` — renders 5 entries in order; `Docs` carries the primary class; active state correct on each `matchPrefix`.
|
|
- `shared/ui/navActive.test.ts` — pure helper unit tests over `isActive(item, path)`.
|
|
|
|
### Manual QA
|
|
|
|
1. Visit `/`, `/docs`, `/index/foo`, `/runs`, `/settings` → exactly one entry highlighted.
|
|
2. Visit `/docs/abc?mode=chunks` → `Docs` highlighted.
|
|
3. Visit a legacy route `/studio` → no nav entry highlighted (page still loads).
|
|
|
|
## 10. Rollout & observability
|
|
|
|
### Release branch
|
|
|
|
`release/0.6.0`.
|
|
|
|
### Feature flag
|
|
|
|
None.
|
|
|
|
### Observability
|
|
|
|
None.
|
|
|
|
### Rollback plan
|
|
|
|
Revert. The legacy nav returns; legacy pages were never broken.
|
|
|
|
## 11. Open questions
|
|
|
|
- Do we add a `Help` entry now or wait? **Decision:** wait. The five-entry nav is part of the value proposition.
|
|
|
|
## 12. References
|
|
|
|
- **Issue:** https://github.com/scub-france/Docling-Studio/issues/209
|
|
- **Related issues:** #207 (routing), #208 (breadcrumb), #210 (FF gating), #211 (library), #216 (workspace)
|
|
- **ADRs:** none planned
|
|
- **Project docs:** Architecture (`docs/architecture.md`), Frontend conventions (`frontend/CLAUDE.md`)
|