Phase 12 v9.2: download-first + backend open-links (Word 16.101+ broke ms-word)
การทดสอบ 6 รอบบนเครื่องจริง (Mac, Word 16.101) พิสูจน์ว่า ms-word:ofe
ถูกเมินแบบไม่ deterministic ทุกรูปแบบ (http/https/query/ไม่มี query/
file:// — Word ไม่ยิง request ถึง server เลย เด้งหน้าเลือกไฟล์แทน)
open -a Word <local file> ใช้ได้แต่เรียกจากเว็บไม่ได้ (sandbox +
backend รัน server กลางใน production) → สรุปทางเดียวที่ deterministic
คือ download-first
- Backend: OpenLinkService (HMAC อายุสั้น ValidateOnStart) +
OpenController /api/open/{t}/{e}/v/{did}/{vid}/file.docx และ /d/{objectKey}
— ทุกอย่างอยู่ใน path ไม่มี query string (Word เมิน URL มี query),
[AllowAnonymous] ด้วยลายเซ็นแทน Bearer, stream จาก MinIO + disposition
ชื่อไทยเหมือนเดิม · download-link + generate-draft ออก open-link
แทน presigned ของ MinIO (http) · ลบ dead code presigned ทิ้ง
- Web: openDocxUrl = ดาวน์โหลดทันทีทุกครั้ง + ยิง ms-word ควบคู่แบบ
best-effort + notice "ไฟล์อยู่ Downloads" — เอา heuristic สลับแอป
ออก (โดนหน้าเลือกไฟล์ของ Word หลอกจนไม่ดาวน์โหลด)
- Spec v9.2 + ตารางทดสอบเครื่องจริงใน acceptance-review + CLAUDE.md
กฎ 13 (ms-word = best-effort เท่านั้น) + ทางเลือก helper อนาคต
- backend 86 / web 58 / add-in 66 + build ครบ; QA reviewer PASS
(1 round, minors 4 แก้ครบ)
หมายเหตุ deploy: ต้องตั้ง OpenLinks__Secret (ค่าลับจริง) และ
OpenLinks__BaseUrl (https domain ของ backend) — fail ดังตั้งแต่สตาร์ทถ้าไม่ตั้ง
Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
parent
e0558e3cf4
commit
ee4d8573ee
21 changed files with 340 additions and 145 deletions
|
|
@ -146,6 +146,7 @@ QA reviewer: **PASS**, 2 rounds, 3 findings fixed (build compatibility, pending
|
|||
| stamp เฉพาะ `TemplateId` — ไม่มี SavedByAddIn/DocumentTrackingId | test เดียวกัน (อ่าน custom properties จากไฟล์จริง) |
|
||||
| **ค่าที่แทนที่ได้ complex script ของ run ข้อความไทย (w:hint="cs"+w:cs) · SDT เปล่าสืบทอด sdtPr rPr** (v9 — แก้การตัดคำไทย) | `DraftTests.Draft_ThaiPlaceholder_UsesComplexScriptRun_ForWordBreaking` (template จำลองโครงสร้าง T14) |
|
||||
| **ค่าที่มีอักขระควบคุมที่ XML ห้าม (เช่น 0x0B จากการ paste) ถูกตัดออก สร้างไฟล์สำเร็จ ไม่กลายเป็น 500** (v9 — bug จริงจากการใช้งาน) | `DraftTests.Draft_ValueWithInvalidXmlControlChars_IsStrippedNot500` (ครอบทั้ง draft และ generate v0) |
|
||||
| **open-link ของ backend (v9.2): ไม่มี query string + จบ .docx + `[AllowAnonymous]` ด้วย HMAC + token ผิด → 404** | `DraftTests.Draft_OpenLink_BadToken_Returns404_AndNoBearerNeeded` + `VersionPdfTests` (inline/attachment + ชื่อไทยผ่าน /api/open) |
|
||||
| validate เหมือน FR-10: required ขาด/type ผิด → 400, unknown → 404, deactivate → 400, ค่าเกินนิยาม ignore | `DraftTests` ที่เหลือ (5 tests) |
|
||||
| Start Versioning ของไฟล์ร่าง: upload + templateId → **v1** + Document ผูก template + field sync ครบ + snapshot แบบมีนิยาม | `TemplateLinkingTests.Upload_WithTemplateId_OnNewDocument_CreatesLinkedDocV1WithFieldSync` |
|
||||
| upload ถัดไปไม่ส่ง templateId → v2, TemplateId คงเดิม | test เดียวกัน (upload รอบสอง) |
|
||||
|
|
@ -156,7 +157,7 @@ QA reviewer: **PASS**, 2 rounds, 3 findings fixed (build compatibility, pending
|
|||
| add-in: อ่าน TemplateId / ส่งเฉพาะ startVersioning / append form field | `metadataService.test.ts` (ไฟล์ร่างอ่าน TemplateId), `versionFlow.test.ts` (แนบ/ไม่แนบ templateId), `versioningService.test.ts` (form field) |
|
||||
| เว็บ: เปิด docx URL ที่ถืออยู่เอง (ไฟล์ร่าง) ผ่าน ms-word + fallback + notice | `useVersionOpen.spec.ts` `openDocxUrl` test |
|
||||
|
||||
ชุดเต็ม (v9): backend **85 ผ่าน**, add-in **66 ผ่าน**, web **59 ผ่าน** + production build ผ่าน (backend 82 / web 59 ของ v8 + แก้ v9)
|
||||
ชุดเต็ม (v9.2): backend **86 ผ่าน**, add-in **66 ผ่าน**, web **58 ผ่าน** + production build ผ่าน
|
||||
|
||||
### ค้างยืนยันด้วยมือ (ต้องมี Word จริง)
|
||||
|
||||
|
|
@ -166,6 +167,19 @@ QA reviewer: **PASS**, 2 rounds, 3 findings fixed (build compatibility, pending
|
|||
|
||||
รายการเต็ม: [แผน FR-16](plans/fr16-draft-generation-plan.md).
|
||||
|
||||
### การทดสอบ `ms-word:ofe` บนเครื่องจริง (Mac, Word 16.101.25092124 — 2026-09-10)
|
||||
|
||||
| ทดสอบ | ผล |
|
||||
|---|---|
|
||||
| `ms-word:ofe|u|<http://localhost MinIO presigned>` | ❌ Word เด้งหน้าเลือกไฟล์ (ไม่ยิง request) |
|
||||
| `ms-word:ofe|u|<https สั้น ไม่มี query>` | ❌ เหมือนกัน (เคยเปิดได้ 1 ครั้ง — ไม่ deterministic) |
|
||||
| `ms-word:ofe|u|<https มี query สั้น/ยาว>` | ❌ Word ไม่ยิง request ถึง server เลย (ยืนยันด้วย log) |
|
||||
| `ms-word:ofe|u|file:///tmp/...` | ❌ หน้าเลือกไฟล์ |
|
||||
| `open-word:` / `launch-word:` scheme | ❌ ไม่ยิง request |
|
||||
| `open -a "Microsoft Word" /tmp/.../v1.docx` | ✅ เปิดได้ (แต่เรียกจากเว็บไม่ได้ — browser sandbox + backend รัน server กลางใน production) |
|
||||
|
||||
→ ข้อสรุป: **download-first** คือกลไกเดียวที่ deterministic ทุกเครื่อง (commit ตามด้วย v9.2); `ms-word:ofe` เหลือเป็น best-effort ควบคู่
|
||||
|
||||
QA reviewer: **PASS**, 2 rounds, 8 findings แก้ครบไม่มีที่ถูกปฏิเสธ (2026-09-10) — round 1: blocker `.at(-1)` ใน test ใหม่ตัดกับ tsconfig `lib: es2020` ทำ `addin npm run build` พัง (jest ไม่ type-check จึงรอดมา) + minors 4 (นับจำนวน test ผิดในตารางนี้, stale notices ระหว่างสองปุ่ม submit, AlertBox สำเร็จไม่ใช่ `type="success"`, `isTrackedDocument` ไม่มี production caller → เก็บไว้พร้อมหมายเหตุเหตุผล) · round 2: minors 2 + pre-existing 1 (หัวเอกสาร/สถานะเก่าใน acceptance-review, CLAUDE.md, implementation-plan header). ค้าง manual บน Word จริงตามรายการด้านบน.
|
||||
|
||||
QA reviewer รอบ v9 (เปิดใน Word + ตัดคำไทย): **PASS**, 2 rounds, 10 findings แก้ครบไม่มีที่ถูกปฏิเสธ (2026-09-10) — round 1: minors 6 (dead `downloadFile`/`filenameFrom`, glossary "stateless" เก่า, lifecycle config เปลี่ยนแล้วเป็น no-op เงียบๆ + days ไม่ validate, ไม่มี test คุม lifecycle, comment เก่าใน TestDocx, typo ใน spec) · round 2: minors 2 + nits 2 (comment เก่าอีก 2 จุด, "(stateless)" ตกค้าง 2 บรรทัด, lifecycle test เพิ่ม assertion ผ่านค่าคืน `true/false`, ตัว verdict นี้เอง) — และ test ใหม่จับ bug จริงได้: `Configuration.Rules` เป็น null ได้ทำให้ startup ตั้ง rule ล้มแบบเงียบมาตั้งแต่แรก (โดน catch กลืน) แก้ด้วย `?? []`.
|
||||
|
|
@ -173,3 +187,5 @@ QA reviewer รอบ v9 (เปิดใน Word + ตัดคำไทย): *
|
|||
QA reviewer รอบ hotfix อักขระควบคุม 0x0B จากการ paste: **PASS**, 1 round (2026-09-10) — reviewer พิสูจน์ว่า test ใหม่ fail จริงบนโค้ดก่อนแก้ · minors 3: แก้ 1 (เปลี่ยนอักขระ VT/FF ล่องหนใน test เป็น escape sequence \u000B/\u000C กันหายระหว่างแก้ไขไฟล์) · ปฏิเสธ 2 พร้อมเหตุผล: (1) fast-path ตรวจ surrogate คู่ครบเป็น invalid ทำให้ค่ามีอีโมจิเดิน slow path — ผลลัพธ์ยังถูก (loop ประกอบคู่กลับคืน) และค่า field สั้นจึงแพงแค่หยดเดียว ไม่คุ้มจะ duplicate pair-logic (2) broad catch ให้ 502 แทน 500 สำหรับ bug ภายใน — สอดคล้อง convention 502 ของ "ไฟล์ template/ค่ามีปัญหา" ที่มีอยู่ และเหตุการณ์จริงที่ catch นี้มีไว้กันคือ input-triggered แท้ๆ (stack ยัง log ฝั่ง server)
|
||||
|
||||
QA reviewer รอบ hotfix "เปิดใน Word ตอน cold-start" (v9.1): **PASS**, 1 round (2026-09-10) — reviewer stash-verify ว่า test ใหม่ fail จริงบนโค้ดก่อนแก้ · minors 3: แก้ 1 (เพิ่ม test re-click ยกเลิก auto-download ค้าง — save ครั้งเดียว URL ล่าสุด) · ยอมรับ 2 พร้อมเหตุผล: (1) ถ้า Word cold-start มาถึงหน้าต่างภายใน 3 วิ heuristic เห็น "สลับแอป" จึงไม่ auto-download ทั้งที่เอกสารไม่เปิด — เป็นข้อจำกัดเชิงหลักการของ heuristic (แยก "Word เปิด" กับ "เปิดเอกสาร" ไม่ได้จาก web) spec ระบุชัดว่าไม่ใช่หลักฐานความสำเร็จ + มี manual check item ครอบ (2) ถ้า Word เปิดเอกสารสำเร็จแต่ช้ากว่า 3 วิ ผู้ใช้ได้ไฟล์ซ้ำใน Downloads — ต้นทุนต่ำยอมรับได้ · ตรวจแล้ว: PDF path ไม่โดน auto-download, ทุก docx entry point (version rows/v0/ไฟล์ร่าง) ผ่าน openDocxUrl ครบ
|
||||
|
||||
QA reviewer รอบ v9.2 (download-first + open-link): **PASS**, 1 round (2026-09-10) — reviewer ตรวจ security ของ `/api/open` เชิงลึก (HMAC binding/fixed-time compare/path scoping ของ draft catch-all route — ผ่านทั้งหมด) + รัน suites เองได้ 86/58/66 ตรงตาม docs · minors 4 แก้ครบ: (1) คำ spec header ที่ขัดแย้งตารางทดสอบเอง (2) OpenLinks config ตรวจตั้งแต่สตาร์ทด้วย ValidateOnStart (Secret ว่าง/BaseUrl ไม่ใช่ https = fail ดัง) (3) เอา dead code presigned ออก (GetPresignedGetUrl/PresignedExpirySeconds) + comment/copy เก่าทั้ง web/add-in/CLAUDE.md (4) draft success copy นำด้วยการดาวน์โหลดแทน "กำลังเปิดใน Word"
|
||||
|
|
|
|||
|
|
@ -646,4 +646,5 @@ npm test # vitest (46 ตัว)
|
|||
- [x] Tests/build (backend 82 / add-in 66 / web 59 + build ทั้ง add-in/web)
|
||||
- [x] QA reviewer PASS (2 rounds, 2026-09-10)
|
||||
- [x] **v9 (feedback จากการใช้จริง): เปิดใน Word ทันที** — เก็บ object ใต้ `drafts/` + lifecycle รายวัน + คืน presigned URL + `useVersionOpen.openDocxUrl` · **แก้ตัดคำไทย** — ค่าเขียนที่ run ข้อความ placeholder จริง (complex script) + SDT เปล่าสืบทอด sdtPr rPr (backend 85 / web 59) + QA reviewer PASS (2 rounds, 2026-09-10)
|
||||
- [ ] ตรวจ Word จริง (manual): เว็บสร้างไฟล์ร่าง → **Word เปิดทันที + ตัดคำไทยถูก** → untracked + hint → Start Versioning → v1 ผูก template + fields sync · รวมในรายการค้างเดิมของ Word for Windows / Word on the web
|
||||
- [x] **v9.2: Word 16.101+ เมิน `ms-word:ofe` ทุกรูปแบบ (ทดสอบ 6 รอบบนเครื่องจริง)** → download-first (ดาวน์โหลดทันที + ยิง scheme ควบคู่, เอา heuristic ออก) + `download-link`/draft ออก open-link ของ backend แทน presigned MinIO (`/api/open/{t}/{e}/...` HMAC ใน path ไม่มี query) — backend 86 / web 58
|
||||
- [ ] ตรวจ Word จริง (manual): เว็บสร้างไฟล์ร่าง → **ไฟล์ตก Downloads ทันที + ตัดคำไทยถูก** → เปิดไฟล์เอง → untracked + hint → Start Versioning → v1 ผูก template + fields sync · รวมในรายการค้างเดิมของ Word for Windows / Word on the web
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue