Your Name
|
0aef3ff028
|
export+sidebar: กรองตามรายคนที่เลือกดูครบทั้งจอและ export + REDACTION คงไว้เสมอ (คำขอผู้ใช้ 2026-09-22)
export PDF (F8):
- route รับ ?user=<userId> เพิ่ม: กรอง annotation ตาม userId นั้น ยกเว้น REDACTION
ติดไปเสมอ (D4 — กล่องดำหาย = เนื้อหาที่ปิดกั้นกลับมาอ่านได้) และ bookmarks → PDF
outline กรองตามผู้บันทึกด้วย (หัวข้อแม่โดนกรองแต่ลูกยังอยู่ ลูกขึ้น root ตามตรรกะ
buildOutline เดิม) ไม่ส่ง param = ทั้งหมด เหมือนเดิม
- ชื่อไฟล์เติมชื่อผู้ใช้ท้าย: <title>-annotated-<ชื่อ>.pdf — ชื่อจาก user_name ที่
mirror ในตาราง (ไม่รับ text จาก client) ผ่าน encodeRFC5987 รองรับชื่อไทย
- PDFViewer handleExportPdf: resolve filter ปัจจุบันก่อนยิง route (mine →
user.userId) ส่ง &user= เมื่อไม่ใช่ ทุกคน
จอ (F4):
- visibleAnnotations คง REDACTION ของทุกคนไว้เสมอแม้กรองดูของคนอื่น — สูตรเดียวกับ
export: กันเนื้อหาที่ปิดกั้นกลับมาอ่านได้บนจอ (เดิมหายไปตาม filter) และจอตรงกับ
ไฟล์ export / ผลค้นหา F14 (visibleSearchResults) ใช้สูตรเดียวกัน
- sidebar แท็บ Bookmark กรองตามเจ้าของหมายเหตุเหมือน annotation (เดิม F4 คุมแค่
annotation — bug report 2026-09-22): ต้นไม้ ตามหัวข้อ มุมมอง ตามหน้า ตัวเลข
แท็บ และ badge จำนวนลูก ใช้ visibleBookmarks ชุดเดียวกัน — ลูกที่แม่โดนกรองขึ้น
root เหมือน export; empty state แยก ไม่มีที่คั่นหน้าของเจ้าของหมายเหตุที่เลือก
ออกจากไฟล์ว่างจริง
- popup ย้ายหัวข้อ (movableTo) และ bookmarkById ยังเห็นต้นไม้เต็ม — ย้ายไปใต้หัวข้อ
ของคนอื่นได้ตามเดิม
verify: tsc + Playwright e2e (สร้าง redaction จริงเป็น user1 → สลับ user3 กรองของ
ตัวเอง: rect ดำของ user1 ยัง render ครบ, tab Bookmark (10)→(2) และแถวต้นไม้ 2 ตรง
DB เป๊ะ, ลบ redaction ทดสอบทิ้งจน DB เหลือ 0) + export จริง 4 filter นับ PDF outline
ตรงจำนวน bookmarks ของผู้ใช้นั้นใน DB ทุกแบบ — sync docs/PLAN-FEAT.md §F8
Co-Authored-By: Claude Code <noreply@anthropic.com>
|
2026-09-22 15:34:37 +07:00 |
|
Your Name
|
e0c78d68fe
|
bookmark: ดักความยาวชื่อ/โน้ตที่ช่องกรอก + F19 สรุปสิ่งที่เปลี่ยนใน dialog ประวัติ + formatThaiDate — (1) bookmark limits: utils/bookmark-limits.ts ใหม่เป็น source of truth เดียว (ชื่อ 120/โน้ต 200 ตัวอักษร) server action import ร่วมแทน const ท้องถิ่น + ใส่ maxLength ที่ popup บันทึก bookmark (PDFViewer) และฟอร์มแก้ไข ✏ ใน sidebar ดักทั้งพิมพ์/paste ตั้งแต่ในช่อง ไม่รอ error ตอนกดบันทึก + แก้ off-by-one ของ normalizeBookmarkTitle (เดิม slice 120 แล้วต่อ … = 121 ตัว ทำให้คลุมข้อความยาวแล้วกด B บันทึกเลยโดน limit ของ server ตีกลับทั้งที่ไม่ได้พิมพ์เอง — ตอนนี้ slice 119 + … = 120 พอดีตามสเปก §7 N2 ที่เขียนไว้ ≤ 120 อยู่แล้ว) + PLAN-FEAT.md §7 N2 บันทึกเพิ่ม — (2) งานคู่ขนาดจากอีก session (แชร์ไฟล์ PDFViewer/sidebar เลยรวม commit): dialog ประวัติ F19 แสดงสรุปสิ่งที่เปลี่ยนต่อรอบผ่าน describeAnnotationChange ใหม่ใน utils/annotation-display.ts (เทียบ snapshot ก่อนแก้ v.data กับ state ถัดไป — snapshot รอบใหม่กว่า หรือค่าปัจจุบันจาก realtime lookup สด historyCurrent — สรุปเป็นหน่วยเดียวกับตัวปรับ UI: ความหนา ×10 ความทึบ % fontSize px ชื่อสี preset ย้าย/ปรับขนาดจาก bbox ผลต่างเกิน GEOM_EPS_PCT 0.5% ข้อความ/โน้ต/label) + dialog ขยาย w-96 max-h-[60vh] แถวเปลี่ยน items-start + utils/date-format.ts ใหม่ formatThaiDate วันที่ไทยเต็ม "18 กันยายน พ.ศ. 2569" (+เวลา) แทน toLocaleString("th-TH") ทุกจุดแสดงวันที่ใน UI (หน้ารายการไฟล์ sidebar ประวัติ/รายการ timestamps ใน PDFViewer) กัน server/client locale ไม่ตรงกัน + tests ใหม่/ขยาย (date-format + describeAnnotationChange) — CLAUDE.md sync โครงสร้าง utils — verify: tsc strict ผ่าน + vitest 139/139 ผ่าน
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 43s
Deploy eCourt Note Web to Server / Deploy eCourt Note Web to Server (push) Successful in 3s
Deploy eCourt Note Web to Server / Notify Deployment Status (push) Successful in 1s
Co-Authored-By: Claude Code <noreply@anthropic.com>
|
2026-09-17 17:02:31 +07:00 |
|
Your Name
|
fa880b314e
|
BASE_PATH: serve ใต้ /docedit/note — next.config.mjs ตั้ง basePath + env NEXT_PUBLIC_BASE_PATH (ประกาศค่าเดียวที่ไฟล์นี้) ให้ utils/base-path.ts (ใหม่) withBasePath() เติม prefix ให้ URL ฝั่ง browser ที่ Next ไม่เติมให้เอง (fetch/EventSource/plain href/workerSrc/img src): PDFViewer (workerSrc, /api/pdf ซ่อม ToUnicode, fallback file.pdfUrl, image branch N3 รวบเป็นตัวแปร fileUrl, export PDF F8), SSE stream ใน useAnnotationRealtime, ปุ่มส่งออก bookmark JSON (N7) + คัดลอกลิงก์ F12 ใน AnnotationSidebar (window.location.origin + basePath กัน paste แล้ว 404), Export CSV (F16) หน้า summary — <Link>/next/navigation/middleware.ts ไม่ต้องแก้ (Next 14.2 auto-prefix ให้ + matcher จับ path ที่ตัด basePath แล้ว + NextURL redirect ใส่กลับเอง ยืนยันจาก source ใน node_modules) + pdf_url ใน DB เก็บ path ไม่รวม basePath เติมตอนใช้เท่านั้น + sync เอกสารตาม governance: CLAUDE.md invariant #6 (workerSrc ผ่าน withBasePath) + #12 ใหม่ (URL ฝั่ง browser ที่สร้างเองต้องผ่าน withBasePath), PLAN.md A3/§4, rules pdf-viewer/realtime, plan-reviewer #8, README URL localhost:3000/docedit/note — verify: tsc strict ผ่าน + curl (root / 404, ไม่มี cookie 307→/docedit/note/login, worker 200, SSE reachable, มี cookie 200) + Playwright login จริงเปิดไฟล์ 44 หน้า render ครบ (SSE /api/pdf /worker 200 ผ่าน basePath) + code-reviewer ผ่าน (vitest 126 tests, ไม่พบ bug, blob URL ไม่โดน prefix ซ้ำ, env inline ครบทั้ง client/server ตาม define-env-plugin) — deploy: basePath เป็น build-time ต้อง build image ใหม่ถึงจะเสิร์ฟที่ /docedit/note + reverse proxy ต้อง forward path เต็มแบบไม่ strip prefix
Deploy eCourt Note Web to UAT Server / Validate Database Schema (Drizzle) (push) Successful in 3s
Deploy eCourt Note Web to UAT Server / Build Web Docker Image (push) Successful in 48s
Deploy eCourt Note Web to Server / Validate Database Schema (Drizzle) (push) Successful in 3s
Deploy eCourt Note Web to UAT Server / Deploy eCourt Note Web to UAT Server (push) Successful in 2s
Deploy eCourt Note Web to Server / Build Web Docker Image (push) Successful in 48s
Deploy eCourt Note Web to UAT Server / Notify Deployment Status (push) Successful in 1s
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 0s
Co-Authored-By: Claude Code <noreply@anthropic.com>
|
2026-09-17 16:06:20 +07:00 |
|
Your Name
|
6940b3870d
|
docs: ร่างแผน N8 ชุดเอกสาร (Document Set) + bookmark รวมทั้งชุด — ปิด gap 5.3.10 ครึ่งหลัง ("หรือชุดของเอกสาร"): ตาราง document_sets + files.set_id nullable (ไฟล์หนึ่งอยู่ชุดเดียว onDelete set null — ลบชุดไฟล์ไม่หาย คนละเรื่องกับ CASCADE ของ annotations) + หน้าใหม่ /sets/[id] bookmark รวมทุกไฟล์ของชุดคลิกกระโดดผ่าน deep link F12 + จัดการชุดบนหน้ารายการ (สร้าง/ย้ายเข้า-ออก/แก้ชื่อ/ลบ — ทุกคนที่ login จัดการได้ roles ยัง out of scope ตาม 5.3.23) — ยังไม่ implement (เสนอ 2026-09-17 รอ /implement-feat N8 ตาม governance: ต้องเขียนสเปกลง PLAN-FEAT.md §7 + ขยาย whitelist ใน CLAUDE.md ก่อน)
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 41s
Deploy eCourt Note Web to Server / Deploy eCourt Note Web to Server (push) Successful in 3s
Deploy eCourt Note Web to Server / Notify Deployment Status (push) Successful in 0s
Co-Authored-By: Claude Code <noreply@anthropic.com>
|
2026-09-17 13:43:16 +07:00 |
|
Your Name
|
55d09ce5c3
|
N7 ส่งออกรายการ bookmark เป็น JSON แทนรายงาน PDF (เปลี่ยน deliverable ตามคำขอผู้ใช้ 2026-09-17) — route /api/bookmarks/export เขียนใหม่จาก PDFDocument.create ทั้งชุด (ฟอนต์ Sarabun/layout A4/แบ่งหน้า/ต้นไม้ indent 3 ระดับ รวม ~190 บรรทัด) เป็น JSON ข้อมูลล้วนจาก DB: validate fileId (UUID → 400) + ไม่พบไฟล์ = 404 → query bookmarks ทั้งไฟล์ orderBy pageIndex → yOffset → createdAt (ลำดับ N5 เดียวกับ sidebar) → envelope { fileId, title, exportedAt (ISO), bookmarks: BookmarkDTO[] } ผ่าน toBookmarkDTO ตรง ๆ (invariant #5) เก็บ parentId ครบ lossless (reconstruct ต้นไม้จากข้อมูลเองได้) จึงถอด build tree/cycle guard/ฟอนต์/layout ทิ้งหมด; pretty-print 2 space + content-type application/json; charset=utf-8 + attachment filename* จาก encodeRFC5987("{title}-bookmarks.json") (pattern F8/F16); 0 bookmark = "bookmarks": [] ไม่ 404 (ปุ่มทำงานเสมอ); ไม่โหลดไฟล์เอกสารต้นฉบับเลย (invariant #1) + read-only ไม่ publish event ไม่ revalidatePath + ปุ่มท้ายแถว toggle เงื่อนไขค้นหา N6 ในแท็บ "ที่คั่นหน้า" เปลี่ยนไอคอน Download → Braces ({ }) พร้อม title/aria-label "เป็น JSON" (ยังเป็นลิงก์ธรรมดา pattern Export CSV F16 — ส่งออกทุก bookmark ของไฟล์เสมอ ไม่ผูกเงื่อนไขค้นหา N6) + PLAN-FEAT.md §7 N7 เขียนสเปกใหม่เป็น JSON + PLAN-BOOKMARK-PDF.md ติด note หัวไฟล์ว่าโค้ด PDF ในแผนเป็น historical record (สเปกปัจจุบันอยู่ PLAN-FEAT) + gap-analysis ปิด gap กลุ่ม B 5.3.11 ✅ (N5) 5.3.12 ✅ (N6) 5.3.14 ✅ (API นี้) 5.3.15 ✅ (export PDF ของ F8 ฝัง bookmark เป็น outline ติดไปกับไฟล์) พร้อม header อัปเดตล่าสุด 2026-09-17 — ไฟล์เดียวกันมี 5.3.19/5.3.22 ✅ mock login/5.3.23 ของงาน login ตามไปด้วย
Co-Authored-By: Claude Code <noreply@anthropic.com>
|
2026-09-17 13:43:00 +07:00 |
|
Your Name
|
65b72cf817
|
mock login e-Court หน้า /login + identity จาก cookie oacCase แทน localStorage — dropdown ผู้ใช้ MOCK_USERS (user1–user5, utils/user.ts pure module ให้ client+server ใช้ร่วม) รหัสผ่านกลาง Demo1234 ผ่าน server action login (เช็ครายชื่อฝั่ง server เป็น defense กัน hand-craft + delay 500ms ให้เห็น "กำลังตรวจสอบ…") ตั้ง cookie oacCase ตาม format จริงของระบบศาล 16 field — u_userid/u_userlogin ต่างกันต่อคน (= ชื่อผู้ใช้) เพื่อให้สิทธิ์ "แก้ไขได้เฉพาะของตัวเอง" (guard ด้วย userId) แยกกันจริงทั้ง 5 คน httpOnly/sameSite lax/8 ชม. + middleware.ts บังคับ login ทุกหน้า (parse จริงด้วย parseOacCase ไม่ใช่แค่มี cookie — ขยะ/ว่าง/ขาด field = redirect /login; matcher ยกเว้น /login, /api/*, /uploads/*, _next และ static ใน public/ — SSE/export จึงไม่โดน 302) + lib/session.ts getSessionUser อ่าน identity ฝั่ง server ใช้ในทุกหน้า (defense ซ้อน middleware) + PDFViewer รับ user เป็น prop จาก annotate page ตั้งแต่ first paint (หมดช่วง null user ที่เคยสร้าง annotation ด้วย userId="" ได้ + ไม่มี hydration mismatch; Server Actions ไม่ต้องแก้ — vString รับ userId ใหม่อยู่แล้ว) + SessionBar แสดง "เข้าสู่ระบบเป็น <user>" + ปุ่มออกจากระบบ (ลบ cookie ด้วย path "/" ตรงตอน set + redirect ใน action เอง — client router.replace เองชนกับ re-render ของหน้าที่เพิ่งเสีย session จน navigation ไม่เกิด) แทน UserPicker mock 10 คน (ลบไฟล์พร้อม MOCK_USERS/localStorage/getLocalUser ทั้งชุด) + LoginForm การ์ด max-w-sm กลางจอ reuse brand lockup และปุ่ม primary เดิม, input text-base 16px กัน iOS zoom บน iPad, dropdown placeholder "เลือกผู้ใช้" บังคับเลือก (ไม่ preselect กัน login ผิดคนโดยไม่ตั้งใจ), error แถบเดียว role=alert "รหัสผ่านไม่ถูกต้อง" (dropdown เลือกผิดไม่ได้แล้ว), ตอนผิดล้าง password คงผู้ใช้ที่เลือกไว้ + focus+select + tests/utils/user.test.ts ล็อก format จริงของ e-Court (parse ตัวอย่าง cookie จริง 235821/tu_2, garbage/empty/ขาด field → null, round-trip, buildOacCaseCookie ครบ 16 field) + sync CLAUDE.md/PLAN.md §0 A4/README — annotation สมัย mock-user-01/UUID ไม่ใช่ของตัวเองอีก (auth จริงเทียบระบบศาล + roles ยัง out of scope; /api/* และ /uploads/* ยังไม่ต้อง login ตามขอบเขต mock)
Co-Authored-By: Claude Code <noreply@anthropic.com>
|
2026-09-17 13:41:02 +07:00 |
|
Your Name
|
460cd9c600
|
N7 รายงานรายการ bookmark เป็น PDF (requirement 5.3.15): route /api/bookmarks/export สร้างเอกสารใหม่ล้วนด้วย PDFDocument.create (ไม่โหลดไฟล์ต้นฉบับเลย — invariant #1) ต้นไม้ indent 3 ระดับเรียงตาม N5 + หัวรายงาน + แบ่งหน้าต่อบรรทัด + footer หน้า n จาก N + cycle guard (seen ร่วมทุก root เติมโหนดนอก root เป็นระดับ 1) + 0 bookmark = หน้าเดียวมีข้อความแจ้ง + ปุ่ม Download ท้ายแถว toggle เงื่อนไขค้นหาในแท็บ "ที่คั่นหน้า" (ลิงก์ธรรมดา pattern F16) + export F8: outline bookmark เรียงตามลำดับหน้าเหมือน sidebar (N5: pageIndex→yOffset→createdAt แทน createdAt เดี่ยว) + ถอด drawNoteBox กลับเป็น sticky note annotation อย่างเดียวตามสเปก §F8 ไม่วาดข้อความ flatten ทับหน้ากระดาษ (กล่องเหลืองแบนทับเนื้อหาเอกสาร — ผู้ใช้ตัดสินใจ; tooltip ตัดไทยใน Chrome เป็น bug ฝั่ง PDFium) + แผง selection ของ COMMENT/REDACTION ที่ไม่มี row สไตล์หุบเป็น w-fit ปุ่ม bookmark/ลบติดกันคั่นเส้นแนวตั้ง
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 49s
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
Co-Authored-By: Claude Code <noreply@anthropic.com>
|
2026-09-17 10:09:57 +07:00 |
|
Your Name
|
a4cac15e42
|
fix(deploy): อัปโหลด/เปิดไฟล์ใน Docker ไม่ได้ — 3 จุดรวมกัน
- app/uploads/[name]/route.ts: Next production (next start/standalone) อ่านรายชื่อ
public/ เก็บใน Set ครั้งเดียวตอน startup เท่านั้น ไฟล์ที่ uploadFile เขียน
ตอน runtime GET /uploads/* แล้ว 404 (dev ไม่ผ่าน branch นี้ = local ผ่าน
Docker พัง) → เสิร์ฟผ่าน route handler แทน: path guard lib/server-pdf +
whitelist ext + content-type จาก utils/file-kind + cache immutable
- drizzle/0001: bookmarks.user_name (N6) + backfill ตาม PLAN-BOOKMARK.md —
image ใช้ migrate.mjs จากไฟล์ SQL ไม่ใช่ drizzle push ของ dev ทำให้ schema
ตกรุ่นจนหน้า annotate 500 ทั้งหน้า; แก้ schema.ts ครั้งต่อไปต้อง drizzle-kit
generate ทุกครั้ง (กติกาใหม่ใน .claude/rules/data-layer.md)
- docker/web.Dockerfile: mkdir public/uploads + chown nextjs — volume ที่
compose mount ทับได้ ownership จาก image (ไม่งั้น root เป็นเจ้าของ = EACCES)
+ .dockerignore กัน public/uploads ของเครื่อง dev ติดไปใน image
- docker-compose.test.yml: compose ทดสอบบนเครื่อง (port 6704 + volume uploads)
verify บน Docker จริง: migration apply บน DB เดิมได้, annotate 500→200,
Playwright อัปโหลด JPG+PDF→เปิด viewer ได้ 7/7, tsc ผ่าน, vitest 120/120
Co-Authored-By: Claude Code <noreply@anthropic.com>
|
2026-09-16 15:59:01 +07:00 |
|
Your Name
|
a020e96bda
|
bookmark เรียงตามลำดับหน้า (N5) + ค้นหา bookmark พร้อมเงื่อนไข คำค้น/ช่วงหน้า/ผู้บันทึก/ช่วงวันที่ พร้อม bookmarks.user_name (N6) + UX audit sidebar 2026-09-16: เมนู ⋯ แทนไอคอนชุดติดกัน, มุมมองรอง ตามหน้า หัวกลุ่มหุบได้, focus ring, ปุ่ม sidebar จิ้มง่าย >=32px, Escape ปิด dialog ประวัติ + แผนใหม่ docs/PLAN-BOOKMARK.md + agent ui-ux-designer แทน ui-designer + skill frontend-design
Co-Authored-By: Claude Code <noreply@anthropic.com>
|
2026-09-16 13:24:33 +07:00 |
|
DESKTOP-1R2VSQH\Lenovo ThinkPad E490
|
9cc38835f0
|
popup ซ้อนกัน/ไม่ปิดตอนกดปุ่ม tool + แท็บที่คั่นหน้ากลับไม่ได้ + งานค้างใน working tree: ไฟล์รูปภาพ annotate ได้ (N3) + อัปโหลดไฟล์ (N4):
Deploy eCourt Note Web to Server / Validate Database Schema (Drizzle) (push) Successful in 2s
Deploy eCourt Note Web to Server / Build Web Docker Image (push) Successful in 40s
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
ส่วนที่ 1 — แก้ popup ตาม bug report ("กดแก้ไขแล้วไปกดที่ tool popup ของแก้ไขไม่ปิด/แสดงซ้อนกัน"):
(1) ปุ่ม tool แบบ dropdown ทั้ง 5 (highlight/draw/shape/stamp/textbox) เรียก switchTool เสมอแม้เป็น tool เดิม — เดิมกดปุ่ม tool ที่ active อยู่จะ toggle เมนูอย่างเดียวไม่เรียก switchTool (ซึ่งเป็นที่เดียวที่เคลียร์ popup บนหน้า: editor/แผง selection/popover) ผลคือ popup แก้ไขค้างเปิด + dropdown เปิดซ้อนขึ้นมาอีกชั้น — ตอนนี้จำ intent เปิด/พับเมนูไว้ก่อนเรียก (switchTool ปิดเมนูทุกตัว) แล้วเปิดคืนเฉพาะที่ตั้งใจ; toggle พับเมนูและกลไกกลืนคลิก M4 เท่าเดิม (mousedown บนปุ่ม mark อยู่แล้ว)
(2) switchTool ปิด popup bookmark ด้วย + openBookmarkComposer ปิดเมนูทั้ง 5 ก่อนเปิด popup (เดิมคีย์ลัด B ระหว่างเมนูเปิด = สอง popup ซ้อนกัน)
(3) คลิกหน้าว่าง = ปิด popover ของ comment pin + เลือกรายการอื่น/goToAnnotation ปิด popover เดิมทิ้ง (เดิมปิด popover ได้แค่กด pin เดิม/Escape/สลับ tool)
(4) COMMENT ที่เปิด popover อยู่ไม่ render กรอบ selection/แผงเครื่องมือ — bbox ของ COMMENT ครอบพื้นที่ pin พอดี แผงจะทับ popover และแถบ handle บังการคลิก (sidebar ยังตาม selectedId ไฮไลต์เหมือนเดิม)
(5) แก้แท็บ sidebar ตาม bug report ("เลือก Annotation แล้วจะกลับไป tabs bookmarks ไม่ได้"): effect เดิม dep รวม tab และบังคับ setTab ไปแท็บ annotations ทุกครั้งที่รันตราบ selectedId ไม่ null ทำให้กดแท็บที่คั่นหน้าแล้วถูกดึงกลับทันที — ใช้ ref จำ id ที่ประกาศแล้ว บังคับสลับเฉพาะตอน selectedId เพิ่งเปลี่ยน เคลียร์เป็น null ตอน deselect ให้เลือกรายการเดิมซ้ำภายหลังยังสลับแท็บให้ ส่วน scroll แถวตอนเปิดแท็บหมายเหตุคงเดิม
- sync rules/pdf-viewer.md: กติกาใหม่ popup บนหน้าเปิดได้ทีละชุดห้ามค้างเปิดซ้อนกัน (ปุ่ม dropdown เรียก switchTool เสมอ + วงจรปิด popover/แผง) และยกเว้น markMenuClosed ของคีย์ B ในกติกา M4
- verify: tsc ผ่าน, vitest 120/120, Playwright 18 เคสผ่าน (repro ตรงตามรายงาน: สร้าง textbox → แก้ไขข้อความ → กดปุ่ม tool เดิม → editor+แผงปิด+เมนูใช้ได้; popover pin ไม่ซ้อนแผง/ปิดด้วยคลิกหน้าว่าง; popup bookmark ปิดตอนสลับ tool; แท็บที่คั่นหน้ากลับได้)
ส่วนที่ 2 — งานที่ค้างใน working tree ก่อนหน้า (ตามแผน docs/PLAN-IMAGE.md):
- N3 รองรับไฟล์รูปภาพ jpg/jpeg/png/tif เป็นเอกสาร annotate ได้ครบทุกชนิด (viewer render img แทน canvas ไม่มี textLayer, scale contract เดียวกับ export) + TIFF หลายเฟรม = หลายหน้า (decode ผ่าน utif2 dynamic import → PNG blob URL ต่อเฟรม ฝั่ง client) + export PDF ฝังรูป (utils/image-to-pdf.ts: embedJpg/embedPng + EXIF rotate) + utils/file-kind.ts derive ชนิดไฟล์ + tests ของทั้งสอง utils
- N4 อัปโหลดไฟล์ PDF/รูป ≤100MB ผ่านหน้ารายการ (components/UploadFileForm.tsx + app/actions/files.ts: validate + เขียนไฟล์ใหม่ที่ public/uploads/ เท่านั้น — invariant #1)
- เอกสาร: docs/PLAN-IMAGE.md เพิ่มใหม่ + sync PLAN.md/PLAN-FEAT.md/CLAUDE.md/README/gap-analysis/data-layer rule
Co-Authored-By: Claude Code <noreply@anthropic.com>
|
2026-09-15 14:12:51 +07:00 |
|
DESKTOP-1R2VSQH\Lenovo ThinkPad E490
|
0c4af09e85
|
จอสัมผัส (iOS/Android): ไฮไลต์ด้วย custom selection ลาก→ปล่อย=สร้างทันที แทน native selection + ปุ่มยืนยันลอย (code review ครบ):
Deploy eCourt Note Web to Server / Validate Database Schema (Drizzle) (push) Failing after 3s
Deploy eCourt Note Web to Server / Build Web Docker Image (push) Has been skipped
Deploy eCourt Note Web to Server / Deploy eCourt Note Web to Server (push) Has been skipped
Deploy eCourt Note Web to Server / Notify Deployment Status (push) Successful in 0s
(1) hooks/useCustomSelection.ts (ใหม่): tool highlight บนอุปกรณ์ pointer หลัก coarse ลากเลือกข้อความเองผ่าน Pointer Events ชุดเดียวคุม mouse+touch — pointerdown เก็บ anchor caret (caretRangeFromPoint → caretPositionFromPoint fallback) ยังไม่ทำอะไร → เลย threshold 8px จึง setPointerCapture + เริ่ม select จริง (จับตอนเริ่ม select ไม่ใช่ pointerdown — capture ตั้งแต่กดจะ retarget click ไป container จน tap เลือก annotation/pin ใช้ไม่ได้) → pointerup = commit ทันทีผ่าน commitHighlight เดิม (ห้ามแก้ signature — ไปทาง readTextSelection(pi, { range }) ที่เพิ่ม opts.range ให้อ่าน Range จากภายนอกแทน native selection) — ชดเชย UX ที่หายจาก native: word snap ขอบคำทั้ง anchor/focus (Intl.Segmenter แยกคำไทย dictionary → fallback regex \S+, กลางช่องว่างไม่ขยาย), finger offset อ่าน caret ที่ y−12 เพราะนิ้วบังข้อความ (เฉพาะ pointerType touch), auto-scroll rAF loop เมื่อนิ้วใกล้ขอบบน/ล่าง viewport 60px, live preview rAF throttle (getClientRects → rectsInSweptPath → % + mergeRectsByLine รูปร่างเดียวกับ liveMark ส่งเข้า PdfPage ทดแทนตอนมีค่า customSelPreview ?? liveMark)
(2) กัน "ลากแล้วบางทีไม่ commit" ตาม bug report 3 จุด + code review: การหา caret เป็น 4 ชั้นเรียงตามต้นทุน (resolveTextCaretDeep ใช้เฉพาะ pointerdown กับทั้งจุด y−12 และจุดแตะจริง): caret API + descend หา text node (childNodes[startOffset] + findFirstTextNode DFS) → retry 8 ทิศ ±2/3px → elementsFromPoint เจาะ overlay ไร้ text (SVG ของ InkLayer/มาร์ก/กรอบ) จับ span ใต้จุด → span ของหน้านั้นที่ใกล้สุดแนวตั้ง ≤40px (เกินถือว่าไม่มีข้อความจริง; cache span list ต่อ 1 gesture) — ระหว่างลากทุก rAF frame ใช้เฉพาะ 2 ชั้นถูก หาไม่เจอ (ผ่านพื้นที่ว่าง/ช่องว่างระหว่างหน้า) ให้คง focus เดิมจาก frame ก่อน (lastFocus) ไม่ re-scan / lastRef เคลียร์เฉพาะ pointerdown, finish และเมื่อหน้า anchor โดน virtualization unmount กลางลาก (anchorPageEl.isConnected — กัน commit ของเก่าเงียบ ๆ) — frame ที่ rectsInSweptPath กรองว่าง (ลากเร็ว sample ห่าง/นิ้วสั่นตอนปล่อย) ล้างแค่ preview / ลากล้ำเข้าหน้าถัดไป (range คร่อม 2 หน้า) ห้าม bail — clampToAnchorPage clamp ฝั่ง focus ไปท้ายหน้า anchor (ลากลง) หรือต้นหน้า anchor (ลากขึ้น) boundary cache ต่อ gesture (clampBounds ไม่เดิน TreeWalker ทุก frame) / จุดเส้นทางกรอง rectsInSweptPath ใช้จุด offset เดียวกับ caret (anchorPathPt = จุด probe ที่ resolve anchor + pathEnd = จุด focus หัก 12px) — ใช้พิกัดนิ้ว raw ตรง ๆ จะคลาด 12px จนบรรทัดเป้าหมายโดน lineTol ตัดทิ้ง (ลากขึ้น) หรือมาร์กเกินบรรทัด (ลากลง) เมื่อฟอนต์เล็ก
(3) ถอด path เดิมทั้งหมด: touchConfirm state, touchSelRef/touchSelTimerRef/touchHideTimerRef, debounce 400ms ใน effect selectionchange, handleTouchConfirmHighlight, ปุ่ม "ไฮไลต์ข้อความ" ลอยใต้ selection — desktop (pointer หลัก fine) ใช้ native mouse selection + mouseup commit ตามเดิมไม่เปลี่ยน (enabled = tool highlight + matchMedia coarse) / ระหว่าง enabled ให้ <main> ได้ class .pdf-custom-select (user-select/-webkit-user-select/-webkit-touch-callout: none + touch-action: none กัน browser ยึด gesture เป็น scroll → pointercancel) ถอดทันทีเมื่อเปลี่ยน tool (tool อื่น native selection + long-press copy ของ OS ตามปกติ) + restore user-select:text และ touch-action:auto ให้ input/textarea/contenteditable ใต้ main (reply ของ comment pin ยังเลือก/เลื่อนข้อความในช่องได้)
(4) ย้าย ClientPt + rectsInSweptPath จาก PDFViewer ไป utils/coordinates.ts (hook import ได้โดยไม่ circular) + unit tests rectsInSweptPath 4 เคส (ลากบรรทัดเดียว/ลากขึ้นหลายบรรทัด/บรรทัดนอกเส้นทาง/ไม่ขยับ) / gap-analysis.md แถว 5.3.18 อัปเดตเป็นกลไกใหม่ (รวมงานฉบับแก้ไขข้อความข้อ 5.3.18–5.3.25 ของเจ้าของเอกสารที่ค้างใน working tree) / sync rules/pdf-viewer.md ครบทั้งกลไก 4 ชั้น + path points + กรณีหน้า unmount
verify: tsc ผ่าน + vitest 104/104 + Playwright touch emulation 3 ชุด (รอยต่อ span คำติดกัน gap=0/ขอบซ้าย-ขวาสุดบรรทัด/ช่องว่าง line-height, ลากช้า-เร็ว flick/ล้ำหน้าถัดไปทั้งลงและขึ้น/ขยับต่ำกว่า threshold ไม่สร้าง/tap annotation ได้, จุดว่างใกล้ 20px → commit vs ไกล 46px → ไม่สร้าง) — console.warn ชุด TEMP-DEBUG คงไว้ชั่วคราวตาม protocol รอยืนยันบนมือถือจริง (Safari iOS + Chrome Android) ก่อนถอด
Co-Authored-By: Claude Code <noreply@anthropic.com>
|
2026-09-15 12:13:05 +07:00 |
|
DESKTOP-1R2VSQH\Lenovo ThinkPad E490
|
df0392ea45
|
จอสัมผัส (iOS/Android): แก้ครบตาม UX audit C1+M1–M6 + code review + งาน export PDF ที่ค้างใน working tree:
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
(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 |
|
DESKTOP-1R2VSQH\Lenovo ThinkPad E490
|
6ddc35d6d5
|
เลือก annotation บนหน้า PDF → sidebar ตามไปเน้นรายการนั้น + สร้างเสร็จเลือกให้ทันที + กัน duplicate ชั่วขณะตอนสร้าง: (1) ส่ง selectedId ให้ AnnotationSidebar — ไฮไลต์แถว (ทั้งลิสต์หลักและผลค้นหา) + scrollIntoView block:nearest + สลับมาแท็บ Annotations ให้เองถ้ากำลังอยู่ Bookmarks (rAF รอแถว render หลังสลับแท็บค่อยเลื่อน) (2) AUTO_SELECT_TYPES — สร้าง DRAW/SHAPE/TEXTBOX/STAMP/HIGHLIGHT/REDACTION เสร็จ = เลือกตัวใหม่ทันทีด้วย saved.id (กรอบ selection + sidebar ตามไปเลย; COMMENT ยกเว้นเพราะ composer/pin ทำหน้าที่นั้นอยู่แล้ว) — แก้ปัญหา "วาดเสร็จคลิกที่เส้น tool ยังเป็นวาด sidebar นิ่ง" (3) กันอาการ row โผล่แล้วหาย (0→2→1): เดิม optimistic row กับ row จาก server คนละ id ทำให้ SSE event มาก่อน action เสร็จ dedupe ไม่ได้ — ตอนนี้ client ส่ง id ของ optimistic row ให้ createAnnotation ใช้ซ้ำ (validate UUID, ไม่ส่ง = สุ่มเองตามเดิมสำหรับ redo path) ทุกชั้น dedupe ด้วย id เดียวกันตั้งแต่แรก — sync PLAN.md §4 + rules/realtime.md ให้ตรงพฤติกรรมใหม่
Co-Authored-By: Claude Code <noreply@anthropic.com>
|
2026-09-14 11:35:05 +07:00 |
|
DESKTOP-1R2VSQH\Lenovo ThinkPad E490
|
4934b9d0b3
|
eraser ลบตรายาง (STAMP) ของตัวเองได้: hit-test ใน InkLayer.eraseAt ด้วย bbox จาก annotationBBox (สูตรเดียวกับ render) เช็คตราก่อนเส้น/รูปทรงเพราะตราอยู่ layer บน — ตอน tool erase ค่า TextboxStampLayer ปิด pointer-events อยู่แล้วจึงไม่ต้องแตะ layer stack
Co-Authored-By: Claude Code <noreply@anthropic.com>
|
2026-09-14 09:59:01 +07:00 |
|
DESKTOP-1R2VSQH\Lenovo ThinkPad E490
|
b588343d50
|
bookmark: pre-fill ชื่อ default "หน้า N" + focus เลือกข้อความทั้งหมด
Deploy eCourt Note Web to Server / Validate Database Schema (Drizzle) (push) Successful in 5s
Deploy eCourt Note Web to Server / Build Web Docker Image (push) Successful in 45s
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
เดิมเปิด popup แล้วช่องชื่อเว้นว่าง (fallback "หน้า N" แค่ตอนบันทึก) — ตอนนี้
pre-fill ทันทีทั้งจากปุ่ม 🔖/คีย์ลัด B (ไม่มีข้อความที่คลุม) และปุ่ม bookmark
ในแผง selection (ชนิดที่ไม่มีข้อความ) พร้อม select ข้อความ default ไว้
ให้พิมพ์ทับ/Enter ยอมรับได้ทันที + sync spec N2 ใน PLAN-FEAT.md
Co-Authored-By: Claude Code <noreply@anthropic.com>
|
2026-09-11 17:45:31 +07:00 |
|
DESKTOP-1R2VSQH\Lenovo ThinkPad E490
|
ca74fb1843
|
TEXTBOX กล่องกว้างคงที่สไตล์ Smallpdf: คลิกเดียวได้กล่อง 30% + ลากขอบซ้าย/ขวาปรับความกว้าง (ฟอนต์คงขนาด ข้อความ wrap ใหม่)
Co-Authored-By: Claude Code <noreply@anthropic.com>
|
2026-09-11 17:41:22 +07:00 |
|
DESKTOP-1R2VSQH\Lenovo ThinkPad E490
|
fbc78b78e9
|
เปลี่ยนชื่อระบบ Jude's Note → Judge's Note
แก้เฉพาะชื่อที่แสดงต่อผู้ใช้และเอกสาร: หัวเว็บหน้าแรก (app/page.tsx),
<title> ทุกหน้า (app/layout.tsx), README, CLAUDE.md, docs/PLAN.md,
docs/PLAN-FEAT.md, .claude/agents/* — โลโก้ JN ใช้ initials เดิมได้
คง identifier ทางเทคนิคไว้: container judes-note-db + volume, package.json
name, localStorage key "judes-note:user" (เปลี่ยนแล้ว identity/ข้อมูลเดิมหาย)
Co-Authored-By: Claude Code <noreply@anthropic.com>
|
2026-09-11 13:37:31 +07:00 |
|
DESKTOP-1R2VSQH\Lenovo ThinkPad E490
|
6fd3a1515f
|
ซ่อม text ไทย PDF (ActualText) + revalidatePath ทุก action + คีย์ลัด DEL + ตรายาง label บรรทัดเดียว
- โหลด PDF ผ่าน /api/pdf?fileId= ที่สร้าง ToUnicode CMap ใหม่บนสำเนาในหน่วยความจำ
จาก ActualText ใน marked content (lib/pdf-actual-text.ts + unit tests) — แก้
ฟอนต์ไทยที่ cmap เพี้ยน (คำสั่งศาล) ให้ textLayer select/copy/ค้นหา/ชื่อ bookmark
ถูกต้องตั้งแต่ต้น ไฟล์ใน public/ ไม่ถูกแตะ (invariant #1) — PDF ปกติได้ bytes
เดิม ไม่มี cost และ fail แล้ว PDFViewer fallback fetch ไฟล์ดิบเอง
- ข้อความจาก selection ห้าม selection.toString() ตรง ๆ: ใช้ selectionTextWithin
เดินทีละอักษร เรียงตามตำแหน่งบนจอ (จัดการ Thai combining marks + ctrl ขยะ)
ปิดท้ายด้วย sanitizePdfText ก่อนเก็บ DB/ชื่อ bookmark/คลิปบอร์ด (มี tests)
- mergeRectsByLine ใช้ median ความสูง rect คำนวณเกณฑ์บรรทัดแทนค่าคงที่
- Server Actions ทุกตัวที่เขียน DB เรียก revalidateFilePages (revalidatePath
หน้า viewer+summary) คู่กับ publish event — แก้กด back แล้วเข้าไฟล์ใหม่ได้
RSC payload เก่าจาก Router Cache ฝั่ง client จนต้อง hard refresh
- คีย์ลัด DEL/Backspace ลบ annotation ที่เลือกอยู่ (ของตัวเองเท่านั้น ข้ามเมื่อ
focus อยู่ใน input/textarea/select/contenteditable)
- STAMP: ย่อฟอนต์ label ให้อยู่บรรทัดเดียวพอดีกรอบทั้งบนจอ (canvas measure) และ
export PDF (stampFitFontSize แชร์กัน) + เพิ่ม handle ปรับขนาดตรายางในแผง
selection (uniform scale + clamp รายแกน)
- sync invariant/กติกา: CLAUDE.md #4, rules/*.md, PLAN-FEAT.md (F3)
Co-Authored-By: Claude Code <noreply@anthropic.com>
|
2026-09-11 13:28:35 +07:00 |
|
DESKTOP-1R2VSQH\Lenovo ThinkPad E490
|
eddcec28c7
|
Add application codebase: PDF annotation for e-Court
Next.js 14 + Drizzle/PostgreSQL + SSE realtime sync — highlight,
freehand, comment, bookmark + ฟีเจอร์ต่อยอด F1–F19 (edit/move, undo/redo,
shapes, redaction, export PDF/CSV, reply, resolve, search, summary,
textbox, stamp, version history)
Co-Authored-By: Claude Code <noreply@anthropic.com>
|
2026-09-10 14:29:40 +07:00 |
|