# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## โปรเจกต์นี้คืออะไร ระบบ **Word Versioning**: จัดการ version history ของไฟล์ .docx — สร้างเอกสารจาก template ผ่านเว็บ, ตรวจจับ tracked document ใน Word, บันทึก version ผ่านปุ่ม Save & Version และ sync ค่า fields กลับ DB ประกอบด้วย 3 ส่วน: | ส่วน | Stack | หน้าที่ | |---|---|---| | `/addin` | Office.js + TypeScript + React + Fluent UI (`yo office`) | Task pane ใน Word Desktop/Online — detect, Save & Version, history, field extraction | | `/backend` | ASP.NET Core 8 + EF Core + PostgreSQL + MinIO (AWSSDK.S3) + OpenXML | Version API, template system, docx generation, JWT validation | | `/web` | Nuxt.js + TailwindCSS (light/dark theme) | จัดการ template + กรอก form สร้างเอกสารเป็น version 1 อัตโนมัติ | Infra ทั้งหมดรันผ่าน `docker-compose.yml`: PostgreSQL + MinIO + Keycloak (OIDC, 3 public clients พร้อม PKCE: `word-addin-officejs`, `word-versioning-web`, `word-addin-vsto`) **สถานะปัจจุบัน: Phase 0–2 เสร็จ** (scaffold + infra + backend core FR-5–8) — งานต่อคือ implement phase 3–8 ในแผน ## เอกสารหลัก (อ่านก่อนเริ่มงานใดๆ) - `specs/spec-officejs.md` — **source of truth ของ requirements** (FR-1–11, acceptance criteria 1–14, data models, platform constraints) - `docs/plans/officejs-implementation-plan.md` — implementation plan แบ่ง 9 phases พร้อม checklist, DoD, dependency ระหว่าง phase และตารา mapping Phase↔FR↔AC เมื่อ requirement เปลี่ยน: แก้ spec ก่อน แล้ว sync ไปยัง plan ## กฎที่ห้ามละเมิด (ข้อจำกัดแพลตฟอร์มจริง — สรุปจาก spec ส่วน 2 และ 9) 1. **ห้ามออกแบบ flow ที่ดัก native save** (Ctrl+S / File>Save) — Office.js ไม่มี before-save event ที่ cancel ได้ ใช้ปุ่มใน task pane เท่านั้น 2. **Custom Document Properties = primary flag** ตรวจจับ tracked document; **Custom XML Part = secondary เท่านั้น** (ต้อง delete แล้ว add ใหม่ทุกครั้ง, มี known bug บน Mac บาง build — ต้อง catch แบบไม่ throw) 3. **ห้าม redirect iframe ของ task pane ไป Keycloak ตรงๆ** — ต้องใช้ Office Dialog API (`displayDialogAsync` + `messageParent`); ส่วน `/web` เป็น top-level page ใช้ OIDC redirect ปกติ 4. **Token เก็บใน memory เท่านั้น** — ห้าม localStorage (theme preference ของ `/web` ยกเว้นได้) 5. **Backend คือ source of truth** ของ version history และ field values 6. **Field key = content control (SDT) tag** ใช้ค่าเดียวกันทั้ง generate (backend) / extract (add-in) / sync (DB) 7. **Docx generation + metadata stamping ทำฝั่ง backend เท่านั้น** (OpenXML, แก้ที่ run level ใน SDT เพื่อรักษา formatting) 8. **Ports:** add-in = `https://localhost:3000`, web = `http://localhost:5173` (ห้ามชนกัน), backend CORS ต้องอนุญาตทั้งคู่ 9. **Config (DB/MinIO/Keycloak) แยกเป็น env/appsettings เท่านั้น** — ห้าม hardcode; `userId` เอาจาก JWT claims เท่านั้น ห้ามรับจาก client 10. **ทุก Office.js call ต้อง catch** — ห้ามปล่อย unhandled promise rejection ## สถาปัตยกรรม — flow หลักที่ต้องเข้าใจ **Create → v1 (FR-10):** web form → `POST /api/documents/generate` → OpenXML แทนที่ค่าใน SDT + stamp `SavedByAddIn`/`DocumentTrackingId` ลงไฟล์ → สร้าง `Document` + `DocumentFieldValue` + upload v1 → ผู้ใช้โหลดไฟล์ไปเปิดใน Word → add-in ตรวจพบ tracked doc ทันทีเห็น v1 **Save & Version (FR-2):** ปุ่มใน task pane → stamp properties → อัปเดต XML part (delete-then-add, fail ได้แบบ silent) → `document.save()` → `getFileAsync` → POST version **พร้อม `fields` map จาก content controls (FR-11)** → backend update `DocumentFieldValue` (latest) + `FieldsSnapshotJson` (ต่อ version) **Field sync policy (FR-11):** field ขาด (ผู้ใช้ลบ control) → เก็บค่าเดิม + mark missing **ไม่ fail request**; ส่งมาเกินนิยาม → ignore **MinIO:** bucket `docx-versions` (snapshot ต่อ version, key `{documentId}/v{N:D4}_{clientVersionId}.docx`) + `docx-templates` (ไฟล์ template) — private ทั้งคู่, เข้าถึงผ่าน backend proxy stream เท่านั้น **Template:** template.docx author ด้วย Word (ใส่ content controls) → upload → backend parse SDT tags → admin ตั้ง label/type/required → delete = deactivate (soft) เพราะ document เก่ายังอ้างอยู่ ## คำสั่ง (ใช้ได้หลัง scaffold ใน Phase 0) ```bash docker compose up -d # infra: PostgreSQL + MinIO + Keycloak # backend cd backend/WordVersioning.Api dotnet run # API + swagger dotnet ef migrations add dotnet test dotnet test --filter "FullyQualifiedName~GenerateTests" # รัน test เดี่ยว # add-in (https://localhost:3000) cd addin npm run build # webpack build npm start # dev server — sideload ผ่าน manifest npm test npx jest src/services/metadataService.test.ts # รัน test เดี่ยว npx office-addin-dev-certs install # ครั้งแรกครั้งเดียว # web portal (http://localhost:5173 — ห้ามใช้ 3000) cd web npm run dev npm test npx vitest run composables/useTheme.spec.ts # รัน test เดี่ยว ```