eCourt-note/docs/requirement/gap-analysis.md
DESKTOP-1R2VSQH\Lenovo ThinkPad E490 df0392ea45
All checks were successful
Deploy eCourt Note Web to Server / Validate Database Schema (Drizzle) (push) Successful in 3s
Deploy eCourt Note Web to Server / Build Web Docker Image (push) Successful in 42s
Deploy eCourt Note Web to Server / Deploy eCourt Note Web to Server (push) Successful in 13s
Deploy eCourt Note Web to Server / Notify Deployment Status (push) Successful in 1s
จอสัมผัส (iOS/Android): แก้ครบตาม UX audit C1+M1–M6 + code review + งาน export PDF ที่ค้างใน working tree:
(1) C1 — เมนู dropdown 5 ตัว + popup bookmark เดิมเป็น absolute ใน scroll container ของแถบ tool ที่สลับ overflow ตอนเปิด ทำให้บนมือถือ scroll position รีเซ็ต (ปุ่มเด้งกลับซ้าย) เมนูเปิดนอก viewport และทั้ง app เอียงเลื่อนแนวนอนได้ — ย้ายทั้งหมดไป createPortal(document.body) เป็น position:fixed ตาม rect จริงของปุ่มตอนคลิก (fixedMenuPos + clamp ให้อยู่ในจอ; bookmarkPos จาก ref ปุ่ม 🔖 ใช้ร่วมทุกทางเข้า รวมคีย์ลัด B) + ถอดการสลับ overflow (คง overflow-x-auto เสมอ) + ปิดเมนูเมื่อเลื่อนแถบต่อ หรือ "ความกว้าง" จอเปลี่ยน (code review Major1: resize ที่เปลี่ยนแค่ความสูง เช่น URL bar ยุบ/คีย์บอร์ดของมือถือ ไม่ปิด — เมนู fixed ยึด sticky header อยู่กับที่อยู่แล้ว กันเมนู/popup ที่เปิดค้างปรับค่าโดนปิดกลางคัน) + outside-click ข้ามโหนดใน [data-tool-menu] (ref ของ wrapper มองไม่เห็นโหนดใน portal ไม่ข้ามแล้วคลิกในเมนู=ปิดเมนูเอง) + rule ปุ่ม 36px ใน globals.css เปลี่ยนไป target [data-tool-menu] ตรง ๆ (เดิมเจาะผ่าน .z-50 ที่ไม่มีแล้ว)

(2) M4 — tap/คลิกที่ใช้ "ปิดเมนู" (mousedown ปิดก่อน click ยิงถึง page) กลายเป็นวาง comment/textbox/stamp โดยไม่ตั้งใจ — menuClosedAtRef (markMenuClosed ทุก path ปิด: outside-click/Escape/switchTool เฉพาะเมื่อมีเมนูเปิดจริง/เลื่อนแถบ/resize) แล้ว handlePageClick เฉย 300ms แรก คลิกที่สองค่อยวาง (มาตรฐาน dropdown ใช้ทั้ง desktop+touch — pattern เดียวกับ touchHideTimerRef ของปุ่มไฮไลต์)

(3) M1+M2 ของ TEXTBOX — ทางเข้า editor เคยผูก double-click อย่างเดียว (บน iOS double-tap = zoom หน้า แก้ข้อความไม่ได้เลยตลอดชีวิตบนมือถือ) — เพิ่มปุ่ม "แก้ไขข้อความ" ในแผง selection (onStartEdit → startTextboxEdit) ใช้ได้ทั้ง touch/desktop และ default fontSize 1.2% (≈7px เล็กกว่า preset ต่ำสุด 10px ของตัวเอง) → 2.5% (≈15px อ่านออกทันที) กระทบเฉพาะกล่องใหม่

(4) M3+clamp — hit area บน pointer:coarse โดยของที่มองเห็นคงขนาดเดิม: มุมกรอบใช้ ::after (10→hit 28px), แถบขอบ (8→16px), ปุ่มแผง 20→36px, swatch 16→32px, icon sidebar 16/14→32px (hooks sel-handle/sel-strip/sel-panel/sel-panel-btn/color-swatches + aside[data-sidebar]) และ clamp แนวนอนของแผง selection (left: max(0, min(box.x, size.width-244))) กันรายการชิดขวาทำแผง w-60 ล้นขอบจอแคบจนปุ่มลบหลุดจอ (เจอตอน verify จอ 390px)

