You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Viewer compatibility — never break packages/@nitpicker/viewer/web/'s existing frontend/API contract. Verify actual frontend consumers (web/api/, web/routes/) before changing any response shape.
These are non-negotiable and ranked in this order. No half-measures: pursue maximum read performance without compromise. Research prior art, benchmark with real measurements (including real large archives, not just synthetic data), and do not let implementation effort or time be a reason to settle for a suboptimal design.
AS IS
The backend directory tree read model and API landed in #107 (GET /api/directory-tree, /api/directory-tree/children, /api/directory-tree/pages). There is no frontend surface for it yet — the viewer has no way to browse the crawled URL space as a directory tree.
TO BE
Add a directory tree view to the viewer frontend (packages/@nitpicker/viewer/web/), following the usage pattern the backend API was designed around (docs/viewer-sql-query-plan.md's directory-tree section):
On load, call GET /api/directory-tree and render the flat { roots: [{ rootKey, nodes }] } response as a nested tree per root, using each node's parentNodeId to build parent/child relationships client-side (the backend never nests server-side).
Each node shows name, and a badge using childCount (directChildDirCount + directPageCount). Only render an expand affordance when hasChildren is true (child directories exist — direct pages are shown separately, not as additional tree rows).
Clicking an unexpanded node with hasChildren: true and depth === 3 (the initial load's cutoff) calls GET /api/directory-tree/children?nodeId= to fetch its direct child directories dynamically.
Selecting a directory node shows its direct pages (not descendants) via GET /api/directory-tree/pages?nodeId=&cursor=&limit=, cursor-paginated (nextCursor only, no prevCursor — forward-only, same contract as other infinite-scroll views in the viewer).
Add a nav entry / route consistent with the other list views (pages / resources / images / etc.), and i18n labels (en/ja) per web/i18n/translations.ts.
Must
Multi-root archives: render one tree per rootKey (most archives will have exactly one).
Respect descendantPageCount / internalDescendantPageCount / externalDescendantPageCount if the UI wants to show subtree size without fetching descendants.
No client-side recursive fetch of the whole tree — only expand on demand via the children endpoint.
Don't
Don't fetch or render descendant pages from the tree expansion endpoints — direct pages only, via the dedicated pages endpoint.
Priority (from #103 — absolute, consult whenever unsure)
packages/@nitpicker/viewer/web/'s existing frontend/API contract. Verify actual frontend consumers (web/api/,web/routes/) before changing any response shape.nitpicker viewer-buildcommand, never inline during a read-only open (see Remove on-open opportunistic read model build (corrects #112) #177, which corrects the Define persistent viewer read model build timing #112 on-open build that violated this).These are non-negotiable and ranked in this order. No half-measures: pursue maximum read performance without compromise. Research prior art, benchmark with real measurements (including real large archives, not just synthetic data), and do not let implementation effort or time be a reason to settle for a suboptimal design.
AS IS
The backend directory tree read model and API landed in #107 (
GET /api/directory-tree,/api/directory-tree/children,/api/directory-tree/pages). There is no frontend surface for it yet — the viewer has no way to browse the crawled URL space as a directory tree.TO BE
Add a directory tree view to the viewer frontend (
packages/@nitpicker/viewer/web/), following the usage pattern the backend API was designed around (docs/viewer-sql-query-plan.md's directory-tree section):GET /api/directory-treeand render the flat{ roots: [{ rootKey, nodes }] }response as a nested tree per root, using each node'sparentNodeIdto build parent/child relationships client-side (the backend never nests server-side).name, and a badge usingchildCount(directChildDirCount + directPageCount). Only render an expand affordance whenhasChildrenistrue(child directories exist — direct pages are shown separately, not as additional tree rows).hasChildren: trueanddepth === 3(the initial load's cutoff) callsGET /api/directory-tree/children?nodeId=to fetch its direct child directories dynamically.GET /api/directory-tree/pages?nodeId=&cursor=&limit=, cursor-paginated (nextCursoronly, noprevCursor— forward-only, same contract as other infinite-scroll views in the viewer).web/i18n/translations.ts.Must
rootKey(most archives will have exactly one).descendantPageCount/internalDescendantPageCount/externalDescendantPageCountif the UI wants to show subtree size without fetching descendants.childrenendpoint.Don't
pagesendpoint.hasChildrenas "has anything" — it reflects child directories only (see Implement directory tree read model and API #107's design note in ARCHITECTURE.md).Acceptance
viewer-e2e) covers initial render + expand + page list.Backend reference: #107.