Skip to content

7.2.2 · Boot, routing, API calls, auth flow

branch: UAT


Boot sequence

1. next.config.js
      basePath '/meetingbo'
      withSentryConfig(...)          next.config.js:21,38
      typescript.ignoreBuildErrors   :13-18

2. _app.tsx
      appWithTranslation(MyApp)
      CacheProvider → ThemeProvider → Layout → page
      ไม่มี auth redirect              _app.tsx:20-37

3. Layout.tsx
      Navbar + Sidebar ทุกหน้า

4. Page
      · index / listapprover → getStaticProps (SSG ที่ build time)
      · creategroup / editgroup / createapprover → client axios
      · [token] → useEffect axios redirectbypass

Routing detail

SSG pages — ข้อมูลค้างตามรอบ build

pages/index.tsx:29-48:

tsx
export const getStaticProps: GetStaticProps = async ({ locale }) => {
  const res = await fetch(
    `${process.env.NEXT_PUBLIC_APP_MEETING_API}/secure/group/listgroup`
  );
  const result = await res.json();
  // ...
  return {
    props: {
      data,
      ...(await serverSideTranslations(locale as string, ['home'])),
    },
  };
};
  • ไม่มี revalidate → ไม่ใช่ ISR — รายการกลุ่มเปลี่ยนที่ backend จะไม่ขึ้นจนกว่า rebuild/redeploy
  • fetch ไม่มี header Authorization / X-API-Key
  • ใช้ serverSideTranslations สำหรับ i18n namespace home

listapprover/index.tsx ใช้ pattern เดียวกันกับ listApprover endpoint

Client mutation pages

หน้าสร้าง/แก้ ยิง axios ตอนผู้ใช้กดปุ่ม — ได้ข้อมูลสดกว่า list หน้าแรกที่เป็น SSG

ตัวอย่าง create group (creategroup/index.tsx:349):

POST ${NEXT_PUBLIC_APP_MEETING_API}/secure/group/creategroup

Dropdown org chain:

  1. GET .../secure/finddropdownbyorg/org/
  2. GET .../secure/finddropdownbyorg/division/
  3. GET .../secure/finddropdownbyorg/department/
  4. GET .../secure/finduserlistbyorg

(พบใน creategroup, editgroup, createapprover)


แคตตาล็อก API ทั้งหมดที่พบใน src/pages

Base: process.env.NEXT_PUBLIC_APP_MEETING_API (= UAT /meeting จาก .env:13)

MethodPathCall site
GET/secure/group/listgroupindex.tsx:30, editgroup:321
POST/secure/group/creategroupcreategroup:349
POST/secure/group/editgroupeditgroup:413
GET/secure/approver/listApproverlistapprover:30, createapprover:169
POST/secure/approver/addNewApprovercreateapprover:377
(delete)/secure/approver/deleteapprovercreateapprover:365
GET/secure/finduserlistbyorgcreate/edit/approver pages
GET/secure/finddropdownbyorg/org/同上
GET/secure/finddropdownbyorg/division/同上
GET/secure/finddropdownbyorg/department/同上
GET/redirectbypass[token].tsx:14

Base 2way: NEXT_PUBLIC_APP_2WAY_API (.env:14)

MethodPathCall site
POST/getUserByConditioncreategroup:392, createapprover:415

หมายเหตุ: ใน meeting-backoffice (UAT) การเรียก getUserByCondition ไม่แนบ Authorization header — ต่างจาก meeting-backoffice-new ที่ hardcode Bearer testnaja


Auth flow — [token].tsx

ทางเข้าเดียวที่มี token ใน repo นี้:

External system
  └── redirect → /meetingbo/{token}
        └── [token].tsx useEffect
              └── GET {MEETING_API}/redirectbypass
                    headers:
                      Authorization: Bearer {tokenID}
                      X-API-Key: "01010101"          ← hardcode ใน frontend


              response.data.token
                    └── setToken → localStorage.accessToken
                    └── router.replace("/meetingbo")

หลักฐาน: pages/[token].tsx:12-28, utils/auth.tsx:1-11