(5) M5 — undo/redo max-lg:order-first ไปหัวแถวเลื่อน: เห็นเสมอโดยไม่ต้องเลื่อนแถบ (undo คือทางแก้พลาดหลักของจอสัมผัส) จอ ≥ lg ไม่มี order ลำดับ/หน้าตาเดิมทุกประการ

(6) M6 อื่น ๆ — -webkit-tap-highlight-color: transparent + overscroll-behavior-y: contain (กัน pull-to-refresh ของ Android ล้าง undo history ฝั่ง client), button/label touch-action: manipulation (ตัด double-tap zoom), safe-area inset แบบ defensive (จะมีค่าเมื่อใส่ viewport-fit=cover ในอนาคต), no-callout กัน long-press magnifier เฉพาะ layer TEXTBOX/STAMP (textLayer ยัง select/copy ได้), ปุ่ม composer/popover/pin 24→36px (coarse-36), ปุ่มหน้าสรุป 30→44px (summary-page), ซ่อนชื่อไฟล์บนจอเล็ก, ปุ่ม X ปิด sidebar บน max-lg (เดิมปิดได้ทางเดียวคือจิ้ม backdrop เพราะ overlay z-50 กลบปุ่ม toggle ใน header), tab sidebar เป็นไทย "ที่คั่นหน้า/หมายเหตุ" ให้สอดคล้อง UI ไทยล้วน, chip แจ้ง "หน้าที่เปิดดูเป็นภาพสแกน" เมื่อ tool highlight และทุกหน้าที่ render มี 0 text spans (onTextLayerRendered รายงานต่อหน้า + pageSpanCount)

(7) งาน export PDF ที่อยู่ใน working tree ก่อนหน้า + แก้ตาม code review — COMMENT กลายเป็น sticky note จริง (/Subtype /Text), bookmark → PDF outline (/Dest คำนวณตาม /Rotate เหมือน annotation), โน้ต N1 → sticky note แนบตำแหน่ง, นิยาม yOffset เป็น "ขอบบนของสิ่งที่ดูอยู่" + goToBookmark ใช้ scrollToBelowHeader, และเพิ่ม guard roots.length===0 ใน buildOutline กัน bookmark cycle ไร้ root (DB ถูกแก้ตรง ๆ) ทำ kids[0].ref พังเป็น 500 ทั้ง export

(8) sync .claude/rules/pdf-viewer.md — portal เมนู+ห้ามสลับ overflow ของแถบ, guard 300ms, hit-area hooks ระดับ coarse, TEXTBOX default 2.5% + ปุ่มแก้ไขข้อความ

verify: tsc ผ่าน · vitest 100/100 · Playwright touch emulation จริง (iPhone 390×844 / iPad 820×1180 / desktop 1280): เมนูอยู่ใน viewport ทุกสถานะหลังเลื่อนแถบ + scrollLeft คงที่ + ไม่มี horizontal overflow, แตะในเมนูไม่ปิดเอง, เลื่อนแถบ/กว้างจอเปลี่ยน=ปิด/สูงเปลี่ยน=ค้าง, guard 300ms ทั้ง stamp/textbox/comment, ปุ่มแก้ไขข้อความเปิด editor พร้อมข้อความเดิม, fontSize ใหม่ 14.9px, hit มุม 28px/ปุ่มลบ 36px/swatch 32px, undo อยู่ในจอ + undo/redo ทำงาน, X ปิด sidebar, chip สแกนโชว์/ไฟล์ text ไม่โชว์, desktop เหมือนเดิม, แผง clamp (x=130..370 ปุ่มลบจบ 363) — annotation ทดสอบลบเฉพาะ id ที่สร้างเองทั้งหมด DB กลับสะอาด

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-14 18:04:40 +07:00

18 KiB
Raw Blame History

