Files
alla-tms/docs/reviews/phase-2-functional-review.md
2026-07-16 09:53:14 +07:00

27 KiB

Phase 2 - Functional Review

Executive Summary

จากการตรวจ functional flow ของระบบ TMS ในรอบนี้ พบว่าฟีเจอร์หลักหลายส่วนสามารถใช้งานได้จริงในระดับ CRUD และ workflow พื้นฐาน เช่น login/session, employee directory, training records creation/import, announcements, online lessons, notifications แบบ in-app, และ training policy activation/history

อย่างไรก็ตาม เมื่อเทียบกับขอบเขตที่ระบุใน prompt แล้ว ระบบยังมี functional gap สำคัญหลายจุด โดยเฉพาะ:

  • workflow รีวิว training-records ยังไม่รองรับ Reject แบบแยกจาก Return for Edit
  • reports ที่รองรับจริงยังน้อยกว่าที่ต้องการ และไม่มี CSV export
  • training-policy ยังไม่รองรับ delete/soft delete/effective date/versioning
  • announcements และ online-lessons ยังไม่มี scheduled publish / versioning และบาง requirement ยังไม่ถูก model ไว้
  • notifications ยังเป็น in-app only และ filter capability ไม่ครบกับ type ที่ระบบประกาศไว้

Feature Inventory

Module Status Notes
Authentication Partial Login/session unauthorized flow มี, self-service sign-up ถูกปิด, ไม่พบ first-time access flow หรือ LDAP/AD integration
Dashboard Overview Partial มี dashboard แยก admin/employee พร้อม year/company/department filters บาง role
Employee Management Supported มี list/search/filter/sort/pagination/detail/create/edit/import/targets
Training Records Partial Create/edit draft/submit/delete/import/certificate/download มี, review flow ยังไม่ครบ reject path
Online Lessons Partial Draft/submit/edit/review/publish/archive มี, schedule publish/versioning/completion ไม่พบ
Announcements Partial Draft/submit/edit/review/publish/archive/pin/unpin/expiration มี, audience/schedule publish/versioning ไม่พบ
Policy Management Partial List/create/edit/clone/activate/deactivate/history มี, delete/soft delete/effective date/versioning ไม่พบ
Approval Workflow Partial Content approval มีหลาย transition, training-record review ยังไม่ครบ state ตาม requirement
Permission Template Management Partial template CRUD-ish/clone/assign/overrides มี, soft delete และ default template behavior ต้องตรวจต่อใน Phase 3
Reports Partial มี employee transcript/training matrix/department summary/annual summary + Excel/PDF export
Notifications Partial In-app/read-unread/link มี, email notification ไม่พบ
Audit Log Supported login/security event และ mutation modules หลักมี audit integration จำนวนมาก

Findings

[High] Training Record review workflow ยังไม่รองรับ Reject แบบแยกจาก Return for Edit

Module: Training Records, Approval Workflow

ตำแหน่งที่พบ:

  • src/app/api/training-records/[id]/review/route.ts
  • src/features/training-records/components/training-record-review-form.tsx
  • src/features/training-records/api/types.ts
  • src/features/training-records/schemas/training-record.ts

รายละเอียด:

prompt ระบุให้ตรวจ flow HRD Approve, HRD Reject, HRD Return for Edit และ status path:

Draft -> Pending Review -> Approved

Draft -> Pending Review -> Rejected

Draft -> Pending Review -> Returned for Edit -> Pending Review

แต่ implementation ปัจจุบันของ training-record review รองรับเพียงสองผลลัพธ์:

  • approved
  • needs_revision

โดยไม่มี payload/action สำหรับ rejected แยกต่างหาก

ผลกระทบ:

  • business workflow ของการรีวิวประวัติอบรมไม่ครบตาม requirement
  • สถานะ rejected มีใน type/list/filter ของ training records แต่ไม่มีช่องทาง review flow ที่ทำให้ state นี้เกิดขึ้นในเส้นทางปกติ
  • ผู้ใช้และผู้ตรวจอาจแยกไม่ออกระหว่าง “ส่งกลับให้แก้ไข” กับ “ปฏิเสธถาวร”

