feat: backend rebuild
This commit is contained in:
60
backend/.backup/Dockerfile copy
Normal file
60
backend/.backup/Dockerfile copy
Normal file
@@ -0,0 +1,60 @@
|
||||
# STAGE 1: build - สร้าง stage พื้นฐานสำหรับติดตั้ง dependencies ทั้งหมด
|
||||
# เราจะใช้ stage นี้เป็น cache ร่วมกันระหว่าง development และ production เพื่อความรวดเร็ว
|
||||
FROM node:20-alpine AS build
|
||||
# USER node
|
||||
WORKDIR /app
|
||||
# สร้าง user ไม่ใช่ root (ปลอดภัยขึ้น)
|
||||
# RUN addgroup -S dms && adduser -S dms -G dms
|
||||
|
||||
# runtime tools + build deps ชั่วคราว (สำหรับ bcrypt ฯลฯ)
|
||||
#RUN apk add --no-cache curl \
|
||||
# && apk add --no-cache --virtual build-deps python3 make g++
|
||||
RUN apk add --no-cache --virtual build-deps python3 make g++
|
||||
# COPY --chown=node:node package*.json package-lock.json* ./
|
||||
# COPY package*.json package-lock.json* ./
|
||||
# COPY package.json ./
|
||||
|
||||
# RUN (npm ci --omit=dev || npm install --omit=dev)
|
||||
# ติดตั้ง deps แบบ clean + ติดตั้ง dev tooling ที่จำเป็น
|
||||
# RUN npm ci --include=dev || npm install --include=dev && \
|
||||
# npx --yes nodemon --version > /dev/null 2>&1 || npm i -D nodemon
|
||||
# RUN npm ci
|
||||
RUN npm install
|
||||
|
||||
# คัดลอกโค้ด + ตั้ง owner/สิทธิ์
|
||||
# COPY --chown=app:app src ./src
|
||||
# ไม่ COPY src เข้ามา — เราจะใช้ bind mount แทน
|
||||
# เพื่อ hot-reload จากโค้ดบน QNAP ได้ทันที
|
||||
|
||||
|
||||
# ลบ build deps ลดขนาดอิมเมจ
|
||||
# RUN apk del --no-network build-deps
|
||||
|
||||
# STAGE 2: development - สำหรับการพัฒนาใน local โดยเฉพาะ
|
||||
# stage นี้จะใช้ dependencies ทั้งหมดจาก 'base'
|
||||
FROM base AS development
|
||||
# (ต้องมี script "dev" ใน package.json, เช่น "dev": "nodemon src/index.js")
|
||||
CMD ["npm", "run", "dev"]
|
||||
|
||||
# ---------- Runtime stage ----------
|
||||
FROM node:20-alpine AS production
|
||||
WORKDIR /app
|
||||
|
||||
# สร้าง user และ group ที่ไม่ใช่ root สำหรับรันแอปพลิเคชัน
|
||||
RUN addgroup -S dms && adduser -S dms -G dms
|
||||
# COPY --from=build /app /app
|
||||
ENV NODE_ENV=production
|
||||
# คัดลอกไฟล์ package.json และ node_modules จาก stage 'base'
|
||||
COPY --from=build /app/package*.json ./
|
||||
COPY --from=build /app/node_modules ./node_modules
|
||||
|
||||
# ลบ devDependencies ที่ไม่จำเป็นสำหรับ production ออก
|
||||
RUN npm prune --production
|
||||
|
||||
# เปลี่ยนไปใช้ user ที่ไม่ใช่ root
|
||||
USER dms
|
||||
|
||||
EXPOSE 3001
|
||||
|
||||
CMD ["npm","start"]
|
||||
# backend/Dockerfile (Node.js ESM)
|
||||
34
backend/.backup/Dockerfile.build
Normal file
34
backend/.backup/Dockerfile.build
Normal file
@@ -0,0 +1,34 @@
|
||||
FROM node:20-alpine
|
||||
# สำหรับอ่านค่า .env ที่วางไว้ระดับ compose (ไม่ copy เข้า image)
|
||||
ENV NODE_ENV=production
|
||||
ENV TZ=Asia/Bangkok
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# สร้าง user ไม่ใช่ root (ปลอดภัยขึ้น)
|
||||
RUN addgroup -S app && adduser -S app -G app
|
||||
|
||||
# runtime tools + build deps ชั่วคราว (สำหรับ bcrypt ฯลฯ)
|
||||
RUN apk add --no-cache curl \
|
||||
&& apk add --no-cache --virtual build-deps python3 make g++
|
||||
# ติดตั้ง deps ของ npm (เช่น bcrypt ต้องมี python3/make/g++)
|
||||
# ใช้ virtual package ชื่อ build-deps (ไม่ต้องมีจุด)
|
||||
COPY package.json package-lock.json* ./
|
||||
RUN (npm ci --omit=dev || npm install --omit=dev)
|
||||
|
||||
# คัดลอกโค้ด + ตั้ง owner/สิทธิ์
|
||||
COPY --chown=app:app src ./src
|
||||
# COPY src ./src
|
||||
# COPY app ./app
|
||||
# เตรียม logs + สิทธิ์อ่านไฟล์ใน /app
|
||||
RUN mkdir -p /app/logs \
|
||||
&& chown -R app:app /app/logs \
|
||||
&& chmod -R a+rX /app
|
||||
|
||||
# ลบ build deps ลดขนาดอิมเมจ
|
||||
RUN apk del --no-network build-deps
|
||||
|
||||
EXPOSE 3001
|
||||
USER app
|
||||
CMD ["node", "src/index.js"]
|
||||
# backend/Dockerfile (Node.js ESM)
|
||||
69
backend/.backup/Dockerfile.dev
Normal file
69
backend/.backup/Dockerfile.dev
Normal file
@@ -0,0 +1,69 @@
|
||||
# syntax=docker/dockerfile:1.6
|
||||
|
||||
########## Base (apk + common tools ติดตั้งตอน build) ##########
|
||||
FROM node:20-alpine AS base
|
||||
WORKDIR /app
|
||||
RUN apk add --no-cache bash curl tzdata python3 make g++ \
|
||||
&& ln -snf /usr/share/zoneinfo/Asia/Bangkok /etc/localtime \
|
||||
&& echo "Asia/Bangkok" > /etc/timezone
|
||||
ENV TZ=Asia/Bangkok APP_HOME=/app RUNTIME_HOME=/opt/runtime
|
||||
|
||||
########## Deps สำหรับ Production (no devDeps) ##########
|
||||
FROM base AS deps-prod
|
||||
WORKDIR /work
|
||||
COPY package*.json ./
|
||||
RUN npm ci --omit=dev || npm install --omit=dev
|
||||
RUN mkdir -p ${RUNTIME_HOME} && mv node_modules ${RUNTIME_HOME}/node_modules
|
||||
|
||||
########## Deps สำหรับ Development (รวม devDeps) ##########
|
||||
FROM base AS deps-dev
|
||||
RUN apk add --no-cache git openssh-client ca-certificates
|
||||
WORKDIR /work
|
||||
COPY package*.json ./
|
||||
RUN npm ci || npm install
|
||||
RUN mkdir -p ${RUNTIME_HOME} && mv node_modules ${RUNTIME_HOME}/node_modules
|
||||
|
||||
########## Runtime: Development ##########
|
||||
FROM base AS dev
|
||||
WORKDIR /app
|
||||
# ทำงานเป็น root ชั่วคราวเพื่อจัดสิทธิ์/ลิงก์ แล้วค่อยเปลี่ยนเป็น node
|
||||
# 1) คัดลอก deps dev
|
||||
COPY --from=deps-dev /opt/runtime/node_modules /opt/runtime/node_modules
|
||||
|
||||
# 2) สร้าง symlink /app/node_modules → /opt/runtime/node_modules (กันปัญหา NODE_PATH/permission)
|
||||
RUN ln -sfn /opt/runtime/node_modules /app/node_modules \
|
||||
&& chown -R node:node /app
|
||||
|
||||
# 3) ใส่สคริปต์ start-dev แล้วค่อยสลับ USER
|
||||
COPY --chown=node:node ./start-dev.sh /app/start-dev.sh
|
||||
RUN chmod +x /app/start-dev.sh
|
||||
USER node
|
||||
|
||||
# ให้หา nodemon ได้จาก node_modules/.bin ที่ bake มาแล้ว
|
||||
# ENV NODE_ENV=development PATH="/opt/runtime/node_modules/.bin:${PATH}"
|
||||
# ให้หา nodemon ได้ และระบุพอร์ตดีฟอลต์
|
||||
ENV NODE_ENV=development \
|
||||
PORT=3001 \
|
||||
PATH="/opt/runtime/node_modules/.bin:${PATH}"
|
||||
|
||||
EXPOSE 3001 9229
|
||||
HEALTHCHECK --interval=15s --timeout=5s --retries=10 \
|
||||
CMD wget -qO- http://127.0.0.1:3001/health || exit 1
|
||||
# HEALTHCHECK --interval=15s --timeout=5s --retries=10 CMD curl -fsS http://127.0.0.1:7001/health || exit 1
|
||||
CMD ["/app/start-dev.sh"]
|
||||
|
||||
########## Runtime: Production ##########
|
||||
FROM base AS prod
|
||||
WORKDIR /app
|
||||
ENV NODE_ENV=production
|
||||
# ใส่ deps สำหรับ prod
|
||||
COPY --from=deps-prod /opt/runtime/node_modules /opt/runtime/node_modules
|
||||
# สร้าง symlink เช่นกัน เพื่อให้ Node resolve deps ได้จาก /app เหมือน dev
|
||||
RUN ln -sfn /opt/runtime/node_modules /app/node_modules
|
||||
# ใส่ซอร์ส (prod ไม่ bind โค้ด)
|
||||
COPY . .
|
||||
USER node
|
||||
EXPOSE 3001
|
||||
HEALTHCHECK --interval=30s --timeout=5s --retries=10 \
|
||||
CMD wget -qO- http://127.0.0.1:3001/health || exit 1
|
||||
CMD ["node","src/index.js"]
|
||||
29
backend/.backup/backend build.md
Normal file
29
backend/.backup/backend build.md
Normal file
@@ -0,0 +1,29 @@
|
||||
# Backend build
|
||||
|
||||
## วิธีสร้าง package-lock.json ด้วย Docker
|
||||
|
||||
### 1. เช็ค uid:gid ของโฟลเดอร์โปรเจกต์บน QNAP
|
||||
|
||||
stat -c "%u:%g" .
|
||||
|
||||
### 2. ใช้ค่าที่ได้มาแทน UID:GID
|
||||
|
||||
```bash
|
||||
docker run --rm \
|
||||
-v "/share/Container/dms/frontend:/app" -w /app \
|
||||
--user UID:GID -e HOME=/tmp \
|
||||
node:20-alpine sh -lc 'mkdir -p /tmp && npm install --package-lock-only --ignore-scripts'
|
||||
```
|
||||
|
||||
สร้าง package-lock.json โดย ไม่ติดตั้ง node_modules
|
||||
|
||||
--user $(id -u):$(id -g) ทำให้ไฟล์ที่ได้เป็นเจ้าของโดยยูสเซอร์ปัจจุบัน (กันปัญหา root-owned)
|
||||
|
||||
## ขั้นตอน Build บน QNAP
|
||||
|
||||
docker compose -f docker-backend-build.yml build --no-cache 2>&1 | tee backend_build.log
|
||||
|
||||
## สำหรับ build local
|
||||
|
||||
cd backend
|
||||
docker build -t dms-backend:dev --target dev .
|
||||
BIN
backend/.backup/backend_tree.txt
Normal file
BIN
backend/.backup/backend_tree.txt
Normal file
Binary file not shown.
7
backend/.backup/ed25519
Normal file
7
backend/.backup/ed25519
Normal file
@@ -0,0 +1,7 @@
|
||||
-----BEGIN OPENSSH PRIVATE KEY-----
|
||||
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
|
||||
QyNTUxOQAAACC3rQmpCi1POXlbmcMDkfAPQJWcwcKs4AzK6jftdbmasQAAAJi4HMhWuBzI
|
||||
VgAAAAtzc2gtZWQyNTUxOQAAACC3rQmpCi1POXlbmcMDkfAPQJWcwcKs4AzK6jftdbmasQ
|
||||
AAAEDlUhx1seuTgio9rCRFC4wXwtrnAa0HrDubQX1Y4FC8lretCakKLU85eVuZwwOR8A9A
|
||||
lZzBwqzgDMrqN+11uZqxAAAAD3BlYW5jQERlc2stNTQzOQECAwQFBg==
|
||||
-----END OPENSSH PRIVATE KEY-----
|
||||
0
backend/.backup/ed25519.pub
Normal file
0
backend/.backup/ed25519.pub
Normal file
64
backend/.backup/fix-bearer-index.patch.diff
Normal file
64
backend/.backup/fix-bearer-index.patch.diff
Normal file
@@ -0,0 +1,64 @@
|
||||
diff --git a/src/index.js b/src/index.js
|
||||
--- a/src/index.js
|
||||
+++ b/src/index.js
|
||||
@@ -1,9 +1,8 @@
|
||||
import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
import express from "express";
|
||||
-import cookieParser from "cookie-parser";
|
||||
import cors from "cors";
|
||||
|
||||
import sql from "./db/index.js";
|
||||
import healthRouter from "./routes/health.js";
|
||||
import { authJwt } from "./middleware/authJwt.js";
|
||||
@@ -64,7 +63,7 @@
|
||||
// ✅ อยู่หลัง NPM/Reverse proxy → ให้ trust proxy เพื่อให้ cookie secure / proto ทำงานถูก
|
||||
app.set("trust proxy", 1);
|
||||
|
||||
-// CORS แบบกำหนด origin ตามรายการที่อนุญาต + อนุญาต credentials (จำเป็นสำหรับ cookie)
|
||||
+// ✅ CORS สำหรับ Bearer token: ไม่ต้องใช้ credentials (ไม่มีคุกกี้)
|
||||
app.use(
|
||||
cors({
|
||||
origin(origin, cb) {
|
||||
if (!origin) return cb(null, true); // server-to-server / curl
|
||||
return cb(null, ALLOW_ORIGINS.includes(origin));
|
||||
},
|
||||
- credentials: true,
|
||||
+ credentials: false,
|
||||
methods: ["GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"],
|
||||
- allowedHeaders: ["Content-Type", "Authorization", "X-Requested-With"],
|
||||
+ allowedHeaders: [
|
||||
+ "Content-Type",
|
||||
+ "Authorization",
|
||||
+ "X-Requested-With",
|
||||
+ "Accept",
|
||||
+ "Origin",
|
||||
+ "Referer",
|
||||
+ "User-Agent",
|
||||
+ "Cache-Control",
|
||||
+ "Pragma"
|
||||
+ ],
|
||||
exposedHeaders: ["Content-Disposition", "Content-Length"],
|
||||
})
|
||||
);
|
||||
// preflight
|
||||
app.options(
|
||||
"*",
|
||||
cors({
|
||||
origin(origin, cb) {
|
||||
if (!origin) return cb(null, true);
|
||||
return cb(null, ALLOW_ORIGINS.includes(origin));
|
||||
},
|
||||
- credentials: true,
|
||||
+ credentials: false,
|
||||
})
|
||||
);
|
||||
|
||||
-app.use(cookieParser());
|
||||
+// ❌ ไม่ต้อง parse cookie แล้ว (เราไม่ใช้คุกกี้สำหรับ auth)
|
||||
+// app.use(cookieParser());
|
||||
|
||||
// Payload limits
|
||||
app.use(express.json({ limit: "10mb" }));
|
||||
app.use(express.urlencoded({ extended: true, limit: "10mb" }));
|
||||
|
||||
Reference in New Issue
Block a user