ข้อเท็จจริงสำคัญเรื่อง auth ที่ตามมา

  1. X-API-Key: "01010101" ฝังใน client bundle ([token].tsx:20) — ใครเปิด sources เห็นได้
  2. หลังได้ token เก็บใน localStorage แล้ว — หน้าอื่นไม่ได้อ่าน token ไปใส่ header ของ /secure/* (ไม่พบ getToken() usage ใน pages อื่น)
  3. จึงสรุปจากโค้ดฝั่ง UI ได้ว่า: การป้องกันการเข้าถึงหน้า list/CRUD ไม่ได้อยู่ที่ frontend route guard — พึ่ง path secrecy + พฤติกรรม backend /secure/* (ดู scorecard ของ meeting-vtrc-api)
  4. ต้นทางที่สร้างลิงก์ /meetingbo/{token} ไม่ได้อยู่ใน repo นี้ → UNVERIFIED ว่าใคร generate (อาจเป็น legacy backoffice / meeting API อื่น)

index.layout = "L3" ถูกตั้งใน [token].tsx:56 แต่ _app ของ repo นี้ ไม่ได้ อ่าน Component.layout (ต่างจาก 2way-meeting-backoffice) — ค่านี้ไม่มีผลต่อ Layout


Env resolution (ไม่มี checkLinkURL)

ต่างจาก legacy vtrc-web ที่สลับ endpoint ตาม window.location.href — repo นี้ฝัง NEXT_PUBLIC_* ตอน build จาก .env

Environmentวิธีได้ค่า
Local / Docker ตาม Dockerfileอ่าน .env ที่ copy เข้า image (UAT URLs)
build:productionenv-cmd -f .env next build

ถ้าต้องการชี้ production host ต้องเปลี่ยน .env แล้ว rebuild — ไม่มี runtime switch ในโค้ด


i18n

  • next-i18next + serverSideTranslations บน SSG pages
  • public/locales/en และ de มีไฟล์ — ไม่มี th ในโฟลเดอร์ locales ที่ตรวจ ทั้งที่ UI ข้อความใน Sidebar/หน้าเป็นภาษาไทย hardcode ใน JSX (Sidebar.tsx:46-58)
  • Locale เยอรมันเป็นซาก starter template

Error page และ Sentry capture path

pages/_error.js import @sentry/nextjs และเรียก Sentry.captureException เมื่อมี err — แต่ถ้า Sentry.init ถูก comment ใน config ไฟล์ client/server การส่ง event อาจไม่ไปถึง project (ขึ้นกับว่า SDK no-op อย่างไรเมื่อยังไม่ init) — ดู 03


เปรียบเทียบสั้นกับ meeting-backoffice-new

หัวข้อmeeting-backoffice (UAT)meeting-backoffice-new (UAT)
RouterNext Pages + basePath /meetingboCRA + PUBLIC_URL /meeting-backoffice
List dataSSG getStaticPropsuseEffect fetch ทุกครั้ง
Auth entryมี [token].tsxไม่มี
2way search authไม่แนบ Bearerhardcode Bearer testnaja
Sentry depมี (init comment)ไม่มี
Embed ใน vtrc-backofficeไม่ใช่ artifact ที่ฝังใช่ (build/ shasum ตรง)

Approver save flow (delete แล้ว add)

createapprover/index.tsx:363-392 เมื่อบันทึก:

1. สร้าง body จากรายการที่เลือก:
      { empCode, sourceDB: "dbHRMI_RC_C_rep" }   ← sourceDB hardcode
2. สร้าง delBody จากรายการที่ลบ (sourceDB เดียวกัน)
3. axios.delete(.../secure/approver/deleteapprover, { data: { deleteApprover: delBody } })
4. ใน .then → axios.post(.../secure/approver/addNewApprover, { addApprover: body })
5. สำเร็จ → router.push('/listapprover')

ลำดับนี้หมายความว่า:

  • ทุกครั้งที่เซฟจะพยายาม ลบชุดหนึ่งก่อน แล้วค่อยเพิ่ม — ไม่ใช่ PATCH ทีละคน
  • sourceDB ถูก hardcode เป็น "dbHRMI_RC_C_rep" (createapprover/index.tsx:351,358) — ถ้า org มาจาก DB อื่นจะผิดแหล่ง
  • Headers ที่ส่งมีแค่ Accept / Content-Typeไม่มี Authorization จาก localStorage

Create / edit group — พฤติกรรมหลัก

ทั้งสองหน้ามี pattern คล้ายกัน (~700 บรรทัด/ไฟล์):

  1. โหลด dropdown org → division → department จาก meeting API
  2. ค้นหาพนักงานด้วย getUserByCondition ผ่าน 2way API (pagination limit/offset)
  3. ผู้ใช้เลือกสมาชิกเข้าตาราง
  4. Submit creategroup หรือ editgroup

Edit รับ groupID จาก query (Listsgroup ส่งมา) แล้วโหลด listgroup อีกรอบเพื่อหาแถวที่จะแก้ (editgroup/index.tsx:321)


Favicon / public asset path

pages/index.tsx:17 อ้าง href="/meetingbo/favicon.ico" — สอดคล้อง basePath (ต้องใส่ prefix เองเมื่อใช้ <link> ดิบ ไม่ผ่าน Next asset helper)