2026-09-10 15:43:17 +07:00
|
|
|
# ─── Stage 1: ติดตั้ง dependencies (npm ci รวม postinstall คัดลอก pdf.worker) ───
|
|
|
|
|
FROM node:24-alpine AS deps
|
|
|
|
|
WORKDIR /app
|
|
|
|
|
COPY package.json package-lock.json ./
|
|
|
|
|
# postinstall เขียน public/pdf.worker.min.mjs — ต้องมีโฟลเดอร์ public/ ก่อน ไม่งั้น npm ci ล้ม
|
|
|
|
|
RUN mkdir -p public && npm ci
|
|
|
|
|
|
|
|
|
|
# ─── Stage 2: build Next.js (output: standalone) ───
|
|
|
|
|
FROM node:24-alpine AS builder
|
|
|
|
|
WORKDIR /app
|
|
|
|
|
COPY --from=deps /app/node_modules ./node_modules
|
|
|
|
|
COPY . .
|
|
|
|
|
# ประกันว่า pdf.worker.min.mjs ตรงกับเวอร์ชัน pdfjs-dist ใน node_modules เสมอ
|
genesis+worker: design system Genesis ทั้งชุด + patch pdf.worker แก้ fake-space ไทย + ปิด review design/responsive/quality รอบ 2026-09-24 — (1) Genesis: ฟอนต์ General Sans self-host + DM Sans + Sarabun, AppNav 56px backdrop-blur แทน SessionBar, DotGrid หน้า login, palette/รัศมี/เงา/focus ตาม docs/DESIGN.md ครบทุกหน้า (2) postinstall scripts/patch-pdf-worker.mjs ถอด if (scaledDim) รอบ prevTransform ให้อัปเดตทุก glyph — กัน addFakeSpaces แทรก space กลางคำไทยใน PDF ที่ justify ด้วย letter-spacing + test กัน regression (tests/scripts/ + fixture thai_letterspacing.pdf, invariant #6) (3) ฟอร์มอัปโหลด + ช่องกลุ่ม typeId ทางเลือก — normDocumentGroup ที่ utils/external-file.ts เป็น single source ร่วมกับ N8 (4) token fixes: focus ring ปุ่ม pin + แถว bookmark ตามหน้า, ปุ่ม action ใน popup/composer/dialog เป็น rounded-md ทั้งคู่, selection preview เป็น tint ของ primary แทน blue-500 ดิบ, default สี shape/highlight รวมที่ utils/annotation-display, loading animate-pulse + จดข้อยกเว้น (เงา pin, font weights ของ viewer) ลง DESIGN.md (5) responsive: Export PDF max-lg:order-first ให้เห็นบน iPad, แถวบน header แถวเดียวเลื่อนได้บนจอแคบ, re-fit ความกว้างตอน toggle sidebar เฉพาะเมื่อยังไม่ซูมเอง, pin popover flip ขึ้นบนเมื่อใกล้ท้ายหน้า, toast hint ตอนสลับ tool กลางเอกสาร, ป้าย "ชนิด · ผู้ทำ" ของรายการผู้อื่นสำหรับจอสัมผัส (6) คุณภาพ: @layer ครอบ @media กันกฎ touch รั่ยไป desktop (Tailwind v3 ยก @layer ออกจาก media ทิ้ง wrapper — ยืนยันด้วย build จริง + วัดบนจอ), กฎ M5 ครอบ contenteditable กัน Safari zoom ตอนแก้ไข TEXTBOX บน iPad, COMMENT ใช้ box มาตราฐานเดียวตาม pin px จริง (render/scroll target/move-clamp/bookmark), ตัดหัวการ์ดซ้ำกับ h2 หน้ารายการ — พร้อมไฟล์ untracked ที่ postinstall/โค้ดอ้างถึงครบชุด (app/fonts/, AppNav, DotGrid, tests/) กัน fresh clone fail ที่ npm install (คำขอผู้ใช้ 2026-09-24)
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-24 11:46:02 +07:00
|
|
|
# (postinstall รันใน stage deps ซึ่งยังไม่มี public/ ของ repo) — ต้องใช้ตัว patch ด้วย
|
|
|
|
|
# ไม่ใช่ copyFileSync เปล่า ๆ ไม่งั้น worker ที่ patch fake-space ไทยถูกเขียนทับด้วยตัวดิบ
|
|
|
|
|
RUN node scripts/patch-pdf-worker.mjs
|
2026-09-10 15:43:17 +07:00
|
|
|
ENV NEXT_TELEMETRY_DISABLED=1
|
|
|
|
|
# db/index.ts throw ถ้าไม่มี DATABASE_URL ตอน next build เก็บ page data —
|
|
|
|
|
# ใส่ค่า dummy (postgres.js เชื่อมแบบ lazy ไม่มี query ตอน build) ตัวจริงฉีดตอน docker run
|
|
|
|
|
ENV DATABASE_URL=postgresql://placeholder:placeholder@127.0.0.1:5432/placeholder
|
|
|
|
|
RUN npm run build
|
|
|
|
|
|
|
|
|
|
# ─── Stage 3: runtime ตัวเบา (แค่ standalone + public/) ───
|
|
|
|
|
FROM node:24-alpine AS runner
|
|
|
|
|
WORKDIR /app
|
|
|
|
|
ENV NODE_ENV=production \
|
|
|
|
|
NEXT_TELEMETRY_DISABLED=1 \
|
|
|
|
|
PORT=3000 \
|
|
|
|
|
HOSTNAME=0.0.0.0
|
|
|
|
|
RUN addgroup -S nodejs && adduser -S nextjs -G nodejs
|
|
|
|
|
# Next 14.2 รวม public/ (pdf.worker, ฟอนต์ Sarabun, samples PDF) ไว้ใน standalone แล้ว
|
|
|
|
|
# แต่ไม่รวม .next/static (JS chunks) — ต้องคัดลอกเพิ่ม ไม่งั้นหน้าเว็บไม่มี JS
|
|
|
|
|
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
|
|
|
|
|
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
|
2026-09-10 16:25:14 +07:00
|
|
|
# migration: ไฟล์ SQL (drizzle-kit generate) + runner — รันตอน container start
|
|
|
|
|
COPY --from=builder --chown=nextjs:nodejs /app/drizzle ./drizzle
|
|
|
|
|
COPY --from=builder --chown=nextjs:nodejs /app/scripts ./scripts
|
2026-09-10 16:30:01 +07:00
|
|
|
# postgres.js โดน Next บีบ bundle เข้า server chunks — standalone node_modules ไม่มี package นี้
|
|
|
|
|
# แต่ migrate.mjs import มันตรง ๆ → คัดลอกจาก stage deps (v3 ไม่มี dependency ย่อย โฟลเดอร์เดียวพอ)
|
|
|
|
|
COPY --from=deps --chown=nextjs:nodejs /app/node_modules/postgres ./node_modules/postgres
|
2026-09-16 15:57:06 +07:00
|
|
|
# สร้างโฟลเดอร์ uploads ให้ user nextjs เป็นเจ้าของ — named volume ที่ compose mount ทับ
|
|
|
|
|
# (เก็บไฟล์อัปโหลดข้าม redeploy) จะได้ ownership จาก image ตอน init:
|
|
|
|
|
# ไม่มี dir นี้ใน image = volume ถูกสร้างโดย root แล้ว action เขียนไฟล์ไม่ได้ (EACCES)
|
|
|
|
|
RUN mkdir -p public/uploads && chown nextjs:nodejs public/uploads
|
2026-09-10 15:43:17 +07:00
|
|
|
USER nextjs
|
|
|
|
|
EXPOSE 3000
|
|
|
|
|
# DATABASE_URL ฉีดตอนรันผ่าน env ของ container (อย่าฝังใน image)
|
2026-09-10 16:25:14 +07:00
|
|
|
# migrate สร้าง database ถ้ายังไม่มี + apply ไฟล์ที่ยังไม่ได้ apply (idempotent)
|
2026-09-10 18:01:25 +07:00
|
|
|
# seed-samples sync ตาราง files กับ public/samples/ ที่ bake อยู่ใน image (idempotent)
|
|
|
|
|
CMD ["sh", "-c", "node scripts/migrate.mjs && node scripts/seed-samples.mjs && exec node server.js"]
|