หลักฐานจากโค้ด:

  • src/features/training-records/api/types.ts กำหนด TrainingRecordReviewPayload.status เป็น 'approved' | 'needs_revision'
  • src/features/training-records/components/training-record-review-form.tsx มี Tabs แค่ approved และ needs_revision
  • src/app/api/training-records/[id]/review/route.ts map non-approved ทุกกรณีไป approvalStatus: 'needs_revision'

สถานการณ์ตัวอย่าง:

หาก HRD ต้อง “ปฏิเสธรายการอบรม” แบบจบ workflow โดยไม่เปิดให้แก้ไข ผู้ใช้จะทำไม่ได้ เพราะระบบรองรับแค่การอนุมัติหรือส่งกลับให้แก้ไข

คำแนะนำ:

แยก review decision ออกเป็น approved / needs_revision / rejected ให้ตรงกับ business rule และให้ type, schema, form, notification, audit log และ table filters สอดคล้องกัน

ต้องแก้ก่อน Production หรือไม่: ใช่

[High] Reports module รองรับรายงานจริงไม่ครบตาม scope และไม่มี CSV export

Module: Reports

ตำแหน่งที่พบ:

  • src/features/reports/components/reports-page-content.tsx
  • src/features/reports/api/types.ts
  • src/app/api/reports/export/route.ts
  • src/features/reports/server/report-data.ts

รายละเอียด:

prompt ระบุให้ตรวจ:

  • Employee Training Report
  • Department Report
  • Company Report
  • K/S/A Report
  • Required Hours Report
  • Missing Training Report
  • Approval Report
  • Export CSV
  • Export Excel
  • Export PDF
  • Filter
  • Sort
  • Pagination

แต่ implementation ปัจจุบันรองรับเพียง:

  • Employee Transcript
  • Training Matrix
  • Department Summary
  • Annual Training Summary
  • Export Excel
  • Export PDF

และไม่พบ:

  • Company Report
  • K/S/A report
  • Required Hours report
  • Missing Training report
  • Approval report
  • CSV export
  • sorting/pagination ของ report output ในหน้า reports

ผลกระทบ:

  • report module ยังไม่ครอบคลุม use case ที่ผู้ใช้งานสาย HRD/manager คาดหวัง
  • งาน operational/reporting ต้องพึ่งการสรุปเองจากข้อมูลดิบหรือ export ไปทำต่อภายนอก

หลักฐานจากโค้ด:

  • src/app/api/reports/export/route.ts รองรับ report แค่ employeeTranscript, trainingMatrix, departmentSummary, annualTrainingSummary
  • src/features/reports/components/reports-page-content.tsx สร้าง export links เฉพาะ xlsx และ pdf
  • ไม่พบโค้ดเกี่ยวกับ CSV export ใน src/features/reports และ src/app/api/reports

สถานการณ์ตัวอย่าง:

หาก HRD ต้องการรายงาน “พนักงานที่ยังขาดชั่วโมงบังคับ” หรือ “สรุปตามบริษัท” จะยังไม่สามารถดึงจาก report module ปัจจุบันได้โดยตรง

คำแนะนำ:

แยก report backlog ตาม report family และกำหนด output contract ที่ชัดเจน รวมถึงเพิ่ม CSV export และพิจารณา UX สำหรับ sort/pagination หรือ downloadable large-result patterns

ต้องแก้ก่อน Production หรือไม่: ใช่

[High] Policy Management ยังไม่ครอบคลุม delete/soft delete/effective date/versioning ตาม requirement

Module: Policy Management

ตำแหน่งที่พบ:

  • src/app/api/training-policies/route.ts
  • src/app/api/training-policies/[id]/route.ts
  • src/app/api/training-policies/[id]/activate/route.ts
  • src/app/api/training-policies/[id]/deactivate/route.ts
  • src/app/api/training-policies/[id]/clone/route.ts
  • src/app/api/training-policies/[id]/history/route.ts
  • src/features/training-policy/api/types.ts

