From: Snapshot-Content-Location: https://docs.google.com/document/u/0/d/1KfeiWDih7G3I40FtWma7Eab3OUDqeIK3os240-At5cA/mobilebasic?hl=th-TH&pli=1 Subject: =?utf-8?Q?LCBP3-DMS=20Backend=20Documentation=20(=E0=B8=89=E0=B8=9A=E0=B8?= =?utf-8?Q?=B1=E0=B8=9A=E0=B8=AA=E0=B8=A1=E0=B8=9A=E0=B8=B9=E0=B8=A3=E0=B8?= =?utf-8?Q?=93=E0=B9=8C)?= Date: Thu, 16 Oct 2025 23:04:32 +0700 MIME-Version: 1.0 Content-Type: multipart/related; type="text/html"; boundary="----MultipartBoundary--VhiUdJuxlxmxWrLaXiSlRP2gfR2PuYkGvhdYgSLHby----" ------MultipartBoundary--VhiUdJuxlxmxWrLaXiSlRP2gfR2PuYkGvhdYgSLHby---- Content-Type: text/html Content-ID: Content-Transfer-Encoding: binary Content-Location: https://docs.google.com/document/u/0/d/1KfeiWDih7G3I40FtWma7Eab3OUDqeIK3os240-At5cA/mobilebasic?hl=th-TH&pli=1 LCBP3-DMS Backend Documentation (ฉบับสมบูรณ์)
LCBP3-DMS Backend Documentation (ฉบับสมบูรณ์)

LCBP3-DMS: Backend Documentation (ฉบับสมบูรณ์)

เอกสารนี้รวบรวมรายละเอียดทั้งหมดของส่วน Backend สำหรับระบบ LCBP3 Document Management System ซึ่งพัฒนาด้วย NestJS Framework ประกอบด้วยขั้นตอนการติดตั้ง, สถาปัตยกรรม, และซอร์สโค้ดทั้งหมดของโปรเจกต์

1. ข้อกำหนดเบื้องต้น (Prerequisites)

ก่อนเริ่มการติดตั้งและพัฒนา คุณจะต้องมีเครื่องมือต่อไปนี้ติดตั้งบนเครื่องคอมพิวเตอร์ของคุณ:

  • Node.js: เวอร์ชัน 18.x หรือสูงกว่า
  • NPM หรือ Yarn: ตัวจัดการ Package (มาพร้อมกับ Node.js)
  • NestJS CLI: ติดตั้งผ่านคำสั่ง npm install -g @nestjs/cli
  • Git: สำหรับการ Clone โปรเจกต์จาก Gitea
  • Docker: (แนะนำ) สำหรับการรันฐานข้อมูล MariaDB ในสภาพแวดล้อมที่เหมือนกับ Production

2. ขั้นตอนการติดตั้งและเริ่มใช้งาน (Installation & Setup)

  1. Clone โปรเจกต์:
  • คัดลอกโปรเจกต์จาก Gitea repository ของคุณมาไว้ที่เครื่อง

