Skip to content

12.10 · Publication + Conicle + Cron

บทนี้เจาะลึก business logic ของการเผยแพร่เนื้อหา (Post/Document/Course), Conicle LMS integration, และ cron jobs ที่ทำงานเบื้องหลัง


ภาพรวม

ด้านค่า
Publication controllerlib/controllers/{post,document,course,career}/*.js
Conicle controllerlib/controllers/conicle/conicle.js (~310 บรรทัด)
Croncrons.js (72 บรรทัด)
Cron jobs active3
Cron jobs disabled1 (auto-cancel leave)
Publication status3 (PUBLIC, INTERNAL, ALLINTERNAL)

Part 1 · Publication (Post/Document/Course)


1. Publication status

135:184:vtrc-api/api/src/lib/controllers/post/post.js
// concept — conditionFilterPublic
if (context.userId == null || prasma.length > 0) {
  status = { status: "PUBLIC" }       // anonymous → เห็นเฉพาะ PUBLIC
} else {
  typePost = ['ABOUTUS', 'ORIENTATION', 'PUBLIC_RELATIONS']
}

Status values

Statusความหมายใครเห็น
PUBLICเผยแพร่สาธารณะทุกคน (รวมผู้ที่ยังไม่ login)
INTERNALภายในหน่วยงานเฉพาะสมาชิก division
ALLINTERNALภายในทั้งหมดทุกพนักงานที่ login แล้ว

2. Post workflow

Operations

Operationที่อยู่ความหมาย
createPost(args)post.js:12สร้าง + nested postDivision
updatePost(postId, args)post.js:20แก้ไข
highLightPost(postId, args)post.js:28ตั้ง highlight (จำกัด ≤ 3/division)
destroyPost(postId)post.js:48ลบ

Highlight limit

js
// post.js:28 (concept)
if (post.length < 3) {
  // ตั้ง highlight ได้
} else {
  throw responError('OUT_OF_LIMIT')
}

จำกัด highlight สูงสุด 3 โพสต์ต่อ division


3. ไม่มี explicit review/publish state machine

ไม่เหมือน domain อื่น — post ไม่มี "draft → review → publish" workflow

status field (PUBLIC, INTERNAL, ALLINTERNAL) ถูกตั้งโดยตรงจาก backoffice — admin เป็นคนเลือก


4. Attachment handling

ไฟล์แนบเก็บใน Models.File (polymorphic):

Fieldใช้กับ
wdSlipIdWelfare slip
relateIdทั่วไป
wdHospitalIdWelfare hospital
postIdPost banner

สำหรับ hospital: handleHospitalDocument + handleHospitalDocumentv2 (hospital.js:3076, 3025)


5. Read tracking — postRead.js

js
// concept — track userId + postId
await PostRead.create({
  userId,
  postId,
  readAt: new Date()
})

ใช้สำหรับแสดง "อ่านแล้ว" หรือนับยอด view


6. Permission scope

js
// concept
clouseFrontEnd(args, context, 'postId', includeRelation)   // ฝั่ง user
clouseBackOffice(args, context, 'postId', includeRelation) // ฝั่ง admin

Plasma branch

ถ้า user division มี KEY_PLASMA config — เห็นโพสต์ plasma ด้วย


Part 2 · Conicle (LMS)


7. Conicle integration — SSO + proxy

ที่อยู่: lib/controllers/conicle/conicle.js

Auth flow — authConicle

25:92:vtrc-api/api/src/lib/controllers/conicle/conicle.js
// concept
const authConicle = async () => {
  // 1. ตรวจ ConicleSessions ใน DB — ถ้า sessionExpireDate > now ใช้ session เดิม
  const existing = await ConicleSessions.findOne({
    where: { sessionExpireDate: { [Op.gt]: new Date() } }
  })
  if (existing) return existing
  
  // 2. ถ้าไม่มี/หมดอายุ → POST ${END_POINT_CONICLE}/api/integrate/account/login/
  const response = await axios.post(loginUrl, {
    username: CONINCLE_USERNAME,
    password: CONINCLE_PASSWORD
  })
  
  // 3. parse set-cookie → extract sessionid, csrftoken, __cfduid
  const cookies = parseCookies(response.headers['set-cookie'])
  
  // 4. createConicle — save DB
  await createConicle({
    sessionid: cookies.sessionid,
    csrftoken: cookies.csrftoken,
    __cfduid: cookies.__cfduid,
    sessionExpireDate: moment().add(1, 'day').toDate()
  })
  
  // 5. cleanup expired sessions
  await destroyConicleSession({ sessionExpireDate: { [Op.lt]: new Date() } })
}

User SSO — authUserConicle

94:vtrc-api/api/src/lib/controllers/conicle/conicle.js
// concept
const authUserConicle = async (cookie, context) => {
  // POST ${END_POINT_CONICLE}/api/integrate/account/sso/generate/
  // username = profileKey
  // header: X-CSRFTOKEN + Cookie
  return response.data.token
}

8. Page redirect

122:vtrc-api/api/src/lib/controllers/conicle/conicle.js
// concept — generateUrlConicle
const generateUrlConicle = async (pageRequest, context) => {
  const cookie = await authConicle()
  const token = await authUserConicle(cookie, context)
  // page: library, public-request, home
  return `${END_POINT_CONICLE}/account/sso/validate/?redirect_path=${page}&token=${token}`
}

CONICLE_PAGE config

IndexPage
0library
1public-request
2home

9. List course

132:vtrc-api/api/src/lib/controllers/conicle/conicle.js
// concept
const conicleListCourse = async (context) => {
  const cookie = await authConicle()
  // GET ${END_POINT_CONICLE}/api/integrate/highlight/v2/
  return response.data
}

10. QR check-in

185:vtrc-api/api/src/lib/controllers/conicle/conicle.js
// concept
const readContentQrCode = async (code, context) => {
  // GET ${END_POINT_CONICLE}/api/integrate/check-in/scan/?code=${code}&username=${profileKey}
}

11. Conicle routes

Routeบรรทัดความหมาย
GET /api/conicle/downloadFile/:idroutes.js:902stream file from disk
GET /api/conicle/getFileFromUrlroutes.js:920proxy fetch external URL → save → return local URL

12. Long-term training export / SFTP

ไม่พบ logic SFTP หรือ long-term training export ใน vtrc-api

ค้นหา sftp|ssh|longterm|long_term|training ใน routes.js — ไม่ match

อาจอยู่ใน cu-central-api หรือไม่ได้ implement ใน vtrc-api


Part 3 · Cron jobs


13. Active cron jobs

14:27:vtrc-api/api/src/crons.js
if (+APP_NO === 1) {
    jobs.push(schedule.scheduleJob('* 1 * * * *', async () => {
        await updateSuccessFundChangeRateByJob()
    }))
}
// Every day at 03:30.
jobs.push(schedule.scheduleJob('30 3 * * *', async () => {
    updateDelegatesExpire();
}))
// Every day at 00:30.
jobs.push(schedule.scheduleJob('30 0 * * *', async () => {
    statLog()
}))
ScheduleJobที่อยู่สิ่งที่ทำ
* 1 * * * * (ทุกนาที ที่วินาที 1)updateSuccessFundChangeRateByJobfund.js:400flip PENDING → SUCCESS provident fund rate change (เฉพาะ APP_NO=1)
30 3 * * * (03:30 ทุกวัน)updateDelegatesExpire(import)ปิด delegate ที่เลย endDate
30 0 * * * (00:30 ทุกวัน)statLogstatLog/statLog.js:8sync activation log จาก log-event-api → reportActivateAccount

14. Disabled cron — auto-cancel leave

29:70:vtrc-api/api/src/crons.js
// concept — ถูก comment ทิ้ง (RecurrenceRule: date=16, hour=0, minute=1)
// เทียบ cron: '1 0 16 * *' = ทุกวันที่ 16 เวลา 00:01
// schedule.scheduleJob(rule, async () => {
//   // ยกเลิกเอกสารลาของสังกัด 0734 อัตโนมัติ
//   await hrmi.updateLeaveDocument(..., {
//     approveStatus: 'C',
//     noteApprove: 'ยกเลิกโดยระบบ'
//   })
// })

ถูกปิดไว้ — แต่ยังอยู่ในโค้ด ควรยืนยันกับ HR ก่อนลบ


15. statLog — cross-service

js
// statLog/statLog.js:8 (concept)
const statLog = async () => {
  // 1. ดึง activation events จาก log-event-api
  const activationEvents = await axios.get(
    `${END_POINT_LOG_EVENT}/log-event-api/api/v1/logEventActive`
  )
  
  // 2. ดึง activated events
  const activatedEvents = await axios.get(
    `${END_POINT_LOG_EVENT}/log-event-api/api/v1/logEventActivated`
  )
  
  // 3. ดึง employee org info จาก cu-central-api
  const employees = await statLogCD()
  
  // 4. INSERT ลง reportActivateAccount (db2 = vtrc-centralize)
  await ReportActivateAccount.bulkInsert(...)
}

16. ข้อระวัง cron

1. ไม่มี error handling

schedule.scheduleJob ไม่ catch error — ถ้า throw จะเป็น unhandledRejection

2. APP_NO gate

cron fund rate ทำงานเฉพาะ APP_NO=1 — ถ้า deploy หลาย instance โดยไม่ตั้งค่า อาจทำซ้ำหรือไม่ทำ

3. ไม่มี lock

ถ้า cron รันนานเกิน schedule ตัวถัดไปอาจเริ่มซ้อนทับ

4. Dead code

auto-cancel leave ถูกปิดไว้ — ควรลบหรือใส่ comment อธิบายว่าทำไมปิด


สรุปทั้ง 3 ส่วน

ด้านทำใน vtrc-apiส่งต่อ cu-central-api / ภายนอก
Publication statusใช่
Read trackingใช่
Permission scope (plasma)ใช่
Conicle auth + SSOใช่Conicle LMS API
Conicle cookie managementใช่
Cron fund rateใช่
Cron delegate expireใช่
Cron stat logใช่log-event-api + cu-central-api
Long-term training exportไม่พบ(ไม่พบใน vtrc-api)

ขั้นตอนถัดไป

ไป บท 11.11 Scorecard + known bugs