vtrc-mobile — Repository map
บทนี้เป็นแผนที่ไฟล์ของ vtrc-mobile (branch: master, 1055 tracked files, ~610 ไฟล์ใต้ src/) — React Native 0.63 ESS app ของพนักงานสภากาชาดไทย
ชื่อ package คือ rn_redcross (vtrc-mobile/package.json:2) — ไม่ตรงกับชื่อโฟลเดอร์ repo
แผนที่โฟลเดอร์ระดับ repo
vtrc-mobile/ (branch: master)
├── index.js # AppRegistry + notification init
├── App.js # 1071 บรรทัด — Provider + PersistGate + Router/Scene ทั้งหมด
├── app.json # name/displayName = rn_redcross
├── package.json / yarn.lock
├── polyfills.js / performanceShim.js / shim.js
├── babel.config.js / metro.config.js / react-native.config.js
├── firebase.json
├── __tests__/App-test.js # template smoke test เดียว
├── __mocks__/
├── android/ # applicationId com.redcross.vtrc
│ └── app/
│ ├── build.gradle # versionName 1.9.12, signingConfigs.release hardcode
│ └── src/main/assets/
│ └── digicert2025.cer # SSL pinning cert
├── ios/
│ ├── Podfile # platform ios 12.0, target rn_redcross
│ └── rn_redcross.xcworkspace
├── assets/fonts/
├── scripts/
└── src/
├── actions/ # 6 ไฟล์ — async helpers (ชื่อ *Slice แต่ไม่ใช่ createSlice)
├── app/ # store + sensitive-storage adapter
├── assets/ # ~150 ไฟล์ (font/json/image)
├── components/ # 218 ไฟล์ ใน 27 โฟลเดอร์ domain
├── config/ # Config.API / MEETING_API
├── constants/ # 19 ไฟล์ รวม HostApi / Authen / PrivateKey
├── containers/ # 141 ไฟล์ (120 top-level + meeting-management/)
├── features/ # 14 createSlice จริง
├── gql/ # client + query/ + mutation/
├── services/ # meetingService.js
├── themes/ # Colors Fonts Metrics Images Svg
└── utils/ # fetch login setting hostUrl …ไม่มี App.js / index.js ใน src/ — อยู่ที่ root ตาม RN CLI convention
นับไฟล์ตามชั้น (ยืนยันจาก filesystem บน branch master)
| ชั้น | จำนวนไฟล์ | หมายเหตุ |
|---|---|---|
src/containers/*.js (ระดับบน) | 120 | 1 screen ต่อไฟล์โดยประมาณ |
src/containers/meeting-management/ | 21 | รวม index.js |
src/components/ | 218 | 27 domain folders |
src/features/ | 14 | createSlice จริง |
src/actions/ | 6 | async helpers — ชื่อไฟล์ลงท้าย Slice ทำให้สับสน |
src/gql/query/ | 14 | string template GraphQL |
src/gql/mutation/ | 7 | string template GraphQL |
src/constants/ | 19 | รวม secrets |
src/utils/ | 25 | fetch / login / setting / … |
src/assets/ | ~150 | static |
| tracked ทั้ง repo | 1055 | git ls-files |
Boot sequence — จาก metro ถึง scene แรก
1. metro bundle entry = index.js
│ `vtrc-mobile/index.js:1-23`
▼
2. polyfill Node globals (crypto, stream, buffer) ผ่าน shim.js
│ จำเป็นเพราะ login.js ใช้ crypto.createHash / publicEncrypt
▼
3. initializeNotificationHandlers()
│ `src/components/shared/NotificationEvent.js`
│ ลงทะเบียน FCM / local notification listener ก่อน UI
▼
4. AppRegistry.registerComponent('rn_redcross', () => App)
▼
5. App mount:
Provider → PersistGate.onBeforeLift → Router
│ `App.js:190-225`
▼
6. Scene initial = key "init" → Init container
`App.js:229-235`Init เป็นจุดตัดสินใจต่อ — หลัง PersistGate เรียก refreshToken ซึ่งจะ Actions.intro / Actions.decideenter / Actions.mainmenu ตามสถานะ token (src/features/authSlice.js:555-623)
containers/ — screen inventory
ทุกไฟล์ด้านล่างถูก import ใน App.js และผูกเป็น {Scene key=...} — ไม่มี code-splitting
Auth / onboarding
| Container | Scene key (App.js) |
|---|---|
Init.js | init (initial) |
Intro.js | intro |
DecideEnter.js | decideenter |
Login.js | login |
Verify.js | verify |
FillProfile.js | fillprofile |
Forgot.js | forgot |
CheckLogin.js | checklogin |
EmpRegistration.js | empregistration |
Term.js | term |
ChangePassword.js | changepassword |
VerifySSO.js | verifysso |
OTPSSO.js | otpsso |
ChangePassWordSSO.js | changepasswordsso |
SettingSecureSSO.js | settingsecuresso |
หลักฐาน scene: vtrc-mobile/App.js:229-261, 379-398, 949-967
Main shell / profile / setting
| Container | Scene key |
|---|---|
MainMenu.js | mainmenu |
AllListMenu.js | alllistmenu |
Profile.js | profile |
PersonalInfo.js | personalinfo |
EmployeePersonalInfo.js | employeepersonalinfo |
EditAddress.js | editaddress |
EditPhone.js | editphone |
Account.js | account |
Setting.js | setting |
SettingNotification.js | settingnotification |
UpdateVersion.js | updateVersion |
ScanUpdate.js | scanupdate |
Subscribe.js | subscribe |
Timeline.js | timeline |
Time.js | time |
News / notification / org / contact / documents
| Container | Scene key |
|---|---|
News.js / NewsList.js / NewsListGuest.js / NewsSearch.js | news / newslist / newslistguest / newsearch |
Notification.js / NotificationList.js / NotificationGroup.js | notification / notificationlist / notificationgroup |
OrgInfo.js / OrgInfoList.js | orginfo / orginfolist |
Principle*.js (5) + QualityDocument.js / ListDocuments.js / SearchResult.js / Orientation.js | principle* / qualitydocument / listdocuments / searchresult / orientation |
Contact.js / ContactHR.js / ContactHRDetail.js / ContactOrg.js | contact / contacthr / contacthrdetail / contactorg |
Leave
| Container | Scene key |
|---|---|
Leave.js / LeaveDetail.js / ListAllLeave.js | leave / leavedetail / listallleave (ประกาศซ้ำ 2 ครั้งใน App.js:609-615) |
LeaveApprove.js / LeaveListApprove.js / LeaveApproveByNotification.js | leaveapprove / leavelistapprove / leaveapprovebynotification |
LeaveCancleListApprove.js / LeaveCancleDocApprove.js | leavecanclelistapprove / leavecancledocapprove |
ManualLeave.js / ReportLeave.js | manualleave / reportleave |
StudyLeave.js / StudyLeaveDetail.js / ListStudyLeave.js | studyleave / studyleavedetail / liststudyleave |
หมายเหตุ: คำว่า Cancle / listallleave duplicate เป็น debt naming — ดู 04-scorecard § QUAL-MOBILE-01
Welfare / medical / other benefits
| Container | Scene key |
|---|---|
Withdraw.js / WithdrawListMenu.js | witchdraw / withdrawlistmenu |
MerdicalExpenses.js / CheckStatusMerdical.js / ListAllMerdicalExpenses.js | medicalexpenses / checkstatusmerdical / listallmerdicalexpenses |
MerdicalExpensesApprove.js / MerdicalExpensesListApprove.js / MedicalExpensesView.js / ReportMerdicalExpenses.js | merdicalexpensesapprove / merdicalexpenseslistapprove / medicalexpensesview / reportmerdicalexpenses |
ChildTuition.js / ListChildTuition.js / StatusChildTuition.js | childtuition / listchildtuition / statuschildtuition |
Delegate.js / ListDelegate.js | delegete (typo ใน scene key, ประกาศซ้ำ) / listdelegete |
OtherWelfare.js / Disaster.js / TuitionReimbursement.js | otherwelfare / disaster / tuitionreimbursement |
ListBenefitForStaff.js / ListBenefitForApprover.js / Benefit.js | listbenefitforstaff / listbenefitforapprover (Benefit ถูก import — ตรวจ scene ใน App.js ตามไฟล์จริง) |
ListPersonalDevelopment.js | listpersonaldevelopment |
NewsListWithdraw.js | newslistwithdraw |
Payslip / provident / tax
| Container | Scene key |
|---|---|
PaySlip.js / PaySlipPreview.js | payslip / payslippreview |
ProvidentFund.js / PercentProvidentFund.js / EditPercentProvidentFund.js | providentfund / percentprovidentfund / editpercentprovidentfund |
ReceiverProvidentFund.js / ProvidentFundListMenu.js / NewsListProvidentFund.js | receiverprovidentfund / providentfundlistmenu / newslistprovidentfund |
TaxReductionView.js / TaxReductionEdit.js / TaxReductionGuide.js | taxview / taxedit / taxguide |
Meeting management (containers/meeting-management/)
| Container | Scene key |
|---|---|
MeetingManagement.js | meetingmanagement |
MyCalendar.js | mycalendar |
MeetingDetail.js | meetingdetail |
MeetingInviteList.js / MeetingOrganizer.js / MeetingPending.js | meetinginvitelist / meetingorganizer / meetingpending |
PreCreateMeeting.js / CreateMeeting.js / CreateMeetingDocument.js | precreatemeeting / createmeeting / createmeetingdocument |
InviteInternal.js / InviteExternal.js | inviteinternal / inviteexternal |
ApproverList.js / ApproverConfirm.js | approverlist / approverconfirm |
ApprovalList.js / ApprovalDetail.js | approvallist / approvaldetail |
Attendees.js / AttendeesList.js | attendees / attendeeslist |
ApprovalRequestList.js / ApprovalRequestDetail.js | approvalrequestlist / approvalrequestdetail |
DelegateNote.js | (ตรวจ import ใน App.js — อยู่ในโฟลเดอร์เดียวกัน) |
Scene block: vtrc-mobile/App.js:730-838
PMS
| Container | Scene key |
|---|---|
ManualPMS.js | manualpms |
ListEvaluators.js / MenuEvaluator.js | listevaluators / menuevaluators |
CheckDataPersonal.js | checkdatapersonal |
EvaluationResult.js / ListEvaluationResult.js / ViewPDFEvaluation.js | evaluationresult / listevaluationresult / viewpdfevaluation |
Recruitment
| Container | Scene key |
|---|---|
RecruitmentListMenu.js | recruitmentlistmenu |
RecruitmentAnnounce.js / FormAnnounce.js | recruitmentannounce / formannounce |
RecruitmentSearchResult.js / RecruitmentDetail.js | recruitmentsearchresult / recruitmentdetail |
ApplyWork.js / RecruitmentHistory.js / WorkWithUs.js | applywork / recruitmenthistory / workwithus |
Course / Conicle
| Container | Scene key |
|---|---|
GuestCourseList.js / GuestCourse.js / GuestCourseId.js | guestcourselist / guestcourse / guestcourseid |
CourseConicle.js / Conicle.js / ContentConicle.js | courseconicle / conicle / contentconicle |
CheckInConicle.js / NotificationConicle.js | checkinconicle / notificationconicle |
components/ — 27 domain folders
src/components/
├── authen/ # ฟอร์ม login / verify / captcha UI
├── button/
├── childtuition/
├── course/ / courseconicle/
├── delegate/
├── form/ # UploadImage UploadFile NewUploadFile FileUpload
├── layout/ # Layout + LinearGradientBackground
├── mainmenu/
├── meeting-management/
├── news/ / notification/
├── org-info/
├── payslip/ / provident/
├── personal-development/
├── picker/
├── profile/
├── recruitment/
├── report/
├── shared/ # NotificationEvent Spiner …
├── sso/
├── tax/ / tax-reduction/
├── time/ / timeline/
└── witchdraw/ # typo folder name (withdraw)จำนวนไฟล์รวม 218 — ไม่มี lazy barrel ที่บังคับ; container import ตรงเข้า component ที่ต้องการ
src/components/shared/NotificationEvent.js (353 บรรทัด) เป็นจุดรวม deep-link จาก push — ดู 03-features-map
features/ vs actions/ — สอง pattern ซ้อนกัน
features/ — createSlice จริง (14 ไฟล์)
| Slice | หน้าที่โดยย่อ |
|---|---|
authSlice.js (1084 บรรทัด) | login / logout / verify / refresh / biometric / captcha / FCM |
userSlice.js | profile + tax + address + phone + fund details |
withdrawSlice.js | leave + medical welfare queries/mutations state |
slipSlice.js | payslip / salary cert (blacklist จาก persist) |
newsSlice.js / notificationSlice.js | ข่าว + แจ้งเตือน |
documentSlice.js / aboutusSlice.js / contactusSlice.js | เอกสาร / องค์กร / ติดต่อ |
courseSlice.js / careerSlice.js / consentSlice.js / settingSlice.js / timeSlice.js | LMS / career / consent / app setting / time |
ลงทะเบียนใน combineReducers ที่ src/app/store.js:67-82
actions/ — plain async (ชื่อลงท้าย Slice ทำให้เข้าใจผิด)
| ไฟล์ | ใช้จริง |
|---|---|
ssoSlice.js | ssoCheckEmpLogin → ${HOST}/SSOService/checkEmpLogin (src/actions/ssoSlice.js:18-19) |
recruitment.js | REST ไป HOSTRECRUITMENT หลาย endpoint (src/actions/recruitment.js:7-273) |
withdrawSlice.js | multipart upload ผ่าน ${HOSTGRAHQL}/graphql (src/actions/withdrawSlice.js:271,339) |
userSlice.js | workforce REST |
slipSlice.js / estimateProfileSlice.js | helpers เสริม |
ดู 04-scorecard § QUAL-MOBILE-05
gql/ — GraphQL operations
src/gql/
├── client.js # ApolloClient → Config.API, timeout 10s, fetchPolicy no-cache
├── index.js # re-export query + mutation
├── query/ # 14 ไฟล์
└── mutation/ # 7 ไฟล์client.js — มีแต่ใช้น้อย
const timeoutLink = new ApolloLinkTimeout(10000);
const httpLink = createHttpLink({uri: Config.API});
const client = new ApolloClient({
link: timeoutHttpLink,
cache: new InMemoryCache(),
defaultOptions, // watchQuery/query = no-cache
});หลักฐาน: vtrc-mobile/src/gql/client.js:1-27
ไม่มี authLink / errorLink บน Apollo client — เพราะ path หลักไม่เดินผ่าน Apollo แต่เดินผ่าน utils/fetch.js ที่แปะ header เองและจัดการ TOKEN_EXPIRED เอง
query/ — ไฟล์และขนาดโดยประมาณ
| ไฟล์ | บรรทัด (wc) | ตัวอย่าง export |
|---|---|---|
withdraw.js | 1230 | leave + medical + child tuition + study leave + PMS master |
user.js | 1023 | profile / tax / provident / address dropdowns |
document.js | 311 | principle / KCMH / quality docs |
slip.js | 157 | slip + salary cert |
auth.js | 156 | VERIFY / REFRESH_TOKEN / captcha / OTP |
course.js | 123 | course list + Conicle URL helpers |
news.js | 64 | NEWS_QUERY |
notification.js | 53 | list / by id / count |
contactus.js | 51 | contact list |
about.js | 35 | org groups |
consent.js | 25 | consent / policy |
setting.js | 22 | app setting / check update |
career.js | 17 | career list |
time.js | 13 | TIME_ATTENDANCE_BY_DATE_QUERY |
mutation/
| ไฟล์ | ตัวอย่าง export |
|---|---|
auth.js | LOGIN_MUTATION, LOGIN_BYPASS_MUTATION, LOGOUT_MUTATION, CREATE_AUTHEN_SESSION_MUTATION, UPDATE_DEVICE_TOKEN_MUTATION, LOG_ERROR (src/gql/mutation/auth.js:21-147) |
withdraw.js | create/update leave, medical destroy, delegate, study leave |
user.js | tax draft, address, phone, fund rate/benefit |
notification.js / news.js / course.js / consent.js | read markers / check-in / consent |
Operations เป็น string template functions ที่รับ buildQuery(...) จาก utils/fetch.js — ไม่ใช่ gql tagged template ของ Apollo
config/ และ constants/ — จุด config ที่ต้องระวัง
src/config/index.js
export const Config = {
// PROD
API: 'https://vtrcapi.redcross.or.th/api/graphql',
// UAT / Local — comment อยู่
MEETING_API: 'https://uat-vtrcapi.redcross.or.th/meeting',
isDevMode: process.env.NODE_ENV !== 'production',
};หลักฐาน: vtrc-mobile/src/config/index.js:1-15
ไฟล์อื่นในโฟลเดอร์: locale.js, global-props.js, form.js — UI/form defaults ไม่ใช่ host
src/constants/HostApi.js — host ชุดที่ถูก import ~25 จุด
| Export | ค่า PROD ปัจจุบัน |
|---|---|
HOST | https://vtrcapi.redcross.or.th |
HOSTGRAHQL | https://vtrcapi.redcross.or.th/api |
HOSTWORKFORCE | …/workforce-api/api/restful |
HOSTRECRUITMENT | …/recruitment-api/api/v1 |
PATH_WORKFORCE / PATH_RECRUITMENT | base path สำหรับ asset/URL |
หลักฐาน: vtrc-mobile/src/constants/HostApi.js:21-38
Drift: fetchRestFull.js:3 import HOSTAPIDEV จาก HostApi แต่ HostApi.js ไม่ได้ export HOSTAPIDEV — ดู 04-scorecard § CORR-MOBILE-02
src/utils/hostUrl.js — duplicate ที่ 3
export const UAT_HOST = 'https://uat-vtrcapi.redcross.or.th'
export const HOST = 'https://vtrcapi.redcross.or.th'ถูก import แค่ที่ src/containers/Conicle.js:21 — ดู LEG-MOBILE-02
Secrets ใน constants/
| ไฟล์ | เนื้อหา |
|---|---|
constants/Authen.js:1-5 | API_KEY production device key |
constants/PrivateKey.js:1 | RECRUITMENT_KEY |
utils/login.js:17-42 | RSA private PEM (ใช้คู่กับ public สำหรับ makeCsID) |
utils/fetch.js:43 | apiKey ซ้ำอีกรอบ (inline) |
ไฟล์ constants อื่น: User.js (USER_QUERY_TYPE), FlowVerify.js, Menu.js, Withdraw.js, Slip.js, Tax.js, Conicle.js, Career.js, News.js, Notification.js, Document.js, Contactus.js, Course.js, Gender.js, ProvidentFund.js, Recruitment.js
app/ — Redux store + persist
src/app/
├── store.js # configureStore + persistReducer
└── redux-persist-sensitive-storage.js # adapter → react-native-sensitive-infoPersist config:
const storage = createSensitiveStorage({
keychainService: 'vtrcKeychain',
sharedPreferencesName: 'vtrcSharedPrefs',
});
const persistConfig = {
key: 'root',
storage,
timeout: 0,
blacklist: ['slip'],
};หลักฐาน: vtrc-mobile/src/app/store.js:55-65
PURGE action รีเซ็ตทุก slice กลับ initialState ด้วยมือ (store.js:84-102) — ถูกเรียกตอน firstRun, TOKEN_INVALID, logout
Middleware: default RTK + redux-logger เฉพาะ non-production (store.js:106-113)
utils/ — helper สำคัญ
| ไฟล์ | หน้าที่ | บรรทัดโดยประมาณ |
|---|---|---|
fetch.js | GraphQL ผ่าน SSL pinning + token refresh inline | ~249 |
fetchRestFull.js | axios GET/POST + refresh บน 401 | ~255 |
login.js | RSA_KEY + makeCsID() เท่านั้น | 76 |
setting.js | AsyncStorage flags (firsttime, FCMToken, ID, Encode, …) | ~117 |
axios.js | meetingAPI baseURL = Config.MEETING_API/secure | 23 |
course.js / meeting.js / withdraw.js / profile.js | domain helpers | — |
hostUrl.js | HOST duplicate สำหรับ Conicle | 6 |
downloadPDF.js / permissionAndroid.js / updateVersion.js | native-ish helpers | — |
services/
src/services/meetingService.js (338 บรรทัด) — ทุกฟังก์ชันยิง meetingAPI หรือ axios ตรงไป Config.MEETING_API:
getListMeetingInMonth,getMeetingdetail,addNewMeeting,updateMeeting, …redirectByPass(accessToken)→GET ${Config.MEETING_API}/redirectbypass(meetingService.js:327-338) ถูกเรียกหลัง login/refresh สำเร็จ (authSlice.js:409,591)
android/ / ios/ — จุดที่ต้องระวังก่อน release
Android signing (Critical)
release {
storeFile file('/Users/bosspj/Desktop/Project/react-native/vtrc-mobile/android/I3Keystore')
storePassword '…'
keyAlias 'VTRC'
keyPassword '…'
}หลักฐาน: vtrc-mobile/android/app/build.gradle:174-179 — SEC-MOBILE-02
SSL pin asset
android/app/src/main/assets/digicert2025.cer ตรงกับชื่อใน fetch.js:36 (certs: ['digicert2025'])
เมื่อ Config.isDevMode === true จะตั้ง disableAllSecurity: true (fetch.js:33) — ปิด pinning ทั้งก้อนใน dev
iOS
- Target / workspace ชื่อ
rn_redcross(ios/Podfile:6) - Permissions pods: Camera, Notifications (
Podfile:11-12) pre_installลบ UIWebView files จาก AFNetworking (Podfile:16-28)
สิ่งที่ไม่มีใน repo นี้
| สิ่งที่คาดว่าจะมีในแอปใหม่ | สถานะใน vtrc-mobile |
|---|---|
@react-navigation | ไม่มี — ใช้ router-flux |
runtime env switch / .env สำหรับ API host | ไม่มี — comment ในซอร์ส |
| Sentry / Crashlytics module | ไม่มีใน package.json dependencies (มีแค่ @react-native-firebase/app + messaging) |
| automated test เกิน template | มีแค่ __tests__/App-test.js |
| TypeScript | JS ทั้งโปรเจกต์ (มี babel TS plugins ใน devDependencies แต่ซอร์สหลักเป็น .js) |