รายละเอียด:

training policy ปัจจุบันรองรับ:

  • list
  • create
  • edit
  • activate/deactivate
  • clone
  • audit history

แต่ไม่พบ capability ที่ prompt ระบุไว้ ได้แก่:

  • delete
  • soft delete
  • effective date
  • versioning

data contract ของ policy ยังมีเพียง year, total_hours, k_hours, s_hours, a_hours, is_active

ผลกระทบ:

  • การจัดการนโยบายย้อนหลังหรือเตรียม policy ล่วงหน้าแบบมีวันเริ่มใช้จริงทำไม่ได้
  • การแยก “ร่าง version ถัดไป” กับ “policy ที่ใช้งานอยู่” ยังไม่ชัดเจนในเชิงโดเมน

หลักฐานจากโค้ด:

  • src/app/api/training-policies/route.ts มีแค่ GET และ POST
  • src/app/api/training-policies/[id]/route.ts มีแค่ GET และ PATCH
  • src/features/training-policy/api/types.ts ไม่มี field กลุ่ม effectiveDate, deletedAt, version, publishedAt
  • ไม่พบ DELETE route ใน src/app/api/training-policies

สถานการณ์ตัวอย่าง:

หากองค์กรต้องเตรียม policy ปีหน้าไว้ล่วงหน้าแต่ยังไม่ activate ทันทีตามวันมีผลบังคับใช้ ระบบยังไม่มี model/function ตรงนี้แบบ explicit

คำแนะนำ:

กำหนด business model ของ policy lifecycle ให้ชัดว่าใช้ปีอย่างเดียวพอหรือจำเป็นต้องมี effective date/version chain/retire state แล้วค่อยแตกเป็น API และ UX ที่ตรง requirement

ต้องแก้ก่อน Production หรือไม่: ใช่

[Medium] Announcements และ Online Lessons ยังไม่มี scheduled publish / versioning และ requirement เสริมบางข้อยังไม่ถูก model

Module: Announcements, Online Lessons

ตำแหน่งที่พบ:

  • src/features/announcements/api/types.ts
  • src/features/online-lessons/api/types.ts
  • src/features/content-approval/lib/workflow.ts
  • src/app/api/announcements/route.ts
  • src/app/api/announcements/[id]/route.ts
  • src/app/api/online-lessons/route.ts
  • src/app/api/online-lessons/[id]/route.ts

รายละเอียด:

ระบบ content workflow ปัจจุบันรองรับ state/action แบบทันที:

  • draft
  • pending_review
  • approved
  • published
  • returned
  • rejected
  • archived

โดย action มีแค่ submit/approve/return/reject/publish/archive

สิ่งที่ prompt ต้องการแต่ยังไม่พบใน contract/model ปัจจุบัน:

  • scheduled publish
  • versioning
  • audience targeting สำหรับ announcements
  • lesson completion สำหรับ online lessons

announcement มี startDate/endDate ซึ่งช่วยเรื่องช่วงเวลาแสดงผลและ expiration ได้ แต่ไม่ใช่ scheduled publish แบบ explicit lifecycle

ผลกระทบ:

  • content team ยังตั้งเวลาเผยแพร่ล่วงหน้าแบบ workflow จริงไม่ได้
  • ไม่มี version chain สำหรับติดตามฉบับก่อน/หลัง
  • announcement ยังไม่แยกกลุ่มผู้รับแบบ audience-specific
  • online lesson ยังไม่ track completion state ของพนักงาน

หลักฐานจากโค้ด:

  • src/features/content-approval/lib/workflow.ts ไม่มี action สำหรับ schedule/unpublish/version
  • src/features/announcements/api/types.ts ไม่มี field audience/version/publishAt
  • src/features/online-lessons/api/types.ts ไม่มี field completion/version/publishAt