<!-- end list -->git clone [http://git.np-dms.work/your-repo/backend-np-dms.git](http://git.np-dms.work/your-repo/backend-np-dms.git)
cd backend-np-dms

  1. ติดตั้ง Dependencies:
  • ใช้ npm เพื่อติดตั้ง Library ทั้งหมดที่โปรเจกต์ต้องการ

<!-- end list -->npm install

  1. ตั้งค่า Environment File:
  • สร้างไฟล์ใหม่ชื่อ .env ที่รากของโปรเจกต์
  • คัดลอกเนื้อหาจากไฟล์ .env.example (ถ้ามี) หรือใช้โครงสร้างด้านล่าง แล้วแก้ไขค่าให้ตรงกับสภาพแวดล้อมของคุณ (โดยเฉพาะข้อมูลการเชื่อมต่อฐานข้อมูล)

ไฟล์ .env (ตัวอย่าง):# Database Configuration
DB_TYPE=mysql
DB_HOST=localhost
DB_PORT=3306
DB_USERNAME=your_db_user
DB_PASSWORD=your_db_password
DB_DATABASE=dms_db

# JWT Configuration
JWT_SECRET=your_super_long_and_random_jwt_secret

# Application Configuration
API_PORT=3001

  1. เริ่มต้นฐานข้อมูล:
  • ตรวจสอบให้แน่ใจว่า MariaDB Server ของคุณกำลังทำงาน
  • สร้างฐานข้อมูลชื่อ dms_db (หรือตามที่คุณตั้งค่าใน .env)
  • นำไฟล์ SQL Scripts (01_..., 05_..., 06_...) ไปรันในฐานข้อมูลเพื่อสร้างตารางและใส่ข้อมูลเริ่มต้น
  1. รันแอปพลิเคชัน (Development Mode):
  • ใช้คำสั่งนี้เพื่อเริ่ม Backend server ในโหมดพัฒนา ซึ่งจะมีการรีสตาร์ทอัตโนมัติเมื่อมีการแก้ไขโค้ด

<!-- end list -->npm run start:dev

  1. ตรวจสอบการทำงาน:
  • หากทุกอย่างถูกต้อง คุณจะเห็น Log การเริ่มต้นทำงานและเชื่อมต่อฐานข้อมูลใน Terminal
  • เปิดเว็บเบราว์เซอร์แล้วไปที่ http://localhost:3001/api-docs เพื่อดูหน้าเอกสาร API ของ Swagger

3. สถาปัตยกรรมและโครงสร้างโปรเจกต์

Backend นี้ใช้สถาปัตยกรรมแบบ Modular ของ NestJS ซึ่งจัดระเบียบโค้ดตามฟังก์ชันการทำงาน (Feature) ทำให้ง่ายต่อการจัดการและขยายระบบ

โครงสร้างโฟลเดอร์หลัก:

src/
├── attachments/          # 📎 โมดูลจัดการไฟล์แนบ
├── audit-logs/           # 📋 โมดูลบันทึกการตรวจสอบ
├── auth/                 # 🔑 โมดูลยืนยันตัวตนและจัดการสิทธิ์
├── circulations/         # 🔄 โมดูลการเวียนเอกสาร
├── common/               # 🌐 โฟลเดอร์สำหรับโค้ดที่ใช้ร่วมกัน
├── contracts/            # 📑 โมดูลจัดการสัญญา
├── correspondences/      # 💌 โมดูลจัดการเอกสารหลัก
├── dashboard/            # 📊 โมดูลสำหรับ API หน้า Dashboard
├── drawings/             # 🖼️ โมดูลจัดการข้อมูล Drawing
├── lookup/               # 🗂️ โฟลเดอร์เก็บ Entity ที่เป็น Master Data
├── organizations/        # 🏢 โมดูลจัดการองค์กร
├── permissions/          # 🔐 โมดูลจัดการ Permissions
├── projects/             # 🏗️ โมดูลจัดการโครงการ
├── rbac/                 # 🧑‍💼 โมดูลจัดการการกำหนดสิทธิ์ (RBAC)
├── reports/              # 📈 โมดูลสร้างรายงาน
├── roles/                # 🛡️ โมดูลจัดการ Roles
├── tags/                 # 🏷️ โมดูลจัดการแท็ก
├── technical-docs/       # ⚙️ โมดูลเอกสารทางเทคนิค
├── users/                # 👤 โมดูลจัดการผู้ใช้
├── app.module.ts         # Root Module ที่รวบรวมทุก Module
└── main.ts               # ไฟล์เริ่มต้นของแอปพลิเคชัน

------MultipartBoundary--VhiUdJuxlxmxWrLaXiSlRP2gfR2PuYkGvhdYgSLHby---- Content-Type: text/css Content-Transfer-Encoding: binary Content-Location: https://themes.googleusercontent.com/fonts/css?kit=kbffV7V9BIH3Ot2AQ2LQRA @charset "utf-8"; @font-face { font-family: Courier; font-style: normal; font-weight: 400; src: url("https://fonts.gstatic.com/l/font?kit=i7dKIFtyYSaNG9A_JrmedWxeSFI&skey=415f62b718dd1a36&v=v12") format("woff2"); unicode-range: U+0-FF, U+131, U+152-153, U+2BB-2BC, U+2C6, U+2DA, U+2DC, U+304, U+308, U+329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; } ------MultipartBoundary--VhiUdJuxlxmxWrLaXiSlRP2gfR2PuYkGvhdYgSLHby---- Content-Type: text/css Content-Transfer-Encoding: binary Content-Location: cid:css-a43a30ce-0932-481b-8734-60b84ca204e0@mhtml.blink @charset "utf-8"; @import url("https://themes.googleusercontent.com/fonts/css?kit=kbffV7V9BIH3Ot2AQ2LQRA"); ol.lst-kix_list_7-0 { list-style-type: none; } ul.lst-kix_list_1-0 { list-style-type: none; } ol.lst-kix_list_3-0 { list-style-type: none; } .lst-kix_list_3-0 > li::before { content: "" counter(lst-ctn-kix_list_3-0) ". "; } ul.lst-kix_list_5-7 { list-style-type: none; } ul.lst-kix_list_5-8 { list-style-type: none; } .lst-kix_list_3-1 > li::before { content: "○ "; } .lst-kix_list_3-2 > li::before { content: "■ "; } ul.lst-kix_list_5-5 { list-style-type: none; } ul.lst-kix_list_5-6 { list-style-type: none; } .lst-kix_list_8-1 > li::before { content: "○ "; } .lst-kix_list_4-0 > li { counter-increment: lst-ctn-kix_list_4-0 1; } .lst-kix_list_8-2 > li::before { content: "■ "; } .lst-kix_list_5-0 > li { counter-increment: lst-ctn-kix_list_5-0 1; } .lst-kix_list_6-0 > li { counter-increment: lst-ctn-kix_list_6-0 1; } .lst-kix_list_7-0 > li { counter-increment: lst-ctn-kix_list_7-0 1; } .lst-kix_list_8-0 > li { counter-increment: lst-ctn-kix_list_8-0 1; } ul.lst-kix_list_1-3 { list-style-type: none; } .lst-kix_list_3-5 > li::before { content: "■ "; } ul.lst-kix_list_1-4 { list-style-type: none; } ul.lst-kix_list_1-1 { list-style-type: none; } .lst-kix_list_3-4 > li::before { content: "■ "; } ul.lst-kix_list_1-2 { list-style-type: none; } ul.lst-kix_list_5-3 { list-style-type: none; } ul.lst-kix_list_1-7 { list-style-type: none; } .lst-kix_list_3-3 > li::before { content: "■ "; } ul.lst-kix_list_5-4 { list-style-type: none; } ul.lst-kix_list_1-8 { list-style-type: none; } ul.lst-kix_list_5-1 { list-style-type: none; } .lst-kix_list_8-0 > li::before { content: "" counter(lst-ctn-kix_list_8-0) ". "; } ul.lst-kix_list_1-5 { list-style-type: none; } ul.lst-kix_list_5-2 { list-style-type: none; } ul.lst-kix_list_1-6 { list-style-type: none; } .lst-kix_list_8-7 > li::before { content: "■ "; } .lst-kix_list_3-8 > li::before { content: "■ "; } .lst-kix_list_8-5 > li::before { content: "■ "; } .lst-kix_list_8-6 > li::before { content: "■ "; } .lst-kix_list_2-0 > li { counter-increment: lst-ctn-kix_list_2-0 1; } .lst-kix_list_8-3 > li::before { content: "■ "; } .lst-kix_list_3-6 > li::before { content: "■ "; } .lst-kix_list_3-7 > li::before { content: "■ "; } .lst-kix_list_8-4 > li::before { content: "■ "; } ol.lst-kix_list_5-0.start { counter-reset: lst-ctn-kix_list_5-0 0; } .lst-kix_list_8-8 > li::before { content: "■ "; } .lst-kix_list_5-0 > li::before { content: "" counter(lst-ctn-kix_list_5-0) ". "; } ol.lst-kix_list_6-0 { list-style-type: none; } ol.lst-kix_list_2-0 { list-style-type: none; } .lst-kix_list_4-8 > li::before { content: "■ "; } .lst-kix_list_5-3 > li::before { content: "■ "; } .lst-kix_list_4-7 > li::before { content: "■ "; } .lst-kix_list_5-2 > li::before { content: "■ "; } .lst-kix_list_5-1 > li::before { content: "○ "; } ul.lst-kix_list_4-8 { list-style-type: none; } .lst-kix_list_5-7 > li::before { content: "■ "; } ul.lst-kix_list_8-4 { list-style-type: none; } ul.lst-kix_list_8-5 { list-style-type: none; } ul.lst-kix_list_4-6 { list-style-type: none; } .lst-kix_list_5-6 > li::before { content: "■ "; } .lst-kix_list_5-8 > li::before { content: "■ "; } ul.lst-kix_list_8-2 { list-style-type: none; } ul.lst-kix_list_4-7 { list-style-type: none; } ul.lst-kix_list_8-3 { list-style-type: none; } ul.lst-kix_list_8-8 { list-style-type: none; } ul.lst-kix_list_8-6 { list-style-type: none; } ul.lst-kix_list_8-7 { list-style-type: none; } ul.lst-kix_list_4-1 { list-style-type: none; } .lst-kix_list_5-4 > li::before { content: "■ "; } ul.lst-kix_list_4-4 { list-style-type: none; } .lst-kix_list_5-5 > li::before { content: "■ "; } ul.lst-kix_list_4-5 { list-style-type: none; } ul.lst-kix_list_8-1 { list-style-type: none; } ul.lst-kix_list_4-2 { list-style-type: none; } ul.lst-kix_list_4-3 { list-style-type: none; } .lst-kix_list_6-1 > li::before { content: "○ "; } .lst-kix_list_6-3 > li::before { content: "■ "; } .lst-kix_list_6-0 > li::before { content: "" counter(lst-ctn-kix_list_6-0) ". "; } .lst-kix_list_6-4 > li::before { content: "■ "; } .lst-kix_list_3-0 > li { counter-increment: lst-ctn-kix_list_3-0 1; } ol.lst-kix_list_4-0.start { counter-reset: lst-ctn-kix_list_4-0 0; } .lst-kix_list_6-2 > li::before { content: "■ "; } .lst-kix_list_6-8 > li::before { content: "■ "; } ol.lst-kix_list_8-0.start { counter-reset: lst-ctn-kix_list_8-0 0; } .lst-kix_list_6-5 > li::before { content: "■ "; } .lst-kix_list_6-7 > li::before { content: "■ "; } .lst-kix_list_7-0 > li::before { content: "" counter(lst-ctn-kix_list_7-0) ". "; } .lst-kix_list_6-6 > li::before { content: "■ "; } ol.lst-kix_list_5-0 { list-style-type: none; } .lst-kix_list_2-6 > li::before { content: "■ "; } .lst-kix_list_2-7 > li::before { content: "■ "; } .lst-kix_list_7-4 > li::before { content: "■ "; } .lst-kix_list_7-6 > li::before { content: "■ "; } .lst-kix_list_2-4 > li::before { content: "■ "; } .lst-kix_list_2-5 > li::before { content: "■ "; } .lst-kix_list_2-8 > li::before { content: "■ "; } .lst-kix_list_7-1 > li::before { content: "○ "; } .lst-kix_list_7-5 > li::before { content: "■ "; } .lst-kix_list_7-2 > li::before { content: "■ "; } .lst-kix_list_7-3 > li::before { content: "■ "; } ul.lst-kix_list_7-5 { list-style-type: none; } ul.lst-kix_list_7-6 { list-style-type: none; } ul.lst-kix_list_7-3 { list-style-type: none; } ul.lst-kix_list_3-7 { list-style-type: none; } ul.lst-kix_list_7-4 { list-style-type: none; } ul.lst-kix_list_3-8 { list-style-type: none; } ul.lst-kix_list_7-7 { list-style-type: none; } ul.lst-kix_list_7-8 { list-style-type: none; } ol.lst-kix_list_3-0.start { counter-reset: lst-ctn-kix_list_3-0 0; } ul.lst-kix_list_3-1 { list-style-type: none; } ul.lst-kix_list_3-2 { list-style-type: none; } .lst-kix_list_7-8 > li::before { content: "■ "; } ul.lst-kix_list_7-1 { list-style-type: none; } ul.lst-kix_list_3-5 { list-style-type: none; } ul.lst-kix_list_7-2 { list-style-type: none; } ul.lst-kix_list_3-6 { list-style-type: none; } ul.lst-kix_list_3-3 { list-style-type: none; } .lst-kix_list_7-7 > li::before { content: "■ "; } ul.lst-kix_list_3-4 { list-style-type: none; } .lst-kix_list_4-0 > li::before { content: "" counter(lst-ctn-kix_list_4-0) ". "; } .lst-kix_list_4-1 > li::before { content: "○ "; } .lst-kix_list_4-4 > li::before { content: "■ "; } .lst-kix_list_4-3 > li::before { content: "■ "; } .lst-kix_list_4-5 > li::before { content: "■ "; } .lst-kix_list_4-2 > li::before { content: "■ "; } .lst-kix_list_4-6 > li::before { content: "■ "; } ol.lst-kix_list_7-0.start { counter-reset: lst-ctn-kix_list_7-0 0; } ol.lst-kix_list_4-0 { list-style-type: none; } ul.lst-kix_list_6-6 { list-style-type: none; } ul.lst-kix_list_6-7 { list-style-type: none; } ul.lst-kix_list_6-4 { list-style-type: none; } ul.lst-kix_list_2-8 { list-style-type: none; } ul.lst-kix_list_6-5 { list-style-type: none; } ul.lst-kix_list_6-8 { list-style-type: none; } ul.lst-kix_list_2-2 { list-style-type: none; } .lst-kix_list_1-0 > li::before { content: "● "; } ul.lst-kix_list_2-3 { list-style-type: none; } ul.lst-kix_list_2-1 { list-style-type: none; } ul.lst-kix_list_6-2 { list-style-type: none; } ol.lst-kix_list_8-0 { list-style-type: none; } ul.lst-kix_list_2-6 { list-style-type: none; } ul.lst-kix_list_6-3 { list-style-type: none; } .lst-kix_list_1-1 > li::before { content: "○ "; } .lst-kix_list_1-2 > li::before { content: "■ "; } ol.lst-kix_list_2-0.start { counter-reset: lst-ctn-kix_list_2-0 0; } ul.lst-kix_list_2-7 { list-style-type: none; } ul.lst-kix_list_2-4 { list-style-type: none; } ul.lst-kix_list_6-1 { list-style-type: none; } ul.lst-kix_list_2-5 { list-style-type: none; } .lst-kix_list_1-3 > li::before { content: "■ "; } .lst-kix_list_1-4 > li::before { content: "■ "; } .lst-kix_list_1-7 > li::before { content: "■ "; } .lst-kix_list_1-5 > li::before { content: "■ "; } .lst-kix_list_1-6 > li::before { content: "■ "; } .lst-kix_list_2-0 > li::before { content: "" counter(lst-ctn-kix_list_2-0) ". "; } .lst-kix_list_2-1 > li::before { content: "○ "; } ol.lst-kix_list_6-0.start { counter-reset: lst-ctn-kix_list_6-0 0; } .lst-kix_list_1-8 > li::before { content: "■ "; } .lst-kix_list_2-2 > li::before { content: "■ "; } .lst-kix_list_2-3 > li::before { content: "■ "; } ------MultipartBoundary--VhiUdJuxlxmxWrLaXiSlRP2gfR2PuYkGvhdYgSLHby---- Content-Type: image/png Content-Transfer-Encoding: binary Content-Location: https://ssl.gstatic.com/docs/common/mobileweb_sprite1.png PNG  IHDR$ UIDATh[[lWΙٛn 8Ik'm\*VEBj51/T5PZ&чJ *ch ܀B)I+!XNHbr:w*>z˅ۦz,3?0u%K/ݚ=sl, XGfѪڎꂒ"ԷU L*ݟ(9 ?/(ϥdb}۽TAq(&c~@̸ ($ L Dҩ:?slxt4eHY' L]; tzMc;#) >bs{SSL.#T<@Sc$T ǝ)9 0*e,Ok=DDAi?3b'_ OP&^`WX?nf0[ט> 2P_"cTd"$`i6'WjEŒF V*4 +7I ;f,RlxLwMÕ=f13dtb zM}b-`"@2)q.wJQ-ޙX=r1/caOڭxfֆ x ӏUbX'Wo}fPb3\=~*kULi_mpIe=$S5~ zS0McH^Z&:9 ([ k5|ǡ8=ˮI$;=e?:HoFy, FXQcC7 aN#Q3ZGH:9%m@  8U#'ږKN{ūvF±01ߜFˮӳN,PcT^>z_<^KGc5yۉg_I 49f1|Yډ4FF,NGuA)jUXd:8A$lkC50'S[=+ tbbٱѓfcPg%w-\c)m* "<%i1lBDc 1(/™3sbΙ4 C kW!BUde6V$ 9iMX\٩ \AN1Ba >O \';2LV(\v "]Le6 \Ėe|v$``hʂ)gzEN 2W_Vnhhp~ `*,#rDv NjU,bO -a-ST?+%ߘqw2Yȋ<#je\(܃PTbC1BDP1<&xܞeUGcH@cdp c#g93#;^K@Kct$ ߿1i0yOZh@}..M.'|f|FŌs M ̂дfki0[o&0T`l` B' LZfbS~8X'7"l[S7Ļ;3A6 킀xgW5l|k?XFk?Hp^[:n?b, L/c@ұ+&3lޒ<0])ᜂKhd VWmI7+c\,)ݮP*?Z/0pŹ u|ԾUB)]+KƔ8s?Z+r`כּe MԶ2Cy|MfS&9ѽ̄i/%ڝfP' սµ[=ߌX?V/$ 5c,b1HBSȿE+5@{ 4(:]