feat: 오피스 → ODF 변환 + 원본/편집본 분리 아키텍처

- original_path/format/hash + conversion_status 필드 추가 (migration 007)
- extract_worker: 텍스트 추출 후 xlsx→ods, docx→odt 등 ODF 변환
  - 변환본은 .derived/{doc_id}.ods 에 저장
  - 원본 메타 보존 (original_path/format/hash)
- file_watcher: .derived/ .preview/ 디렉토리 제외
- DocumentViewer: ODF 포맷이면 편집 버튼 자동 표시
  - edit_url 있으면 "편집", 없으면 "Synology Drive에서 열기"

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Hyungi Ahn
2026-04-03 13:11:43 +09:00
parent b937eb948b
commit 1b5fa95a9f
6 changed files with 78 additions and 8 deletions

View File

@@ -25,11 +25,15 @@
return 'unsupported';
}
function getEditUrl(doc) {
const ODF_FORMATS = ['ods', 'odt', 'odp', 'odoc', 'osheet'];
function getEditInfo(doc) {
// DB에 저장된 편집 URL 우선
if (doc.edit_url) return doc.edit_url;
// CAD는 AutoCAD Web
if (['dwg', 'dxf'].includes(doc.file_format)) return 'https://web.autocad.com';
if (doc.edit_url) return { url: doc.edit_url, label: '편집' };
// ODF 포맷 → Synology Drive
if (ODF_FORMATS.includes(doc.file_format)) return { url: 'https://link.hyungi.net', label: 'Synology Drive에서 열기' };
// CAD
if (['dwg', 'dxf'].includes(doc.file_format)) return { url: 'https://web.autocad.com', label: 'AutoCAD Web' };
return null;
}
@@ -82,7 +86,7 @@
}
}
let editUrl = $derived(fullDoc ? getEditUrl(fullDoc) : null);
let editInfo = $derived(fullDoc ? getEditInfo(fullDoc) : null);
</script>
<svelte:window on:keydown={handleKeydown} />
@@ -113,14 +117,14 @@
>편집</button>
{/if}
{/if}
{#if editUrl}
{#if editInfo}
<a
href={editUrl}
href={editInfo.url}
target="_blank"
rel="noopener"
class="flex items-center gap-1 px-2 py-1 text-xs text-[var(--text-dim)] hover:text-[var(--accent)] border border-[var(--border)] rounded"
>
<ExternalLink size={12} /> 편집
<ExternalLink size={12} /> {editInfo.label}
</a>
{/if}
<a