สถานการณ์ตัวอย่าง:

หาก HRD ต้องเตรียมประกาศให้เผยแพร่วันจันทร์ 09:00 โดยอนุมัติล่วงหน้าวันศุกร์ หรืออยากเก็บ revision history ของบทเรียนออนไลน์ ระบบยังไม่รองรับ workflow นี้โดยตรง

คำแนะนำ:

แยก requirement ของ content lifecycle ออกเป็น:

  • schedule model
  • publication window
  • audience scope
  • version history
  • completion tracking

แล้วทำให้ schema/API/UI ใช้ศัพท์เดียวกัน

ต้องแก้ก่อน Production หรือไม่: ควรพิจารณา

[Medium] Notifications เป็น in-app only และ filter capability ไม่ครบกับ notification types ที่ระบบประกาศไว้

Module: Notifications

ตำแหน่งที่พบ:

  • src/features/notifications/api/types.ts
  • src/app/api/notifications/route.ts
  • src/features/notifications/server/notification-data.ts
  • src/features/notifications/server/notification-service.ts

รายละเอียด:

prompt ระบุให้ตรวจทั้ง In-app Notification และ Email Notification

implementation ปัจจุบันรองรับ:

  • in-app notifications
  • read/unread
  • mark all read
  • link navigation

แต่ไม่พบ email delivery implementation เช่น SMTP/provider/send function

อีกทั้ง type layer ประกาศ notification types ไว้กว้างกว่า filter API ที่รองรับจริง เช่น:

  • CONTENT_SUBMITTED
  • CONTENT_APPROVED
  • CONTENT_RETURNED
  • CONTENT_REJECTED
  • CONTENT_PUBLISHED

มีใน src/features/notifications/api/types.ts และถูกสร้างได้จาก notification-service.ts แต่ src/app/api/notifications/route.ts เปิดให้ filter ได้เพียง subset หนึ่งเท่านั้น

ผลกระทบ:

  • ผู้ใช้ที่คาดหวังการแจ้งเตือนทางอีเมลจะยังไม่ได้รับ
  • filtering experience ของ notifications ไม่สอดคล้องกับ event types ที่ระบบเองประกาศไว้

หลักฐานจากโค้ด:

  • src/app/api/notifications/route.ts ไม่มี logic ส่งอีเมล และ enum filter รองรับ subset จำกัด
  • src/features/notifications/server/notification-service.ts มีแต่ createNotification(...) ลงตาราง notifications
  • ไม่พบ library/provider สำหรับ email sending ใน codebase ที่ตรวจ

สถานการณ์ตัวอย่าง:

ผู้จัดการที่ไม่เข้า dashboard เป็นประจำจะไม่ถูกแจ้งผ่าน email เมื่อมี content รออนุมัติหรือประกาศใหม่ แม้ระบบจะมี event notification ระดับ in-app อยู่แล้ว

คำแนะนำ:

แยก notification channel model ให้ชัดว่าอะไรคือ in-app only และอะไรต้องมี email จากนั้นทำให้ notification type/filter API ครอบคลุม types ที่ระบบสร้างจริง

ต้องแก้ก่อน Production หรือไม่: ควรพิจารณา

[Medium] Training Records ยังไม่พบ export feature ระดับโมดูล แม้ import/template/download certificate จะรองรับแล้ว

Module: Training Records

ตำแหน่งที่พบ:

  • src/app/dashboard/training-records/page.tsx
  • src/app/api/training-records/route.ts
  • src/app/api/training-records/import/route.ts
  • src/app/api/training-records/import/template/route.ts
  • src/features/training-records/components/training-record-import-page.tsx

รายละเอียด:

training records ปัจจุบันรองรับ:

  • create/edit draft
  • submit
  • delete editable record
  • import
  • import template download
  • certificate upload/download/delete

แต่ไม่พบ export flow ของ training records module โดยตรง แม้ prompt ระบุให้ตรวจ Export

