Skip to content

vtrc-mobile

vtrc-mobile (branch: master, 1055 tracked files) คือแอปมือถือหลักของพนักงานสภากาชาดไทย — React Native ที่ดูแลมายาวนานที่สุดในกลุ่ม Mobile และมี business logic กว้างที่สุด (120 container ระดับบน + 21 ไฟล์ใน meeting-management/ = 141 ไฟล์ใต้ src/containers/, scene key ใน App.js มากกว่า 120 รายการ)

เทียบกับ sibling ใน Volume 8:

RepoบทบาทScreen / ขอบเขต
vtrc-mobile (master)Production ESS app121+ scene, leave / welfare / slip / PMS / recruitment / meeting
new-vtrc-mobileRewrite ระยะต้นscreen น้อยมาก (ดู new-vtrc-mobile)
vtrc-application-frontLanding / stubไม่มี screen business จริง

ชื่อ package ภายในคือ rn_redcross ไม่ใช่ vtrc-mobile — เป็นชื่อตอน scaffold ที่ไม่เคยถูกเปลี่ยน (vtrc-mobile/package.json:2, vtrc-mobile/app.json:1-4)


Stack

องค์ประกอบค่าหลักฐาน
React Native0.63.2vtrc-mobile/package.json:64
React16.13.1vtrc-mobile/package.json:63
Navigationreact-native-router-flux ^4.2.0 (Actions.* imperative, ไม่ใช่ @react-navigation)vtrc-mobile/package.json:99
State@reduxjs/toolkit ^1.4.0 + redux-persist ^6.0.0vtrc-mobile/package.json:31,124
Persist storagereact-native-sensitive-info ผ่าน custom adapter (keychain / SharedPreferences) — ไม่ใช่ AsyncStorage สำหรับ tokenvtrc-mobile/src/app/store.js:9,55-58, vtrc-mobile/src/app/redux-persist-sensitive-storage.js:1-38
GraphQL client@apollo/client ^3.1.3 มีอยู่ แต่ path หลักยิงผ่าน react-native-ssl-pinning ใน utils/fetch.jsvtrc-mobile/package.json:19, vtrc-mobile/src/gql/client.js:1-27, vtrc-mobile/src/utils/fetch.js:1-48
RESTaxios + fetchRestFull.js + meetingAPIvtrc-mobile/package.json:38, vtrc-mobile/src/utils/fetchRestFull.js:1-36, vtrc-mobile/src/utils/axios.js:1-23
Push@react-native-firebase/messaging ^7.8.6 + react-native-push-notification + iOS community pushvtrc-mobile/package.json:27,30,95
Biometricreact-native-biometrics ^2.1.4vtrc-mobile/package.json:65, vtrc-mobile/src/features/authSlice.js:953-1062
RSA (csId)crypto (Node polyfill) + PEM ใน login.jsvtrc-mobile/src/utils/login.js:6-74
RSA (biometric keypair)react-native-rsa-native สร้างคู่กุญแจตอนเปิด biometric ใน Settingvtrc-mobile/src/containers/Setting.js:36-43
Test1 ไฟล์ template (__tests__/App-test.js)vtrc-mobile/__tests__/App-test.js:1-14
Package manageryarn (yarn.lock)vtrc-mobile/yarn.lock

Entrypoint

ลำดับ boot:

index.js
  ├── import gesture-handler / reanimated
  ├── polyfills.js + performanceShim.js + shim.js   (Node crypto/stream polyfill)
  ├── initializeNotificationHandlers()              (ก่อน register component)
  └── AppRegistry.registerComponent(rn_redcross)
        │  `vtrc-mobile/index.js:1-23`, `vtrc-mobile/app.json:1-4`

App.js
  Provider(store) → PersistGate → SafeAreaProvider → Router/Stack/Scene×120+
        `vtrc-mobile/App.js:178-1071`

PersistGate.onBeforeLift (vtrc-mobile/App.js:194-224) ทำสามอย่างก่อน mount UI จริง:

  1. ถ้าไม่มี key firstRun ใน AsyncStorage → persist/PURGE แล้วตั้ง firstRun=true (App.js:195-200)
  2. เช็ก jailbreak/root ด้วย jail-monkey — ถ้าเจอและไม่ใช่ dev mode จะบังคับ RNExitApp.exitApp() (App.js:202-208)
  3. เรียก refreshToken(store.getState().auth.token) เพื่อ auto-login (App.js:210)

บล็อก fetchCheckUpdateVersion ใน onBeforeLift ถูก comment ปิดทั้งหมด (App.js:213-224) — ฟีเจอร์บังคับอัปเดตตอน cold start ไม่ทำงานจากจุดนี้ (หน้า CheckLogin ยังเรียกเองแยก — ดู 02-core-pipeline)

App.js ยาว 1,071 บรรทัด — import container ทั้งชุดแล้วประกาศ {Scene} แบบ flat ในไฟล์เดียว ไม่มี nested navigator / lazy load (vtrc-mobile/App.js:15-176 import, 228-1062 scenes)


Build config

แพลตฟอร์มค่าหลักฐาน
Android applicationIdcom.redcross.vtrcvtrc-mobile/android/app/build.gradle:149
Android versionName / versionCode1.9.12 / 139vtrc-mobile/android/app/build.gradle:154-155
Android SDKmin 23 / compile 34 / target 35vtrc-mobile/android/build.gradle:6-8
Android release signingpath + password hardcode ในซอร์ส ชี้เครื่อง dev คนหนึ่งvtrc-mobile/android/app/build.gradle:174-17904-scorecard § SEC-MOBILE-02
Hermesปิด (enableHermes: false)vtrc-mobile/android/app/build.gradle:81-82
iOS deployment target12.0vtrc-mobile/ios/Podfile:5
iOS target namern_redcrossvtrc-mobile/ios/Podfile:6
SSL pin cert assetandroid/app/src/main/assets/digicert2025.cerใช้ชื่อ digicert2025 ใน fetch.js:36

