This commit is contained in:
2026-07-16 09:53:14 +07:00
parent 0fc112a2e8
commit 29cec708a3
1236 changed files with 212848 additions and 0 deletions

View File

@@ -0,0 +1,135 @@
# 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
1. validate form
2. `PATCH /api/training-records/[id]` ด้วย `submissionMode=draft`
3. `POST /api/training-records/[id]/certificates`
4. `PATCH /api/training-records/[id]` ด้วย `submissionMode=submit`
5. invalidate query จาก mutations
6. `router.push('/dashboard/training-records')`
### Create + Submit
1. validate form
2. `POST /api/training-records` ด้วย `submissionMode=draft`
3. `POST /api/training-records/[id]/certificates`
4. `PATCH /api/training-records/[id]` ด้วย `submissionMode=submit`
5. invalidate query จาก mutations
6. redirect
## API Call Sequence
- `POST /api/training-records`
- `PATCH /api/training-records/[id]`
- `POST /api/training-records/[id]/certificates`
- `DELETE /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](/D:/WY-2569/HRD/training-system-minimal-refactor/src/features/training-records/components/training-record-form.tsx) ส่ง record ไปสถานะ `pending` ก่อนเรียก route upload ในบางเส้นทาง ขณะที่ business rule ของ route upload ใน [route.ts](/D:/WY-2569/HRD/training-system-minimal-refactor/src/app/api/training-records/[id]/certificates/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 submit
- `src/features/training-records/server/training-record-data.ts`
ปรับ shared editable guard ให้เช็กสิทธิ์จาก employee mapping ได้ครบขึ้น
- `src/app/api/training-records/[id]/route.ts`
ใช้ shared editable guard แบบใหม่และอัปเดตข้อความ error
- `src/app/api/training-records/[id]/certificates/route.ts`
ใช้ shared editable guard แบบใหม่และอัปเดตข้อความ error
- `src/app/api/training-records/[id]/certificates/[certificateId]/route.ts`
ใช้ shared editable guard แบบใหม่และอัปเดตข้อความ error
- `src/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