Files
setrip/ADMIN_VERIFICATION_ROADMAP.md
T
arifal c4efe4453b -
- 
- 
- 
2026-05-18 18:31:16 +07:00

89 lines
5.7 KiB
Markdown

# 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).