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>
This commit is contained in:
Your Name 2026-09-16 15:57:06 +07:00
parent 21b9958600
commit a4cac15e42
9 changed files with 571 additions and 1 deletions

View file

@ -51,6 +51,7 @@ app/actions/files.ts ← Server Action uploadFile — validate + เขีย
app/api/annotations/stream/route.ts ← SSE endpoint (GET ?fileId=)
app/api/annotations/export/route.ts ← export PDF ฝัง annotation (pdf-lib, F8)
app/api/annotations/export-csv/route.ts ← export สรุป CSV พร้อม BOM (F16)
app/uploads/[name]/route.ts ← เสิร์ฟไฟล์อัปโหลดจาก public/uploads/ (N4 — Next production เห็นไฟล์ static เฉพาะที่มีตอน startup ไฟล์ที่เขียน runtime ต้องเสิร์ฟผ่าน route)
app/page.tsx ← รายการไฟล์ (server component)
app/annotate/[id]/page.tsx ← โหลด file + initial data → PDFViewer
app/annotate/[id]/summary/page.tsx ← หน้าสรุปหมายเหตุจัดกลุ่มตามหน้า (F15)