6.9 KiB
Training Record Submit Workflow Review
Executive Summary
ปัญหาหลักเกิดจาก submit flow ฝั่งฟอร์มเรียกเปลี่ยนสถานะรายการเป็น pending ก่อนอัปโหลด certificate เสร็จในบางเส้นทาง โดย backend อนุญาตให้อัปโหลดได้เฉพาะตอนสถานะ draft หรือ needs_revision เท่านั้น จึงเกิด error ระหว่าง submit
Current Workflow
ก่อนแก้ไข โฟลว์หลักใน training-record-form.tsx เป็นดังนี้
- Edit Draft Submit:
PATCH training record (submit)->POST certificates - Create Submit:
POST training record (submit)->POST certificates
ผลคือเมื่อ record ถูกเปลี่ยนเป็น pending แล้ว route upload จะปฏิเสธทันที
Expected Workflow
โฟลว์ที่ต้องการและที่แก้แล้วคือ
- Submit:
validate->save editable data as draft->upload certificates->update status to pending->redirect - Save Draft:
save draft->upload certificates->redirect
Execution Timeline
Edit + Submit
- validate form
PATCH /api/training-records/[id]ด้วยsubmissionMode=draftPOST /api/training-records/[id]/certificatesPATCH /api/training-records/[id]ด้วยsubmissionMode=submit- invalidate query จาก mutations
router.push('/dashboard/training-records')
Create + Submit
- validate form
POST /api/training-recordsด้วยsubmissionMode=draftPOST /api/training-records/[id]/certificatesPATCH /api/training-records/[id]ด้วยsubmissionMode=submit- invalidate query จาก mutations
- redirect
API Call Sequence
POST /api/training-recordsPATCH /api/training-records/[id]POST /api/training-records/[id]/certificatesDELETE /api/training-records/[id]/certificates/[certificateId]
ลำดับใหม่ยืนยันว่า upload เกิดก่อน status transition ไป pending
React Query Flow
- ใช้
createTrainingRecordMutation - ใช้
updateTrainingRecordMutation - ใช้
uploadCertificatesMutation - แต่ละ mutation invalidate query ตาม key เดิมของ feature
- ไม่มี
Promise.allหรือ upload background
Async Analysis
- flow ใช้
awaitแบบลำดับตรง - ไม่มี parallel mutation ที่เสี่ยงชนกัน
- submit จะไม่ไปขั้นเปลี่ยนสถานะถ้า upload ล้มเหลว
Race Condition Analysis
ก่อนแก้มี race เชิงลำดับธุรกิจ ไม่ใช่ race จาก concurrency จริง:
- route update เปลี่ยน status เป็น
pending - route upload ถูกเรียกทีหลัง
- backend reject เพราะ record ไม่อยู่ในสถานะ editable แล้ว
หลังแก้ upload เกิดก่อน status update จึงปิดช่องนี้
Upload Component Review
- ฟอร์มหลักใช้
FileUploaderเก็บไฟล์ไว้ในpendingFiles - upload จริงเกิดใน
onSubmit TrainingRecordCertificateManagerใช้สำหรับจัดการไฟล์ของรายการที่บันทึกแล้ว- ไม่พบ auto-upload บน mount
Root Cause
root cause คือ submit flow ใน training-record-form.tsx ส่ง record ไปสถานะ pending ก่อนเรียก route upload ในบางเส้นทาง ขณะที่ business rule ของ route upload ใน route.ts อนุญาตเฉพาะ draft หรือ needs_revision
หลักฐานจาก source:
- ฟอร์มเดิมเรียก create/update ด้วย
submissionMode=submitก่อน upload - route upload ตรวจ
canEmployeeManageEditableRecord(...) - helper ฝั่ง server อนุญาตเฉพาะสถานะ editable
Files Modified
src/features/training-records/components/training-record-form.tsxปรับลำดับ submit ให้ save-as-draft ก่อน upload แล้วค่อย final submitsrc/features/training-records/server/training-record-data.tsปรับ shared editable guard ให้เช็กสิทธิ์จาก employee mapping ได้ครบขึ้นsrc/app/api/training-records/[id]/route.tsใช้ shared editable guard แบบใหม่และอัปเดตข้อความ errorsrc/app/api/training-records/[id]/certificates/route.tsใช้ shared editable guard แบบใหม่และอัปเดตข้อความ errorsrc/app/api/training-records/[id]/certificates/[certificateId]/route.tsใช้ shared editable guard แบบใหม่และอัปเดตข้อความ errorsrc/features/training-records/components/training-record-certificate-manager.tsxปรับ helper text ให้ตรงกับสถานะ editable จริง
Risk Assessment
- Employee: ผลดีคือ submit draft/revision พร้อม upload ทำงานสอดคล้องกับ backend มากขึ้น
- HRD: pending queue จะเห็นเฉพาะรายการที่ผ่าน upload flow แล้ว
- Admin: ไม่มีการเปลี่ยน schema หรือ permission model
Regression Test Result
ตรวจเช็กเชิงโค้ดและ lint แล้ว
- editable guard ถูกใช้กับ route แก้ไข/อัปโหลด/ลบ
- submit flow ในฟอร์มถูกย้ายเป็น upload ก่อน status update
npx oxlintผ่านสำหรับไฟล์ที่แก้
ยังไม่ได้รัน E2E/manual test ครบทุก case ในเอกสาร
Remaining Issues
- ปุ่ม submit เดิมในฟอร์มยังถูกซ่อนไว้ ควรลบออกในรอบ cleanup
- success message บางจุดยังไม่แยก wording ระหว่าง draft กับ submit แบบครบทุกสถานะ
- ยังไม่ได้ทำ manual regression ครบทั้ง 10 case ตาม checklist