รายงานเทียบ Requirement กับโปรเจกต์ (Gap Analysis)

  • วันที่ตรวจสอบ: 2026-09-14
  • เอกสาร requirement ต้นทาง: docs/requirement/1.png, docs/requirement/2.png (ข้อกำหนดระบบบันทึกความเห็นของกรรมการ — Judges' Notes System)
  • โค้ดที่ใช้เทียบ: branch forgejo-dev ณ commit b3b884c (implement ครบตาม PLAN.md + PLAN-FEAT.md แล้ว ยกเว้น F11 ที่ถูกถอดออก)
  • ช่วงเลขข้อ (ยืนยันโดยเจ้าของเอกสาร): ภาพที่ 1 = ข้อ 5.3.1–5.3.6 / ภาพที่ 2 = ข้อ 5.3.7–5.3.25

⚠️ หมายเหตุการอ่าน requirement: สำนวนภาษาไทยบางคำอาจคลาดเคลื่อนเล็กน้อยจากต้นฉบับ แต่สาระของทุกข้อชัดเจน — การอ่านครั้งแรกสับสนเพราะเลขข้อเป็นเลขอารบิก (5.3.X) ที่ OCR อ่านเป็นอักษรไทย ช่วงเลขข้อได้รับยืนยันจากเจ้าของเอกสารแล้ว และการตรวจซ้ำด้วยการสแกนตำแหน่งบรรทัด + อ่านเลขข้อรายบรรทัดยืนยันว่า จำนวนข้อ map ตรง 1:1 ครบทั้ง 19 ข้อ (10 ข้อครึ่งบน + 9 ข้อครึ่งล่าง รวม 5.3.7–5.3.25) — การจับคู่เลข ↔ เนื้อหาในตารางจึงเป็นที่ยืนยันแล้วทั้งหมด

สรุปผล

โปรเจกต์ judes-note ตอบแกน functional ของ requirement ได้ค่อนข้างเต็ม — การ annotate บนเอกสาร PDF, bookmark ต่อหน้าเอกสาร, Text Box + Freehand Drawing, ลบ/แก้ไขความเห็น, แสดงผลรายการ, ใช้งานหลายคนพร้อมกันแบบ realtime, responsive และรองรับ tablet/iPad

แต่ requirement ฉบับนี้เขียนสำหรับระบบ production เต็มรูปแบบ ขณะที่ judes-note เป็น MVP เฟสแรกตามขอบเขตใน CLAUDE.md / docs/PLAN.md — ข้อที่ขาดส่วนใหญ่จึงแบ่งได้เป็น 2 กลุ่ม: (1) ของที่ตั้งใจไม่ทำในเฟสแรก (auth, API, integration) และ (2) ของที่เกือบมีแต่ต่างรายละเอียด (ค้นหาไม่ครอบ bookmark, ลบ bookmark ทีละรายการ) รวมถึง (3) ของใหม่ที่ไม่เคยอยู่ในแผน (รองรับไฟล์รูปภาพ)

สถานะ ความหมาย
✅ มีและตรงตาม requirement
⚠️ มีบางส่วน / ใกล้เคียงแต่ต่างรายละเอียด
❌ ไม่มีในโปรเจกต์

1. ภาพที่ 1 — ข้อ 5.3.1–5.3.6 (คุณลักษณะหลักของระบบ)

5.3 พัฒนาระบบบันทึกความเห็นของกรรมการ (Judges' Notes System) มีคุณลักษณะดังต่อไปนี้

Requirement สถานะ รายละเอียดในโปรเจกต์
5.3.1 เรียกดูเอกสารที่เกี่ยวข้องและตรวจสอบจากระบบงานคดีปกครองได้โดยตรง ⚠️ ตัว viewer แสดงไฟล์ PDF ที่ระบุใน DB ได้ แต่ไม่มีการเชื่อมต่อระบบงานคดีปกครอง (ไม่มี integration/API ดึงเอกสารโดยตรง) และไม่มีหน้า upload — หน้า / อ่านรายการจาก DB เท่านั้น (sample data seed ด้วย SQL) — ผูกกับ gap 5.3.14 (API) และ 5.3.16 (integrate)
5.3.2 ระบบต้องไม่สามารถแก้ไขไฟล์ต้นฉบับได้ (Non-Destructive) ✅ เป็น invariant หลักของโปรเจกต์ (CLAUDE.md ข้อ 1): annotation เก็บใน DB เป็นพิกัด % เท่านั้น, ไฟล์ PDF ใน public/ ถูกอ่านอย่างเดียวผ่าน path guard (lib/server-pdf.ts), export PDF (F8) สร้างไฟล์ใหม่จากสำเนาในหน่วยความจำ (pdf-lib load แล้ว save คืน bytes ใหม่) — ไม่เขียนทับต้นฉบับเด็ดขาด
5.3.3 จัดเก็บข้อมูล Bookmark แยกจากเอกสารโดยเก็บไว้ในฐานข้อมูล และสามารถนำข้อมูลดังกล่าวมาแสดงได้ ✅ เป็นสถาปัตยกรรมแกนกลางของโปรเจกต์ (invariant #1–2): bookmark เก็บใน PostgreSQL ตาราง bookmarks เป็นพิกัด/ข้อมูลล้วน (pageIndex, ชื่อ, โครงสร้าง parent_id) แยกจากไฟล์ PDF ใน public/ — นำกลับมาแสดงได้ทั้งแท็บ Bookmarks ใน sidebar (scroll ไปหน้านั้น), หน้าสรุป F15 และ export
5.3.4 รูปแบบเอกสารที่รองรับได้ — ไฟล์เอกสาร PDF และไฟล์รูปภาพ (jpg, jpeg, png, tif) เป็นอย่างน้อย ❌ รองรับ PDF เท่านั้น — viewer ใช้ pdfjs-dist ล้วน ไม่มีการรับไฟล์รูปภาพ (ไม่เคยอยู่ในแผน)
5.3.5 บันทึกความเห็น (Bookmark) ทั้งแบบกรอกข้อความ (Text Box) และเขียนด้วยมือ (Freehand Drawing) ✅ TEXTBOX (F17) + DRAW freehand ดินสอ/ไฮไลต์เตอร์ + รองรับสไตลัส pressure (F7)
5.3.6 เพิ่ม ลบ แก้ไขความเห็นในกล่องข้อความได้ ✅ TEXTBOX (F17): สร้างกล่องข้อความ + แก้ไขข้อความในกล่องโดยตรง (editor รองรับตัวหนาบางส่วน — rich text) + ลบ/ย้าย/ปรับขนาด ของตัวเอง (F1, F13)

2. ภาพที่ 2 — ข้อ 5.3.7–5.3.25 (รายละเอียด bookmark + ข้อกำหนดระบบ)

Requirement สถานะ รายละเอียดในโปรเจกต์
5.3.7 เพิ่ม แก้ไข ลบ ข้อความที่เขียนหรือวาดได้ เช่น สีหรือขนาด ✅ ครบทั้งวงจร: สร้าง annotation ทุกชนิด (HIGHLIGHT/DRAW/SHAPE/TEXTBOX/STAMP) + แก้ไขสี/ความหนา/ขนาด ผ่านแผง selection (F1 — AnnotationSelectionLayer: แถบสี + ความหนา, TEXTBOX ปรับ fontSize ได้) + ย้าย/ปรับขนาด + F13 แก้ไขข้อความ + ลบของตัวเอง + F19 version history
5.3.8 ข้อมูลบันทึก bookmark ต้องอ้างถึงไฟล์เอกสาร หน้าเอกสาร วันที่บันทึก และผู้บันทึก ✅ ตาราง bookmarks มีครบทั้ง 4: file_id (FK → ไฟล์เอกสาร), page_index (หน้าเอกสาร), created_at (วันที่บันทึก), user_id (ผู้บันทึก) — นำมาแสดงในแท็บ Bookmarks, หน้าสรุป F15 และ export
5.3.9 กำหนดความเป็นส่วนตัวของ bookmark: ส่วนบุคคล (Private) / กลุ่ม (Group) ❌ ไม่มี Private/Group visibility — ทุกคนเห็นทุกรายการ (ไม่มี auth/roles โดยเจตนา)
5.3.10 แสดง bookmark ของเอกสารแต่ละไฟล์ หรือชุดของเอกสารได้ ⚠️ รายไฟล์ ✅ — แท็บ Bookmarks ใน sidebar แสดง bookmark ทั้งหมดของไฟล์ที่เปิด (ผูก file_id) + หน้าสรุป F15 / แต่ชุดของเอกสาร ❌ — ไม่มี concept การจัดกลุ่มไฟล์ (document set) และไม่มีหน้าแสดง bookmark รวมข้ามหลายไฟล์
5.3.11 แสดง bookmark ตามลำดับหน้าได้ ⚠️ แท็บ Bookmarks แสดงเลขหน้าต่อรายการ ("หน้า N") แต่เรียงตามเวลาสร้าง ไม่ใช่ลำดับหน้า (AnnotationSidebar.tsx:753 — root เรียงตามเวลาสร้าง) และหน้าสรุป F15 ไม่มี bookmark — แก้ง่าย: sort roots ของต้นไม้ตาม pageIndex
5.3.12 สามารถกำหนดเงื่อนไขการค้นหา bookmarks ได้ ❌ ช่องค้นหา (F14) ครอบเฉพาะ annotations เท่านั้น (searchAnnotations query ตาราง annotations) — ค้นหา bookmark ยังไม่ได้เลย ยิ่งไม่มีการกำหนดเงื่อนไข (เช่น ตามหน้า/ผู้บันทึก/ช่วงวันที่)
5.3.13 แสดงผลรายการหน้าของเอกสารที่ bookmark ไว้ ✅ แท็บ Bookmarks ใน sidebar + หน้าสรุป (F15)
5.3.14 จัดทำชุด API ดึงข้อมูล bookmark สำหรับเชื่อมต่อระบบอื่น ❌ ไม่มี REST API ภายนอก — มีเฉพาะ SSE stream ภายใน + export routes สำหรับผู้ใช้ (F11 export/import JSON ถูกถอดออกจากโค้ดแล้ว)
5.3.15 ส่งออก (Export) รายการ bookmark เป็น PDF ⚠️ ใกล้เคียง: export PDF ฝัง annotation + bookmark เป็น PDF outline (F8 — app/api/annotations/export/route.ts) + export CSV สรุปรายการ (F16) — แต่ไม่ใช่ "รายงานรายการ bookmark" แบบเอกสาร PDF ตรง ๆ
5.3.16 หน้าจอเชื่อมต่อกับระบบอื่น (Integrate) เป็น modal หรือ iframe ❌ เป็น standalone Next.js app — ไม่มีโหมด embed
5.3.17 รองรับ Web Browser: Google Chrome, Microsoft Edge, Safari ✅ Web app มาตรฐาน — ทดสอบ desktop + iOS/Android แล้ว
5.3.18 ใช้งานบน Tablet, iPad — Web Application ภาษา HTML5 ✅ Touch support เต็มรูปแบบ: ไฮไลต์ผ่านปุ่มลอย, ลาก handles, วาดด้วยนิ้ว (commit b3b884c)
5.3.19 Responsive แสดงผลได้ทุกความละเอียดหน้าจอ ✅ sidebar จอกลาง/จอเล็ก, PDF fit จอเล็ก, ปุ่มขนาด touch-44px (commit 1c2f4c8)
5.3.20 ใช้งานหลายผู้ใช้พร้อมกัน (Multi-user) จากหลายเครื่อง ✅ Realtime sync ผ่าน SSE (hooks/useAnnotationRealtime.ts) — แก้ไข/ลบ ของใครของมันบนไฟล์เดียวกันได้พร้อมกัน
5.3.21 การรับรองตัวผู้ใช้งาน (Authentication) ❌ ไม่มีระบบ auth — anonymous identity จาก localStorage โดยเจตนา (out of scope ตามแผน)
5.3.22 ใช้งานร่วมกับระบบงานอื่นผ่าน API ❌ ไม่มี
5.3.23 ติดตั้ง On-Premise บน Server ภายใน หรือ Cloud ⚠️ สถาปัตยกรรม Next.js + PostgreSQL deploy ได้ทั้งสองรูปแบบทางเทคนิค แต่ไม่มีข้อกำหนด/packaging พิเศษ (หมายเหตุ: SSE pub/sub เป็น in-memory — รันหลาย instance ต้องเพิ่ม Redis/LISTEN-NOTIFY ก่อน)
5.3.24 รองรับมาตรฐานความมั่นคงปลอดภัยของหน่วยงาน ❌ ไม่มี auth/audit log/encryption policy — ไม่ตอบโจทย์ในระดับนี้
5.3.25 ระบบมีความพร้อมในการให้บริการ (Availability) อย่างน้อย 99.5% ตลอดเวลาการให้บริการ ⚠️ ยังไม่มีการออกแบบเรื่อง SLA/uptime — ไม่มี health check, monitoring, แผน failover/backups — เป็นข้อกำหนดระดับ infrastructure (กลุ่ม D) ที่ต้องออกแบบตอนวางระบบ production จริง

3. สรุป Gap รายกลุ่ม

กลุ่ม A — ของที่ out of scope โดยเจตนาตามแผนเฟสแรก

ข้อที่ต้องเปลี่ยนขอบเขตโปรเจกต์ + ออกแบบเพิ่มก่อน implement:

  • Authentication ผู้ใช้งาน + ระบบสิทธิ์ (5.3.21, 5.3.24)
  • Private/Group visibility ของ bookmark (5.3.9)
  • ชุด API สำหรับระบบภายนอก (5.3.14, 5.3.22)
  • โหมด Integrate แบบ modal/iframe (5.3.16)
  • เรียกดูเอกสารจากระบบงานคดีปกครองโดยตรง (5.3.1)

กลุ่ม B — ฟังก์ชันที่มีอยู่แล้ว ต่อยอดเล็กน้อยได้เลย

งานขนาดเล็ก–กลาง ไม่กระทบสถาปัตยกรรม:

  • ค้นหา bookmark พร้อมเงื่อนไข (5.3.12) — เพิ่มการค้นหาตาราง bookmarks (ชื่อ/โน้ต) + รองรับเงื่อนไขเช่นหน้าเอกสาร/ผู้บันทึก/ช่วงวันที่
  • เรียง bookmark ตามลำดับหน้า (5.3.11) — sort roots ของต้นไม้ bookmark ตาม pageIndex แทนเวลาสร้าง
  • รายงานรายการ bookmark เป็น PDF (5.3.15) — ต่อจากหน้าสรุป F15 หรือ export route เดิม

กลุ่ม C — ของใหม่ที่ไม่เคยอยู่ในแผน

  • รองรับไฟล์รูปภาพ jpg/jpeg/png/tif (5.3.4) — กระทบ viewer เป็นวงกว้าง (pdfjs-dist อ่าน PDF เท่านั้น ต้องเพิ่ม image viewer path แยก + คิดเรื่องพิกัด % ของหน้ารูปภาพ)
  • ชุดของเอกสาร (document set) + แสดง bookmark รวมหลายไฟล์ (5.3.10) — ต้องเพิ่ม data model จัดกลุ่มไฟล์ + หน้ารวม bookmark ข้ามไฟล์ (ตอนนี้ไฟล์เป็นลิสต์แบนหน้าเดียว)

กลุ่ม D — infrastructure (ระยะยาว)

  • On-Premise/Cloud packaging (5.3.23) — รวมถึงเตรียม multi-instance สำหรับ SSE
  • มาตรฐานความปลอดภัยของหน่วยงาน (5.3.24) — ผูกกับ auth ในกลุ่ม A
  • Availability ≥ 99.5% (5.3.25) — SLA/uptime, monitoring, failover, backup ระดับ production

4. ข้อเสนอแนะลำดับความสำคัญ

  1. ทำกลุ่ม B ก่อน — คุ้มค่าต่อแรง เห็นผลไว เสริมฟีเจอร์ bookmark ให้ครบ requirement โดยไม่แตะสถาปัตยกรรม
  2. ตัดสินใจเรื่องรูปภาพ (กลุ่ม C) — เป็น requirement ที่ชัดเจนใน 5.3.4 แต่แพงที่สุดในเชิงโครงสร้าง ควรตัดสินใจก่อนว่าจะอยู่ในขอบเขตจริงไหม
  3. กลุ่ม A ตามด้วย D — ต้องอัปเดต docs/PLAN.md ขยายขอบเขตอย่างเป็นทางการก่อน implement ตามกระบวนการของโปรเจกต์