Scripts สำคัญใน package.json:5-16: start, ios / run-ios, run-android, build:apk-release, aab-ios (ชื่อสคริปต์ทำให้เข้าใจผิด — รัน Gradle Android จริง), postinstall รัน patch-package + rebuild react-native-sensitive-info + rn-nodeify


การเชื่อมต่อ backend

ต่างจาก vtrc-web ที่เลือก GraphQL endpoint ตอน runtime ด้วย checkLinkURL() จาก window.location.hrefvtrc-mobile ไม่มี runtime resolver Endpoint เป็นค่าคงที่ในซอร์ส ต้อง comment/uncomment แล้ว rebuild ทุกครั้งที่สลับ PROD/UAT/local

ค่าคงที่ชุดเดียวกันถูกประกาศซ้ำใน 3 ไฟล์ที่ไม่ประสานกัน (path suffix ไม่ตรงกันจริง):

ไฟล์ตัวแปรหลักค่า PROD ที่ uncomment อยู่
src/config/index.js:3-4Config.APIhttps://vtrcapi.redcross.or.th/api/graphql
src/constants/HostApi.js:21-23HOST, HOSTGRAHQLhost + /api (ไม่มี /graphql)
src/utils/hostUrl.js:4-5HOSThost อย่างเดียว (ไม่มี path)

นอกจากนี้ Config.MEETING_API hardcode ชี้ UAT เสมอ (src/config/index.js:12) — ดู 02-core-pipeline และ 04-scorecard § CORR-MOBILE-01 / LEG-MOBILE-02

Backend ที่แอปคุยด้วย (ยืนยันจากโค้ด):

vtrc-mobile
  ├── GraphQL  → Config.API          (vtrc-api)           via fetch.js SSL pin
  ├── GraphQL  → HOSTGRAHQL/graphql  (multipart upload)   via actions/withdrawSlice.js
  ├── REST     → HOST/SSOService/*   (SSO)                via actions/ssoSlice.js
  ├── REST     → HOSTRECRUITMENT/*   (recruitment-api)    via actions/recruitment.js
  ├── REST     → HOSTWORKFORCE/*     (workforce)          via actions/userSlice.js
  ├── REST     → Config.MEETING_API  (meeting, UAT host)  via meetingService.js
  └── WebView  → HOST/graphql/conicle/*                   via containers/Conicle.js + hostUrl.js

Auth model (สรุป)

ทุก GraphQL request ผ่าน utils/fetch.js แนบ:

  • Authorization: Bearer {accessToken} จาก redux auth.token (ถ้ามี)
  • apiKey: 346155c3-cea8-41f3-a9a0-305d0cc7ccf4 (production device key hardcode)

ดูรายละเอียด login / refresh / biometric / token storage ที่ 02-core-pipeline


สิ่งที่พบซึ่งกระทบทั้งแพลตฟอร์ม (candidate canonical truths)

  1. RSA private key (PEM) hardcode ใน client bundlevtrc-mobile/src/utils/login.js:17-42 และถูก copy ไป new-vtrc-mobile (ดู scorecard ของ sibling) — SEC-MOBILE-01
  2. ไม่มี checkLinkURL() pattern — environment switch = edit source + rebuild
  3. Host config drift 3 ไฟล์Config.API vs HOSTGRAHQL vs hostUrl.HOST path ไม่ตรงกันแล้วในซอร์สปัจจุบัน
  4. Token auth อยู่ sensitive storage; biometric private key อยู่ AsyncStorage key Encode — ชั้นความปลอดภัยไม่เท่ากัน (store.js vs setting.js:90-105)
  5. Meeting feature ใน production build ยิง UAT meeting hostConfig.MEETING_API ไม่มี branch prod

สารบัญ

บทหัวข้อ
01Repository map — โครงสร้าง src/, containers, gql, state, native
02Endpoint drift, auth/login, token refresh, RSA, AsyncStorage vs keychain
03แผนที่ฟีเจอร์ — cluster ตาม domain + scene keys + notification deep-link
04Scorecard + debt ID (SEC / LEG / CORR / QUAL / OBS)

สถิติ repo (master ณ เวลาเขียน)

เมตริกค่าวิธีนับ
Tracked files1055git ls-files
ไฟล์ใต้ src/~610find src -type f
Containers (top + meeting)120 + 21ls src/containers
Components218find src/components -type f
Features slices14ls src/features
Actions helpers6ls src/actions
GQL query / mutation files14 / 7ls src/gql/query / mutation
App.js1071 บรรทัดwc -l
authSlice.js1084 บรรทัดwc -l
Android version1.9.12 (139)android/app/build.gradle:154-155

เส้นอ่านแนะนำ

  1. อ่านบทนี้ให้จบ stack + entrypoint + candidate truths
  2. 01-repository-map — หาไฟล์ก่อนแตะโค้ด
  3. 02-core-pipelineบังคับ ถ้าแตะ login / host / RSA / token
  4. 03-features-map — หา cluster ก่อนแก้ UI
  5. 04-scorecard — ก่อนเสนอ refactor หรือ security fix

ดูภาพรวมกลุ่ม Mobile ที่ Volume 8 index.