From 7a38c95f3f8e85471c37355ddc5b03b57975b112 Mon Sep 17 00:00:00 2001 From: Hyungi Ahn Date: Wed, 8 Apr 2026 12:46:03 +0900 Subject: [PATCH] =?UTF-8?q?feat(ui):=20Phase=20F=20=E2=80=94=20Inbox=20?= =?UTF-8?q?=EB=B6=84=EB=A5=98=20UX=20+=20review=5Fstatus=20hotfix?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit F.1 review_status 버그 fix + 승인 UX 가드: - PATCH body에 review_status: 'approved' 누락 버그 수정 (hotfix) → 기존에는 승인해도 문서가 inbox에서 사라지지 않던 증상 해결 - isApprovable(doc): effective domain(override or original)이 비어 있으면 false - 미분류 행: 체크박스 disabled + ⚠ "도메인 선택 필요" Badge 인라인 표시 + 카드 border-warning 강조. 클릭 자체가 막힘 (toast 경고 아님) F.2 runes 마이그레이션 + 프리미티브 전환: - let → $state/$derived/$derived.by, onMount 유지 - Card/Button/Select/TextInput/Badge/EmptyState/Skeleton/Modal/ ConfirmDialog/FormatIcon/TagPill 프리미티브로 전면 재작성 - 기존 bg-[var(--*)] 클러스터 전부 제거 F.3 필터 row: - source / format Select 드롭다운 (현재 documents에서 동적 집계) - confidence는 백엔드 ai_confidence 필드 추가 대기 — 주석 TODO(backend) F.4 처리 단계 가시성: - extracted_at / ai_processed_at / embedded_at 3개 Badge (success tone = 완료, neutral = 대기) + source_channel 표시 - backend 전용 endpoint 없이 기존 응답 필드만으로 stop-gap F.5 행별 override: - Map 로컬 state - 도메인 select 변경 시 overrides에 기록, 원복 버튼으로 clear - 승인(approveOne) 시점에 override를 PATCH body에 병합 - 도메인 override로 미분류 → 분류 전환 가능 (바로 승인 가능해짐) F.6 배치 override + 재시도 stub: - 선택 toolbar: 일괄 도메인 / 일괄 태그 modal - 배치 override는 로컬 Map만 갱신, 실제 PATCH는 승인 시 1회 - 재시도 버튼: disabled stub (TODO backend POST /queue/retry) - 선택 상한 50건, pLimit(5) + Promise.allSettled 일괄 승인 검증: - npm run build 통과 (a11y 경고 fix: label → span + aria-label) - npm run lint:tokens 229 → 204 (inbox 레거시 var() 토큰 전부 제거, -25) Co-Authored-By: Claude Opus 4.6 (1M context) --- frontend/src/routes/inbox/+page.svelte | 546 +++++++++++++++++++------ 1 file changed, 424 insertions(+), 122 deletions(-) diff --git a/frontend/src/routes/inbox/+page.svelte b/frontend/src/routes/inbox/+page.svelte index 0c74b1c..4c2156d 100644 --- a/frontend/src/routes/inbox/+page.svelte +++ b/frontend/src/routes/inbox/+page.svelte @@ -1,20 +1,67 @@ -
+
+
-

Inbox

- {documents.length} +

Inbox

+ {documents.length} + {#if unclassifiedCount > 0} + + + 미분류 {unclassifiedCount} + + {/if}
- - + {selected.size === approvableCount && approvableCount > 0 ? '전체 해제' : '전체 선택'} + + +
-
- {#if loading} -
- {#each Array(3) as _} -
- {/each} -
- {:else if documents.length === 0} -
-

Inbox가 비어 있습니다

-

새 파일이 들어오면 자동으로 표시됩니다

-
- {:else} -
- {#each documents as doc} -
+ +
+
+ +
+ +
+ + + {#if selectionCount > 0} +
+ + {selectionCount}건 선택 + {#if selectionOverLimit} + (최대 {MAX_SELECTION}건 초과) + {/if} + +
+ + +
+ {/if} + + + {#if loading} +
+ {#each Array(3) as _} + + {/each} +
+ {:else if filteredDocs.length === 0} + + {:else} +
+ {#each filteredDocs as doc (doc.id)} + {@const approvable = isApprovable(doc)} + {@const isChecked = selected.has(doc.id)} + {@const ov = overrides.get(doc.id) ?? {}} + {@const displayDomain = effectiveDomain(doc)} + {@const displayTags = effectiveTags(doc)} + {@const hasOverride = ov.domain !== undefined || ov.tags !== undefined} + +
toggleSelect(doc.id)} - class="mt-1 accent-[var(--accent)]" + class="mt-1 h-4 w-4 accent-accent disabled:opacity-40 disabled:cursor-not-allowed" + aria-label="{doc.title || '문서'} 선택" />
-
- {doc.file_format} - {doc.title || '제목 없음'} + +
+ + + {doc.title || '제목 없음'} + + {#if !approvable} + + + 도메인 선택 필요 + + {/if} + {#if hasOverride} + override + {/if}
{#if doc.ai_summary} -

{doc.ai_summary.slice(0, 120)}

+

{doc.ai_summary.slice(0, 140)}

{/if} -
- AI 분류: + + +
+ + {#if doc.extracted_at}{/if} + 추출 + + + {#if doc.ai_processed_at}{/if} + 분류 + + + {#if doc.embedded_at}{/if} + 임베딩 + + + · {doc.source_channel || '-'} + +
+ + +
+ 도메인 - {#if doc.ai_tags?.length > 0} -
- {#each doc.ai_tags.slice(0, 3) as tag} - {tag} + {#if hasOverride} + + {/if} + {#if displayTags.length > 0} +
+ {#each displayTags.slice(0, 6) as tag} + {/each}
{/if}
- {/each} -
- {/if} -
- - - {#if showConfirm} -
-
-

{selected.size}건을 승인합니다

-

AI 분류 결과를 확정하고 Inbox에서 이동합니다.

-
- - -
-
+ + {/each}
{/if}
+ + + + + + +

+ 선택한 {selectionCount}건에 로컬 override 적용. 아직 저장되지 않음 — 승인 시 반영됨. +

+