feat(hier): 절 딥링크 — /clause 클릭 시 읽기뷰가 해당 절을 표시

문제: /clause 결과 클릭이 문서 첫 화면으로만 가고 해당 절로 안 감.
수정 2곳:
- /clause → /documents/{id}?section={chunk_id} 로 이동.
- 읽기뷰 defaultSelId 가 ?section=<chunk_id>(outline 에 존재 시)를 우선 선택 → 그 절 표시.
- 컨테이너 절(is_leaf=false 비-split, outline 부재: UG-136/UHX-13 등 26개 핵심절)은
  clause-lookup 이 문서순서상 첫 딥링크 가능 자손으로 점프 타깃 해소(검색은 그대로 찾되
  클릭은 그 절 내용으로). 26개 전부 해소 검증.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
hyungi
2026-06-20 08:41:00 +09:00
parent 16f3e313da
commit 1f0be3312b
3 changed files with 17 additions and 3 deletions
+13 -2
View File
@@ -710,8 +710,19 @@ async def clause_lookup(
await session.execute(
sql_text(
"""
SELECT c.doc_id, d.title AS doc_title, c.section_title,
c.char_start, c.id AS chunk_id, c.node_type
SELECT c.doc_id, d.title AS doc_title, c.section_title, c.char_start, c.node_type,
-- 점프 타깃 = outline(/sections: is_leaf 또는 %_split)에 있는 chunk 여야 딥링크 동작.
-- 자신이 그러면 자신, 아니면(컨테이너 절: 자식 heading 보유·is_leaf=false) 문서순서상
-- 자신 이후 첫 딥링크 가능 chunk(=그 절 내용 시작)로 해소. 그래도 없으면 자신(폴백).
COALESCE(
CASE WHEN c.is_leaf = true OR c.node_type LIKE '%\\_split' ESCAPE '\\' THEN c.id END,
(SELECT ch.id FROM document_chunks ch
WHERE ch.doc_id = c.doc_id AND ch.source_type = 'hier_section'
AND ch.chunk_index >= c.chunk_index
AND (ch.is_leaf = true OR ch.node_type LIKE '%\\_split' ESCAPE '\\')
ORDER BY ch.chunk_index LIMIT 1),
c.id
) AS chunk_id
FROM document_chunks c
JOIN documents d ON d.id = c.doc_id
WHERE c.node_type IN ('clause', 'clause_split')
+1 -1
View File
@@ -61,7 +61,7 @@
{/if}
{#each hits as hit (hit.chunk_id)}
<button
onclick={() => goto(`/documents/${hit.doc_id}`)}
onclick={() => goto(`/documents/${hit.doc_id}?section=${hit.chunk_id}`)}
class="block w-full rounded-lg border border-default bg-surface px-4 py-3 text-left transition hover:border-accent hover:bg-surface-hover"
>
<div class="font-medium text-base">{hit.section_title}</div>
@@ -130,6 +130,9 @@
let manageOpen = $state(false);
// 기본 선택 = 첫 본문 Part 의 첫 절(front-matter TOC 가 아니라 실제 내용으로 진입, front-matter 접힘 유지).
let defaultSelId = $derived.by(() => {
// 딥링크 진입: ?section=<chunk_id> 가 outline 에 있으면 그 절로 (/clause 절 바로가기 → 해당 절 표시).
const deep = Number($page.url.searchParams.get('section'));
if (deep && outline.some((it) => it.section.chunk_id === deep)) return deep;
if (treeGroups) {
const body = treeGroups.find((g) => !g.isFrontMatter);
if (body && body.items.length) return body.items[0].section.chunk_id;