4.1 · vtrc-web Deep Dive
vtrc-web คือเว็บแอปฝั่งพนักงานของสภากาชาดไทย — ดูสลิปเงินเดือน, ยื่นคำขอลา, เบิกสวัสดิการรักษาพยาบาล, ดูข่าวสารและนโยบาย, จัดการกองทุนสงเคราะห์, สมัครงาน และอื่น ๆ เป็น React 16.14 + Apollo Client v2 (react-apollo@3.1.5) + AntD v3.26 + Webpack 4.42 ที่ ejected จาก CRA (vtrc-web/package.json:75,76,20,106) รันที่ https://vtrc.redcross.or.th/ (prod) และ https://uat-vtrc.redcross.or.th/ (UAT) — ทั้งคู่ใช้ bundle ตัวเดียวกัน ที่เลือก GraphQL endpoint ตอน runtime ผ่าน checkLinkURL() (vtrc-web/src/config/apollo.js:17-34)
คู่สมรสคือ vtrc-rc-backoffice (ฝั่ง HR — Volume 4.2) ใช้ pattern คล้ายกันแต่คนละเวอร์ชัน library (AntD v3 vs v4, Webpack vs CRA, class + withApollo vs Recoil) ห้ามสับสน
เป้าหมายของ Volume นี้
ให้ผู้อ่านเข้าใจโครงสร้างของ vtrc-web/src/, รู้จุดที่ต้องระวัง, และสามารถแก้ไขหรือเพิ่มฟีเจอร์ได้โดยไม่ทำลาย pattern ที่มีอยู่ เอกสารนี้เป็นแผนที่ ไม่ใช่ตัวแทนของโค้ด — ควรเปิดไฟล์จริงใน repo ควบคู่กับการอ่าน
Tech stack (verify กับ vtrc-web/package.json 2026-07-13)
| Layer | Tech | เวอร์ชัน | Citation |
|---|---|---|---|
| UI runtime | React | 16.14 | vtrc-web/package.json:75 |
| React DOM | react-dom | 16.14 | vtrc-web/package.json:81 |
| GraphQL client | react-apollo (Apollo Client v2 HOC) | 3.1.5 | vtrc-web/package.json:76 |
| apollo-client core | apollo-client | 2.6.3 | vtrc-web/package.json:22 |
| Component lib | antd | 3.26.20 | vtrc-web/package.json:20 |
| Routing | react-router-dom | 5.3.3 | vtrc-web/package.json:92 |
| Date library | moment | 2.29.4 | vtrc-web/package.json:64 |
| Build tool | webpack (CRA ejected) | 4.42.0 | vtrc-web/package.json:106 |
| Dev server | webpack-dev-server | 3.11.0 | vtrc-web/package.json:107 |
| Bundler minify | terser-webpack-plugin | 2.3.8 | vtrc-web/package.json:101 |
| HTTP (REST) | axios | 0.21.4 | vtrc-web/package.json:29 |
| State (lightweight) | styled-components, lodash, uuid | — | vtrc-web/package.json:62,100,105 |
| File upload | apollo-upload-client | 11.0.0 | vtrc-web/package.json:28 |
| Drag and drop | react-dnd, react-dnd-html5-backend | 11.1.3 | vtrc-web/package.json:79,80 |
| PDF viewer | react-pdf, pdfjs-dist, react-pdf-to-image | — | vtrc-web/package.json:90,68,91 |
| Container (Docker) | node + nginx | 14.20 / 1.24.0 | vtrc-web/Dockerfile:1,11 |
ห้าม upgrade React เป็น 17/18, Apollo เป็น v3, หรือ AntD ข้าม major โดยไม่ได้รับมอบหมาย — breaking change เพราะ HOC withApollo deprecated ใน Apollo v3, AntD v3 ใช้ LocaleProvider + Form.create ที่หายไปใน v4, React 17 เปลี่ยน event delegation
Branch info
- Default/canonical branch —
master(default repo branch ที่ GitHub รู้จัก) ไม่มี patternprod/uatแยกเหมือนหลาย repo ใน workspace - Working directory — 1,055 ไฟล์ทั้ง repo (รวม build/ และ node_modules) เนื้อที่จริงใน
src/ประมาณ 18,000 บรรทัดรวม - CI/CD —
bitbucket-pipelines.ymltrigger branchfeature/cicd,develop,uat,prodทำ pipeline เดียวกัน (build-front-end-production→build-docker→push-image-to-registry) - No
.envใน workspace — env-specific ทำงานที่ runtime ผ่านwindow.location.hrefทั้งหมด bundle ตัวเดียวใช้กับทุก env
ตัวเลขที่ควรจำ
| ตัวเลข | ค่า | Citation |
|---|---|---|
| GraphQL queries | 138 ตัว (export default keys) | vtrc-web/src/graphql/queries.js (4,493 บรรทัด) |
| GraphQL mutations | 41 ตัว | vtrc-web/src/graphql/mutations.js (1,447 บรรทัด) |
| Page folders | 48 โฟลเดอร์ (11 cluster) | vtrc-web/src/pages/user/ |
| Routes table | 1,410 บรรทัด | vtrc-web/src/config/routes.js |
| Shell (SiderLayout) | 1,226 บรรทัด | vtrc-web/src/components/user/SiderLayout/index.js |
| Leave Form (ใหญ่สุด) | 2,410 บรรทัด | vtrc-web/src/pages/user/Leave/Form/index.js |
| Slip page | 1,528 บรรทัด | vtrc-web/src/pages/user/Slip/index.js |
| Login page | 650 บรรทัด | vtrc-web/src/pages/user/Login/index.js |
ไฟล์ _bk* legacy/backup | 55 ไฟล์ | find in src/ |
dangerouslySetInnerHTML | 52 ไฟล์ทั่ว src/ | grep |
| AntD override (compiled CSS) | 21,190 บรรทัด | vtrc-web/src/config/custom-antd.css |
| GA4 ID | G-LKXD2EBDZ4 | vtrc-web/public/index.html:32 |
| AES key hardcoded | "6A45soD%9eB#" | vtrc-web/src/utils/auth.js:38,41 |
| Node (Docker) | 14.20 (EOL เม.ย. 2566) | vtrc-web/Dockerfile:1 |
สไตล์โค้ด — 3 ข้อที่ต้องจำ
- class component +
withApolloHOC เป็นหลัก — ไม่มีuseQuery, ไม่มี<Query>/<Mutation>render props, ไม่มี function component ยกเว้นApp/index.js(vtrc-web/src/containers/App/index.js:14) fetchPolicy: 'no-cache'เป็น default ทุก query/watchQuery — cache ของ Apollo แทบไม่ถูกใช้ (vtrc-web/src/config/apollo.js:171-182)- endpoint เลือกตอน runtime ด้วย
window.location.href.includes(...)ในcheckLinkURL()— ไม่ใช้NODE_ENVหรือREACT_APP_*(vtrc-web/src/config/apollo.js:17-34)
โครงสร้าง src/ ระดับบน
vtrc-web/
├── package.json — deps + 3 scripts (start/build/test)
├── Dockerfile — 2 stages: node:14.20 build → nginx:1.24.0 serve
├── bitbucket-pipelines.yml — CI/CD
├── nginx-config/default.conf — server block + SPA fallback
├── public/index.html — title + GA4 gtag inline
├── config/ — CRA ejected (webpack/env/paths)
└── src/
├── index.js 93 บรรทัด — entry + ApolloProvider + LocaleProvider th_TH
├── index_bk.js 124 บรรทัด — legacy entry (ห้ามแตะ)
├── serviceWorker.js 135 บรรทัด — CRA SW (เรียก unregister)
├── assets/ — css, sass, fonts, images, pdf
├── components/
│ ├── element/ 3 ไฟล์ — reusable UI เล็ก ๆ
│ └── user/ 36 โฟลเดอร์ — domain components (รวม `from/` = typo ของ `Form`)
├── config/
│ ├── apollo.js 184 บรรทัด — Apollo Client + errorLink + authLink
│ ├── routes.js 1,410 บรรทัด — route table + render helpers
│ ├── custom-antd.css 21,190 บรรทัด — AntD v3 override (compiled)
│ ├── axios-bo.js 85 บรรทัด — REST axios instance
│ ├── refreshToken.js 35 บรรทัด — token refresh promise wrapper
│ └── datasets*.js ~1,689 บรรทัด — dropdown master data
├── containers/App/index.js 35 บรรทัด — root router + auth gate
├── graphql/
│ ├── queries.js 4,493 บรรทัด — 138 queries
│ ├── mutations.js 1,447 บรรทัด — 41 mutations
│ └── index.js 2 บรรทัด — re-export Queries + Mutations
├── pages/user/ 48 โฟลเดอร์ — route screens (11 cluster)
└── utils/ 36 ไฟล์ — helpers (`auth.js`, `formatdate.js`, …)ไฟล์ legacy/backup — ห้ามแตะ ห้ามใช้เป็นต้นแบบ
vtrc-web มีไฟล์ backup/snapshot 55 ไฟล์ กระจายทั่ว repo จากการ deploy หลาย env และการทดลอง refactor ที่ยังไม่ลบ
| รูปแบบชื่อ | ตัวอย่าง |
|---|---|
_bk.js | src/index_bk.js, src/config/routes_bk.js, src/pages/user/Login/index_bk.js |
_bk<date>.js | src/config/routes_bk11072568.js |
_bk-prd.js/_bk-pro.js/_bkPpu.js | Leave/Form/index_bk-to-prd.js, detail_bk-prd.js |
_pentest, _prd (สะกดผิด) | queries_pentest.js, querries_prd.js |
_gql.js/_axios.js/_table.js | Contact/index_gql.js, index_axios.js, ChildEducationFee/index_table.js |
| ชื่อสะกดผิด | components/user/from/ (ควรเป็น Form — ห้ามแก้ชื่อ เพราะมี import อ้างถึงทั้งระบบ) |
กฎเหล็ก — (1) อย่าแก้ไฟล์ที่ลงท้ายด้วย suffix backup (2) อย่า copy โค้ดจากไฟล์เหล่านี้เป็นต้นแบบ (query อาจ deprecated) (3) อย่าลบทิ้งเองโดยไม่ตรวจ git history ก่อน
สารบัญ
| บท | หัวข้อ | คำถามที่ตอบ |
|---|---|---|
| 4.1.1 | Bootstrap + Webpack build + Apollo Client | แอปเริ่มที่ไหน สร้าง bundle อย่างไร ส่ง request อย่างไร เลือก endpoint อย่างไร |
| 4.1.2 | Routing + auth gate + Component patterns + GraphQL catalog | route ทำงานอย่างไร component ใช้ pattern อะไร มี query/mutation อะไรบ้าง |
| 4.1.3 | State + styling + locale (พ.ศ.) + security + scorecard | state อยู่ที่ไหน ใช้ CSS แบบไหน จัดการ พ.ศ. อย่างไร จุดเสี่ยงด้านความปลอดภัย สรุปสุขภาพ repo |
บทเต็มของ v1 (docs-v1-archive/volume-06-vtrc-web/) มี 10 บท + index (~3,325 บรรทัด) — v2 ย่อเป็น 3 บทหนา เนื้อหาเดียวกันแต่กลั่นกรองและ verify กับโค้ดปัจจุบัน (2026-07-13) ทุก claim
สิ่งที่ไม่ cover ใน Volume นี้
- GraphQL schema ฝั่ง
vtrc-api— cover ใน Volume 3 โดยเฉพาะ@auth(accessRole, accessMenu)directive - HRMI MSSQL schema ฝั่ง cu-central-api — cover ใน Volume 8 (Data Model, ยังไม่เขียน)
- business rule ของแต่ละฟีเจอร์ — cover ใน Volume 1 (Business, ยังไม่เขียน)
- vtrc-rc-backoffice — Volume 4.2 แยกต่างหาก (ใช้ AntD v4 + Recoil + MUI v5)
- Modern microservices (2way/benefit/pms/…) — Volume 5+ เป็นกลุ่ม NestJS แยกจาก Legacy Core
การเปลี่ยนแปลงจาก v1
เนื้อหาพอร์ตจาก docs-v1-archive/volume-06-vtrc-web/ และ verify ใหม่ทุก claim — สิ่งที่เปลี่ยน
- Meeting cluster ถูก comment out ทั้งหมด —
vtrc-web/src/config/routes.js:1170-1300มี meeting cluster ~130 บรรทัดที่ถูก comment ไว้ แสดงว่า vtrc-web ไม่ได้ใช้ meeting cluster แล้ว (ย้ายไปmeeting-backoffice/2way-meeting-backoffice) v1 บอกว่า meeting มี ~15 route ซึ่งตอนนี้เป็น 0 route ในroutesarray (แม้ component ยัง import อยู่ที่routes.js:73-95) _bk*ไฟล์ 55 ไฟล์ (v1 บอก "มากกว่า 50") — verify ด้วยfind src -name '*_bk*'dangerouslySetInnerHTML52 ไฟล์ (v1 บอก "20+") — มากกว่าที่ v1 รายงานอย่างมากformatdate.jsจริง ๆ 441 บรรทัด (v1 บอก 442),message.js/messages.jsจริง ๆ 29 บรรทัด (v1 บอก 30),markDown.js15 บรรทัด (v1 บอก 16),checkError.js71 บรรทัด (v1 บอก 72)
สิ่งที่ยังเหมือนเดิมจาก v1 — AES key hardcoded, apiKey prod base64, console override, checkLinkURL() substring match, fetchPolicy: 'no-cache', moment.locale('th'), Webpack 4 CRA ejected, Docker 2 stages, GA4 ID
วิธีอ่านเล่มนี้
- เวลาน้อย — อ่าน 4.1.1 (map + bootstrap + Apollo) + 4.1.3 (security + scorecard) ก็พอเข้าใจภาพรวม
- จะแก้ฟีเจอร์ — อ่าน 4.1.2 ก่อนหา route entry ของฟีเจอร์ แล้วดู query/mutation ใน catalog
- จะทำ security review — อ่าน 4.1.3 ก่อน แล้ว cross-check กับ Volume 9 (Security)
- จะ debug "หน้าขาว" — อ่านส่วน "ตอน debug หน้าขาว" ใน 4.1.1 ก่อน เพราะ console ถูกปิดไว้ที่
vtrc-web/src/containers/App/index.js:15
ขอแนะนำให้เปิดไฟล์จริงใน repo ควบคู่กับการอ่าน — คู่มือนี้เป็นแผนที่ ไม่ใช่ตัวแทนของโค้ด