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

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

เอกสารนี้รวบรวมรายละเอียดทั้งหมดของส่วน Frontend สำหรับระบบ LCBP3 Document Management System ซึ่งพัฒนาด้วย Next.js (App Router), TypeScript, Tailwind CSS, และ shadcn/ui

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

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

  • Node.js: เวอร์ชัน 18.x หรือสูงกว่า
  • NPM หรือ Yarn: ตัวจัดการ Package (มาพร้อมกับ Node.js)
  • Git: สำหรับการ Clone โปรเจกต์จาก Gitea

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

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

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

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

<!-- end list -->npm install

  1. ตั้งค่า Environment File:
  • สร้างไฟล์ใหม่ชื่อ .env.local ที่รากของโปรเจกต์
  • กำหนด URL ของ Backend API ที่จะให้ Frontend เชื่อมต่อ

ไฟล์ .env.local:# URL ของ NestJS Backend (ที่รันผ่าน Docker)
NEXT_PUBLIC_API_BASE_URL=http://localhost:3001

  1. รันแอปพลิเคชัน (Development Mode):
  • ใช้คำสั่งนี้เพื่อเริ่ม Frontend server ในโหมดพัฒนา

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

  1. ตรวจสอบการทำงาน:
  • เปิดเว็บเบราว์เซอร์แล้วไปที่ http://localhost:3000
  • คุณควรจะเห็นหน้า Landing Page ของระบบ

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

Frontend นี้ใช้ App Router ของ Next.js ซึ่งเป็นสถาปัตยกรรมสมัยใหม่ที่เน้นการทำ Server-Side Rendering (SSR) และ Server Components เพื่อประสิทธิภาพสูงสุด

  • Framework: Next.js 14+ (App Router)
  • ภาษา: TypeScript
  • Styling: Tailwind CSS
  • Component Library: shadcn/ui (ไม่ใช่ Library แต่เป็นชุดของ Reusable Components ที่สามารถปรับแต่งได้)
  • State Management: React Context API (สำหรับ Global Authentication State)
  • Data Fetching: ใช้ API Routes ของ Next.js เป็น Proxy เพื่อสื่อสารกับ Backend อย่างปลอดภัย

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

frontend-np-dms/
├── app/
│   ├── (auth)/             # Group สำหรับหน้าหลัง Login (มี Layout พร้อม Navbar/Sidebar)
│   │   ├── admin/
│   │   ├── correspondences/
│   │   ├── dashboard/
│   │   └── layout.tsx
│   ├── (public)/           # Group สำหรับหน้าสาธารณะ (มี Layout แบบว่าง)
│   │   ├── login/
│   │   └── layout.tsx
│   ├── api/                # API Routes ที่ทำหน้าที่เป็น Proxy ไปยัง Backend
│   ├── globals.css
│   └── layout.tsx          # Root Layout (ที่ห่อหุ้มด้วย AuthProvider)
├── components/             # ที่เก็บ UI Components ที่สร้างด้วย shadcn และ Components ที่สร้างขึ้นเอง
│   ├── dashboard/
│   ├── layout/
│   ├── rfa/
│   └── ui/
├── contexts/               # ที่เก็บ React Context สำหรับ Global State
│   └── AuthContext.tsx
├── lib/                    # ที่เก็บฟังก์ชันเสริม (เช่น utils.ts จาก shadcn)
├── public/                 # ที่เก็บไฟล์สาธารณะ เช่น รูปภาพ, favicon
├── types/                  # (แนะนำ) ที่เก็บ TypeScript type definitions ที่ใช้ร่วมกัน
├── middleware.ts           # ไฟล์สำคัญสำหรับป้องกัน Route (Route Protection)
└── package.json

------MultipartBoundary--csF0EXC0RJ3vOG6iJZx4sbJHPtjAmchlkrKXyomDzE---- 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--csF0EXC0RJ3vOG6iJZx4sbJHPtjAmchlkrKXyomDzE---- Content-Type: text/css Content-Transfer-Encoding: binary Content-Location: cid:css-8579d4bc-81a4-446d-b2aa-5e3d220689ab@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; } 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: "● "; } 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_8-0 { list-style-type: none; } 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: "■ "; } .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; } 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--csF0EXC0RJ3vOG6iJZx4sbJHPtjAmchlkrKXyomDzE---- 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(:]