Skip to content

fix(ui): render document content + entity graph; nil-safe embedder#93

Merged
aksOps merged 1 commit intomainfrom
fix/ui-doc-content-and-entity-graph
May 3, 2026
Merged

fix(ui): render document content + entity graph; nil-safe embedder#93
aksOps merged 1 commit intomainfrom
fix/ui-doc-content-and-entity-graph

Conversation

@aksOps
Copy link
Copy Markdown
Contributor

@aksOps aksOps commented May 3, 2026

Summary

Three fixes that were surfaced when walking through the full indexed-corpus flow end-to-end.

Backend

  • GET /api/documents/{id}/chunks — new endpoint returning ordered chunks (id, chunk_index, content, token_count). The store already exposes ListChunksByDoc; this is a thin handler.
  • GET /api/graph?project=... — new endpoint returning the full entity graph as {nodes, edges}, shaped to match the UI's existing RawGraphResponse.
  • pipeline.indexFile is now nil-safe on the embedder when provider=none. Previously the CLI panicked with (*Embedder).EmbedTexts on a nil receiver, contradicting CLAUDE.md's nil-safe contract.

Frontend

  • DocumentView now renders chunk content as markdown (via markdown-it, already a dep) when doc_type is md/markdown, with a <pre> fallback otherwise. Previously the view only rendered title + doc_type · v<n>, so any opened document looked blank.
  • Graph now loads both the entity graph and the notes graph, defaults to the entity graph when it has nodes, and exposes a toggle so users can switch. Previously hard-wired to useNotesGraph, so an indexed corpus with no hand-authored notes always showed the empty state.

Verified

  • CGO_ENABLED=1 go build -tags sqlite_fts5 ./... — clean.
  • go test ./internal/api/... ./internal/pipeline/... ./internal/embedder/... — all green.
  • tsc -b --noEmit && vite build — clean.
  • End-to-end against a running docsiq serve --port 37777:
    • GET /api/graph?project=_default → 200, 10 nodes / 7 edges (entities & relationships from the sample corpus).
    • GET /api/documents/{id}/chunks?project=_default → 200, returns the actual document body chunks in order.

Out of scope (separate PRs)

  • ./docsiq index --force collides on documents.file_hash UNIQUE — the supersede path bumps version but doesn't release the old hash.
  • /api/graph/neighborhood only accepts the entity name (case-sensitive via GetEntityByName); UUIDs return 404.

Test plan

  • CI green on ci, codeql, security, scorecard, playwright
  • Manually load /documents/<id> in the UI — content should render
  • Manually load /graph in the UI — entity graph should render with 10 nodes if _default is indexed; toggle to Notes graph should work too

Three fixes for issues surfaced when running through the indexed-corpus
flow end-to-end.

Backend
- Add `GET /api/documents/{id}/chunks` returning the ordered chunks for
  a document (id, chunk_index, content, token_count). The store already
  exposes `ListChunksByDoc`; this is a thin handler around it.
- Add `GET /api/graph?project=...&type=...&limit=...` returning the full
  entity graph as `{nodes, edges}` matching the UI's existing
  RawGraphResponse shape, so the same GraphCanvas can render it without
  a parallel transform.
- Skip the embedding phase in `pipeline.indexFile` when `p.embedder` is
  nil (provider=none / graph-only flow). Previously every CLI index run
  with `DOCSIQ_LLM_PROVIDER=none` panicked with a nil-pointer in
  `(*Embedder).EmbedTexts`, contradicting the CLAUDE.md guarantee that
  the embedder is nil-safe in this mode. Chunks are still persisted;
  downstream extraction works off raw text rather than vectors.

Frontend
- New `useDocChunks` hook fetching the chunks endpoint above.
- `DocumentView` now renders chunk content. For markdown documents we
  pipe through `markdown-it` (already a dep) for HTML; otherwise we
  fall back to a `<pre>` of the raw text. The previous view rendered
  only `title + doc_type · v<n>`, leaving the document body blank — the
  symptom users were hitting after `docsiq index`.
- New `useEntityGraph` hook fetching `/api/graph` and adapting it to
  the existing `GraphData` interface.
- `Graph.tsx` now loads both the entity graph (from the indexing
  pipeline) and the notes graph (wikilinks between authored notes),
  defaults to the entity graph when it has nodes, and exposes a small
  toggle so users can flip between the two. The previous route was
  hard-wired to `useNotesGraph` only, so an indexed corpus with no
  hand-authored notes always showed the empty state.

Adjacent issues surfaced but **not** fixed here (separate PRs):
- `./docsiq index --force` collides on `documents.file_hash UNIQUE`
  because the supersede path bumps version but doesn't release the old
  hash.
- `/api/graph/neighborhood` requires the entity *name* (case-sensitive
  via `GetEntityByName`); UUIDs return 404. Worth accepting either.
@aksOps aksOps enabled auto-merge (squash) May 3, 2026 16:40
@aksOps aksOps merged commit 19e7ac2 into main May 3, 2026
17 of 18 checks passed
@aksOps aksOps deleted the fix/ui-doc-content-and-entity-graph branch May 3, 2026 16:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant