diff --git a/.gitignore b/.gitignore index e2a6c162..92ef2a64 100644 --- a/.gitignore +++ b/.gitignore @@ -5,9 +5,12 @@ Documents/ mariadb/data/ n8n*/ +n8n-postgres/ npm/ phpmyadmin/ pgadmin/ +.tmp.driveupload +.qsync # ===================================================== # IDE/Editor settings # ===================================================== diff --git a/backend/Dockerfile copy b/backend/.backup/Dockerfile copy similarity index 100% rename from backend/Dockerfile copy rename to backend/.backup/Dockerfile copy diff --git a/backend/Dockerfile.build b/backend/.backup/Dockerfile.build similarity index 100% rename from backend/Dockerfile.build rename to backend/.backup/Dockerfile.build diff --git a/backend/Dockerfile.dev b/backend/.backup/Dockerfile.dev similarity index 100% rename from backend/Dockerfile.dev rename to backend/.backup/Dockerfile.dev diff --git a/backend/.backup/backend build.md b/backend/.backup/backend build.md new file mode 100644 index 00000000..d67f618e --- /dev/null +++ b/backend/.backup/backend build.md @@ -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 . diff --git a/backend/backend_tree.txt b/backend/.backup/backend_tree.txt old mode 100755 new mode 100644 similarity index 100% rename from backend/backend_tree.txt rename to backend/.backup/backend_tree.txt diff --git a/backend/ed25519 b/backend/.backup/ed25519 similarity index 100% rename from backend/ed25519 rename to backend/.backup/ed25519 diff --git a/backend/ed25519.pub b/backend/.backup/ed25519.pub similarity index 100% rename from backend/ed25519.pub rename to backend/.backup/ed25519.pub diff --git a/backend/fix-bearer-index.patch.diff b/backend/.backup/fix-bearer-index.patch.diff similarity index 100% rename from backend/fix-bearer-index.patch.diff rename to backend/.backup/fix-bearer-index.patch.diff diff --git a/backend/.dockerignore b/backend/.dockerignore index 8f61cf2f..4133e0fe 100644 --- a/backend/.dockerignore +++ b/backend/.dockerignore @@ -1,8 +1,11 @@ .git +.vscode +.backup node_modules logs *.log -Dockerfile* +Dockerfile*.* +*.yml README*.md coverage tmp diff --git a/backend/.eslintrc.json b/backend/.eslintrc.json new file mode 100644 index 00000000..26441a93 --- /dev/null +++ b/backend/.eslintrc.json @@ -0,0 +1,15 @@ +{ + "env": { + "node": true, + "es2021": true, + "jest": true + }, + "extends": ["eslint:recommended", "plugin:prettier/recommended"], + "parserOptions": { + "ecmaVersion": "latest", + "sourceType": "module" + }, + "rules": { + "prettier/prettier": "warn" + } +} diff --git a/backend/.prettierrc.json b/backend/.prettierrc.json new file mode 100644 index 00000000..8b4d1e23 --- /dev/null +++ b/backend/.prettierrc.json @@ -0,0 +1,7 @@ +{ + "semi": true, + "singleQuote": true, + "trailingComma": "es5", + "arrowParens": "always", + "printWidth": 80 +} diff --git a/backend/Dockerfile b/backend/Dockerfile index 4a178dd3..ed942ade 100644 --- a/backend/Dockerfile +++ b/backend/Dockerfile @@ -66,4 +66,5 @@ 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"] \ No newline at end of file +CMD ["node","src/index.js"] + diff --git a/backend/docker-compose.yml b/backend/docker-compose.yml index 0165ccdd..a529977a 100755 --- a/backend/docker-compose.yml +++ b/backend/docker-compose.yml @@ -51,7 +51,7 @@ services: JWT_EXPIRES_IN: "12h" PASSWORD_SALT_ROUNDS: "10" FRONTEND_ORIGIN: "https://lcbp3.np-dms.work" - CORS_ORIGINS: "https://lcbp3.np-dms.work,http://localhost:3000,http://127.0.0.1:3000" + CORS_ORIGINS: "https://backend.np-dms.work,http://localhost:3000,http://127.0.0.1:3000,https://lcbp3.np-dms.work" COOKIE_DOMAIN: ".np-dms.work" RATE_LIMIT_WINDOW_MS: "900000" RATE_LIMIT_MAX: "200" diff --git a/backend/package.json b/backend/package.json index 5e4ade07..f0a1455a 100644 --- a/backend/package.json +++ b/backend/package.json @@ -1,6 +1,6 @@ { "name": "dms-backend", - "version": "0.6.0", + "version": "0.8.0", "private": true, "type": "module", "main": "src/index.js", @@ -11,7 +11,12 @@ "dev": "nodemon --watch src src/index.js", "dev:desktop": "node --watch src/index.js", "start": "node src/index.js", - "lint": "echo 'lint placeholder'", + "lint": "eslint . --ext .js", + "lint:fix": "eslint . --ext .js --fix", + "test": "jest", + "test:watch": "jest --watch", + "test:coverage": "jest --coverage", + "test:watch:coverage": "jest --watch --coverage", "health": "node -e \"fetch('http://localhost:'+ (process.env.BACKEND_PORT||3001) +'/health').then(r=>r.text()).then(console.log).catch(e=>{console.error(e);process.exit(1)})\"", "postinstall": "node -e \"console.log('Installed dms-backend %s','0.6.0')\"" }, @@ -33,6 +38,12 @@ "winston": "^3.13.0" }, "devDependencies": { - "nodemon": "^3.1.10" + "nodemon": "^3.1.10", + "eslint": "^8.56.0", + "prettier": "^3.1.0", + "eslint-config-prettier": "^9.0.0", + "eslint-plugin-prettier": "^5.0.0", + "jest": "^29.7.0", + "supertest": "^6.3.4" } } diff --git a/backend/package_v0_5_0..json b/backend/package_v0_5_0..json deleted file mode 100644 index 5b2fcbf6..00000000 --- a/backend/package_v0_5_0..json +++ /dev/null @@ -1,25 +0,0 @@ - -{ - "name": "dms-backend", - "version": "0.5.0", - "private": true, - "type": "module", - "scripts": { - "dev": "node --env-file=../.env src/index.js", - "start": "node src/index.js", - "health": "node -e \"fetch('http://localhost:'+ (process.env.BACKEND_PORT||3001) +'/health').then(r=>r.text()).then(console.log).catch(e=>{console.error(e);process.exit(1)})\"" - }, - "dependencies": { - "bcrypt": "5.1.1", - "cors": "2.8.5", - "dotenv": "16.4.5", - "express": "4.19.2", - "express-rate-limit": "7.4.0", - "helmet": "7.1.0", - "jsonwebtoken": "9.0.2", - "mariadb": "3.3.1", - "morgan": "1.10.0", - "sequelize": "6.37.3" - } -} - diff --git a/backend/package_v0_6_0.json b/backend/package_v0_6_0.json deleted file mode 100644 index 902851e6..00000000 --- a/backend/package_v0_6_0.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "name": "dms-backend", - "version": "0.6.0", - "private": true, - "type": "module", - "main": "src/index.js", - "engines": { - "node": ">=20.0.0" - }, - "scripts": { - "dev": "nodemon --watch src src/index.js", - "start": "node src/index.js", - "lint": "echo 'lint placeholder'", - "health": "node -e \"fetch('http://localhost:'+ (process.env.BACKEND_PORT||3001) +'/health').then(r=>r.text()).then(console.log).catch(e=>{console.error(e);process.exit(1)})\"", - "postinstall": "node -e \"console.log('Installed dms-backend %s','0.6.0')\"" - }, - - "dependencies": { - "bcrypt": "5.1.1", - "bcryptjs": "^2.4.3", - "cookie-parser": "^1.4.7", - "cors": "2.8.5", - "dotenv": "16.4.5", - "express": "^4.21.2", - "express-rate-limit": "7.4.0", - "helmet": "7.1.0", - "jsonwebtoken": "9.0.2", - "mariadb": "3.3.1", - "morgan": "^1.10.1", - "multer": "^2.0.2", - "mysql2": "^3.11.0", - "sequelize": "6.37.3", - "winston": "^3.13.0" - }, - "devDependencies": { - "nodemon": "^3.1.10" - } -} diff --git a/backend/tests/health.test.js b/backend/tests/health.test.js new file mode 100644 index 00000000..586c78f0 --- /dev/null +++ b/backend/tests/health.test.js @@ -0,0 +1,15 @@ +import app from "../src/index.js"; // สมมติว่าคุณ export app จาก src/index.js +import request from "supertest"; + +// ปิด server หลังจากเทสเสร็จ +afterAll((done) => { + app.server.close(done); +}); + +describe("GET /health", () => { + it("should respond with 200 OK and a health message", async () => { + const response = await request(app).get("/health"); + expect(response.statusCode).toBe(200); + expect(response.text).toContain("Backend is healthy"); + }); +}); diff --git a/docker-backend-build.yml b/docker-backend-build.yml index 4be9dfe2..13a18769 100644 --- a/docker-backend-build.yml +++ b/docker-backend-build.yml @@ -16,8 +16,8 @@ services: target: prod image: dms-backend:prod command: ["true"] -# docker compose -f docker-backend-build.yml build --no-cache +# docker compose -f docker-backend-build.yml build --no-cache 2>&1 | tee backend_build.log # ***** สำหรับ build บน server เอา ## ออก ***** # สำหรับ build บน local # cd backend -# docker build -t dms-backend:dev --target dev . \ No newline at end of file +# docker build -t dms-backend:dev --target dev .