ผลกระทบ:

  • ผู้ใช้ต้องพึ่ง reports module หรือดึงข้อมูลจากตารางแทน หากต้องการ export รายการประวัติอบรมโดยตรงจากหน้า feature

หลักฐานจากโค้ด:

  • ไม่พบ route กลุ่ม /api/training-records/export
  • src/app/dashboard/training-records/page.tsx มี CTA สำหรับ import/template/review/create แต่ไม่มี export action

สถานการณ์ตัวอย่าง:

HRD ต้องการ export เฉพาะรายการจากหน้า training records หลัง filter แล้ว แต่ workflow ปัจจุบันไม่รองรับตรงตัว

คำแนะนำ:

ตัดสินใจให้ชัดว่า export ถือเป็น responsibility ของ report module เท่านั้น หรือควรมี export จาก training-record listing โดยตรง

ต้องแก้ก่อน Production หรือไม่: ควรพิจารณา

[Low] Notification filter API กับ UI ไม่สอดคล้องกับ types ที่ระบบสร้างได้จริง

Module: Notifications

ตำแหน่งที่พบ:

  • src/features/notifications/api/types.ts
  • src/app/api/notifications/route.ts
  • src/features/notifications/constants/notification-options.ts
  • src/features/notifications/server/notification-service.ts

รายละเอียด:

ระบบสร้าง content workflow notifications ได้หลายประเภท แต่ GET /api/notifications filter schema รองรับไม่ครบ และหน้า notifications อิงจาก option set ที่แคบกว่า type universe จริง

ผลกระทบ:

  • ผู้ใช้ filter หา event บางชนิดไม่ได้ ทั้งที่ระบบบันทึก notification ชนิดนั้นอยู่

หลักฐานจากโค้ด:

  • notification-service.ts รองรับ CONTENT_SUBMITTED, CONTENT_APPROVED, CONTENT_RETURNED, CONTENT_REJECTED, CONTENT_PUBLISHED
  • src/app/api/notifications/route.ts enum filter ไม่รวม type เหล่านี้ทั้งหมด

สถานการณ์ตัวอย่าง:

ทีมต้องการเปิดเฉพาะ “content returned” notifications เพื่อติดตามงานแก้ไข แต่หน้า UI/API ปัจจุบันยังไม่มี filter ตรงประเภทนี้

คำแนะนำ:

ทำ notification type registry กลาง และให้ API/UI/share same enum

ต้องแก้ก่อน Production หรือไม่: ไม่ใช่

Positive Coverage Observed

  • employee-directory รองรับ search/filter/sort/pagination/detail/create/import ได้ค่อนข้างครบ
  • announcements รองรับ draft/submit/edit/review/publish/pin-unpin/expiration/employee view ได้ดีในระดับพื้นฐาน
  • online-lessons รองรับทั้ง video URL และ video upload พร้อม thumbnail/attachment และ approval/publish flow พื้นฐาน
  • training-records รองรับ draft/edit/delete/import/template/certificate handling ได้ค่อนข้างครบ
  • overview และ reports มี role-aware scoping สำหรับ employee vs admin

Commands Executed and Results

  1. rg -n "Phase 2|Functional Review|phase-2-functional-review" plans/tms-system-full-audit-prompts.md Result: ใช้ยืนยันหัวข้อและ output file ของ Phase 2
  2. Get-ChildItem -Recurse -File src/app/dashboard | Select-Object FullName Result: ใช้ inventory route/pages ของ dashboard
  3. Get-ChildItem -Recurse -File src/app/api | Select-Object FullName Result: ใช้ inventory route handlers ที่รองรับแต่ละ feature
  4. rg --files -g "*test*" -g "*spec*" src Result: ไม่พบ test coverage ที่มีนัยสำคัญสำหรับ functional verification
  5. rg -n "/dashboard/.*/new" src Result: ใช้เทียบ CTA create routes กับ implementation จริง
  6. rg -n "csv|CSV|text/csv|createCsv|export csv" src/features/reports src/app/api/reports Result: ไม่พบ CSV export ใน reports module
  7. rg -n "sendMail|nodemailer|resend|smtp|email" src/features src/app/api src/lib Result: ไม่พบ email notification implementation ที่ชัดเจน
  8. rg -n "delete|DELETE" src/app/api/training-policies src/features/training-policy Result: ไม่พบ delete route ของ training policies
  9. rg -n "effective|version|audience|schedule|publishAt|publishedAt|expires|expiration" ... Result: พบเพียง publish timestamp/expiration บางส่วน แต่ไม่พบ scheduled publish/versioning/audience model

