# Setrip — Admin Verification Roadmap Enhancement KYC organizer verification: reopen REJECTED, request re-upload, audit override. > **Skenario nyata:** organizer terverifikasi dengan KTP buram → admin REJECT. Organizer foto ulang dan kirim via email. Admin sekarang harus edit DB manual karena `OrganizerVerification.status = REJECTED` tidak bisa kembali ke `PENDING` lewat UI. --- ## Baseline - ✅ Approve / Reject ada di [app/admin/verifications/page.tsx](app/admin/verifications/page.tsx). - ✅ `OrganizerVerification` model lengkap dengan `reviewedBy`, `reviewedAt`, `rejectionReason`. - ✅ NIK encrypted (decrypt via `organizerService.decryptNik` saat di-render). - ❌ Tidak ada cara reopen REJECTED → kembali ke PENDING. - ❌ Tidak ada flow "request re-upload" (admin minta organizer upload ulang field tertentu tanpa harus reject penuh). - ❌ Tidak ada history per verification — kalau organizer ajukan ulang setelah reject, history sebelumnya hilang (di-overwrite). --- ## Phase 1 — Reopen Rejected Verification ⏳ Tombol di REJECTED detail untuk reset ke PENDING supaya admin/organizer bisa coba lagi tanpa harus drop & recreate. **Keputusan asumsi:** - Tidak hapus `rejectionReason` saat reopen — simpan untuk history (rename field jadi `lastRejectionReason`). Sebenarnya rejectionReason cuma string, kalau di-reopen lalu di-reject lagi otomatis di-overwrite. Untuk MVP cukup itu. - Service method baru `reopenVerification(verifId, adminId, note)` — set `status = PENDING`, clear `reviewedBy/reviewedAt`, log via [ADMIN_AUDIT_ROADMAP.md](ADMIN_AUDIT_ROADMAP.md) Phase 4 `auditLog.record`. - UI: tombol "Buka kembali" di REJECTED card dengan modal note wajib. - Tidak otomatis kirim notif ke organizer di MVP — admin coordinate via email/WA. | # | Item | Status | File | |---|---|---|---| | 1.1 | `organizerService.reopenVerification(verifId, adminId, note)` — set PENDING + clear review fields | ⏳ | [server/services/organizer.service.ts](server/services/organizer.service.ts) | | 1.2 | Server action `reopenVerificationAction(verifId, note)` (guard isAdmin) | ⏳ | [features/organizer/actions.ts](features/organizer/actions.ts) | | 1.3 | UI: tombol "Buka kembali" di tab REJECTED dengan modal note | ⏳ | [app/admin/verifications/page.tsx](app/admin/verifications/page.tsx) atau [features/organizer/components/review-card.tsx](features/organizer/components/review-card.tsx) | | 1.4 | Tampilkan `lastRejectionReason` di tab PENDING juga (sebagai konteks "ini submission ke-N") | ⏳ | [features/organizer/components/review-card.tsx](features/organizer/components/review-card.tsx) | **Tindakan manual:** 1. Brief admin: jangan reopen tanpa konfirmasi organizer sudah siap upload ulang. Note wajib menjelaskan alasan reopen. --- ## Phase 2 — Re-upload Request Flow ⏳ Daripada reject penuh, admin bisa request specific field di-update (KTP buram, foto liveness terlalu gelap). **Keputusan asumsi:** - Tambah `OrganizerVerification.reuploadRequested Boolean @default(false)` + `reuploadFields String[]` + `reuploadNote String?`. - Saat di-request, set `status = PENDING` (atau status baru `NEEDS_REUPLOAD`). Pakai `PENDING` saja supaya tidak nambah enum (organizer-facing copy bedakan via `reuploadRequested` flag). - Organizer page `/verify` baca flag → tampilkan banner kuning + highlight field yang di-request. - Setelah organizer submit ulang, flag auto-clear → status tetap PENDING menunggu admin review. | # | Item | Status | File | |---|---|---|---| | 2.1 | Migration: tambah `reuploadRequested`, `reuploadFields`, `reuploadNote` di `OrganizerVerification` | ⏳ | `prisma/migrations/` | | 2.2 | `organizerService.requestReupload(verifId, adminId, fields[], note)` | ⏳ | [server/services/organizer.service.ts](server/services/organizer.service.ts) | | 2.3 | Server action + UI tombol "Request re-upload" di admin detail (checkbox per field + textarea note) | ⏳ | [features/organizer/actions.ts](features/organizer/actions.ts) + admin page | | 2.4 | Banner kuning di `/verify` saat `reuploadRequested = true` + highlight field-nya | ⏳ | [app/(public)/verify/page.tsx](app/(public)/verify/page.tsx) + [features/organizer/components/verify-form.tsx](features/organizer/components/verify-form.tsx) | | 2.5 | Auto-clear `reuploadRequested` saat organizer submit ulang | ⏳ | [features/organizer/actions.ts](features/organizer/actions.ts) (di `submitVerificationAction`) | **Tindakan manual:** tidak ada. --- ## Phase 3 — Verification History (opsional) ⏳ Kalau audit butuh trace "berapa kali organizer ini coba verify", tambah tabel history. Skip untuk MVP. | # | Item | Status | File | |---|---|---|---| | 3.1 | Model `OrganizerVerificationHistory` (snapshot per submission) | ⏳ | [prisma/schema.prisma](prisma/schema.prisma) | | 3.2 | Trigger create snapshot saat submit ulang | ⏳ | [server/services/organizer.service.ts](server/services/organizer.service.ts) | | 3.3 | Tab "History" di admin verification detail | ⏳ | admin page | **Tindakan manual:** tidak ada (skip phase). --- ## Phase 4 — Manual Override (super-low priority) ⏳ Admin verifikasi organizer tanpa upload (referral dari partner trusted). Skip kecuali ada use case nyata. | # | Item | Status | File | |---|---|---|---| | 4.1 | `organizerService.adminCreateVerification(userId, adminId, note)` — buat row APPROVED langsung dengan flag `isManualOverride` | ⏳ | [server/services/organizer.service.ts](server/services/organizer.service.ts) | | 4.2 | Migration: tambah `isManualOverride Boolean @default(false)` | ⏳ | `prisma/migrations/` | | 4.3 | UI: tombol "Verify manually" di `/admin/users/[id]` (organizer tab) | ⏳ | `app/admin/users/[id]/page.tsx` | **Tindakan manual:** tidak ada (skip phase, evaluate ulang setelah ada partnership program).