Files Reviewed

  • plans/tms-system-full-audit-prompts.md
  • src/app/dashboard/training-records/page.tsx
  • src/app/dashboard/training-records/[trainingRecordId]/page.tsx
  • src/app/dashboard/announcements/page.tsx
  • src/app/dashboard/announcements/[id]/page.tsx
  • src/app/dashboard/online-lessons/page.tsx
  • src/app/dashboard/online-lessons/manage/[id]/page.tsx
  • src/app/dashboard/reports/page.tsx
  • src/app/dashboard/notifications/page.tsx
  • src/app/dashboard/employee-directory/page.tsx
  • src/app/dashboard/overview/@area_stats/page.tsx
  • src/features/training-records/components/training-record-form.tsx
  • src/features/training-records/components/training-record-review-form.tsx
  • src/features/training-records/components/training-record-view-page.tsx
  • src/features/training-records/components/training-record-import-page.tsx
  • src/features/announcements/components/announcement-form.tsx
  • src/features/announcements/components/announcement-view-page.tsx
  • src/features/announcements/components/announcements-page.tsx
  • src/features/online-lessons/components/online-lesson-form.tsx
  • src/features/online-lessons/components/online-lesson-detail-page.tsx
  • src/features/online-lessons/components/online-lessons-manage-page.tsx
  • src/features/training-policy/components/training-policy-page.tsx
  • src/features/reports/components/reports-page-content.tsx
  • src/features/notifications/components/notifications-page.tsx
  • src/features/notifications/server/notification-data.ts
  • src/features/notifications/server/notification-service.ts
  • src/features/content-approval/lib/workflow.ts
  • src/features/employee-directory/components/employee-directory-columns.tsx
  • src/features/employee-directory/components/employee-directory-header.tsx
  • src/app/api/training-records/route.ts
  • src/app/api/training-records/[id]/route.ts
  • src/app/api/training-records/[id]/review/route.ts
  • src/app/api/training-records/import/route.ts
  • src/app/api/training-records/import/template/route.ts
  • src/app/api/announcements/route.ts
  • src/app/api/announcements/[id]/route.ts
  • src/app/api/online-lessons/route.ts
  • src/app/api/online-lessons/[id]/route.ts
  • src/app/api/training-policies/route.ts
  • src/app/api/training-policies/[id]/route.ts
  • src/app/api/reports/export/route.ts
  • src/app/api/notifications/route.ts

Areas Not Verified

  • ไม่ได้รัน UI จริงใน browser เพื่อยืนยัน end-to-end interaction, toast, redirect, และ empty/error state runtime behavior
  • ไม่ได้ส่ง request จริงไปทุก API route พร้อมฐานข้อมูลจริง
  • ไม่ได้ทดสอบไฟล์ upload/download จริง
  • ไม่ได้ยืนยัน behavior ของ permission templates เชิงลึก เพราะ Phase 3 จะลงรายละเอียดกว่า
  • ไม่ได้ยืนยัน notification delivery ภายนอกระบบ เพราะไม่พบ implementation email channel ในรอบนี้

Phase ถัดไปควรเป็น Phase 3 - Permission & Authorization Audit โดยเน้น:

  • data scoping ของ employee vs HRD vs IT vs super admin
  • route/API consistency
  • effective permissions vs nav visibility
  • ownership rules ใน training records / announcements / online lessons