# Handover Backend → Frontend Perubahan perilaku API hasil audit backend. Semua contoh payload di bawah diambil dari kode aktual (`src/features/...`), bukan desain baru. > Identifikasi endpoint memakai controller + method. Path lengkap mengikuti route yang sudah ada di frontend (tidak ada route path yang berubah). --- ## 1. Pagination — HANYA endpoint list WEB ### 1a. Web verification-checks — `GET /` (findAll) **Request (query params, baru):** | param | tipe | default | aturan | |---|---|---|---| | `take` | number | `50` | di-clamp ke `1..100` (angka di luar → dibatasi, bukan error) | | `skip` | number | `0` | di-clamp ≥ `0` | ``` GET /?take=20&skip=40 ``` **Response:** bentuk array check **tidak berubah**. Yang berubah: maksimal `take` row per request (sebelumnya seluruh isi tabel). ### 1b. Web verification-checks — `POST /find` (findManyByOwnerId) **Request:** ```jsonc // body (tidak berubah) { "ownerId": "..." } // query params baru: status (lihat §2), take, skip — aturan clamp sama dengan §1a POST /find?status=rejected&take=20&skip=0 ``` **Response:** bentuk tidak berubah, dibatasi `take`. ### 1c. Mobile verification-checks — list (`findManyByOwnerId`) ⚠️ **Tidak ada pagination** di endpoint mobile (`ownerId` via body, `status` via query). Default masih "semua row". Jangan kirim `take`/`skip` ke sini — diabaikan. --- ## 2. Filter `status` — perilaku diperbaiki **Sebelum (bug):** semua nilai selain `verified` dianggap "tanpa filter" → `status=rejected` dan `status=need_approval` **menampilkan semua row**. **Sesudah (web + mobile, mapping sama):** | query `status` | hasil filter | |---|---| | `verified` atau `approved` | hanya `APPROVED` | | `rejected` | hanya `REJECTED` | | `need_approval` atau `need-approval` | hanya `NEED_APPROVAL` | | tidak dikirim / nilai tidak dikenal | **tanpa filter** (semua row) — ini default lama | Tidak ada perubahan shape request/response. Klien yang tadinya "sengaja" pakai nilai aneh untuk melihat semua data: perilaku itu tetap berfungsi (nilai tidak dikenal → semua). --- ## 3. Web category list — ⚠️ SHAPE RESPONSE BERUBAH `GET` category list web (`findAll(projectId, ownerId)` di `VerificationCheckCategoriesWebService`). **Sebelum:** ```jsonc [ { "id": "...", "name": "...", "ownerId": "...", "projectId": "...", "verificationChecks": [ /* array penuh semua check di kategori ini */ ] } ] ``` **Sesudah:** ```jsonc [ { "id": "...", "name": "...", "ownerId": "...", "projectId": "...", "verifiedCounter": 3 // jumlah check berstatus APPROVED di kategori ini } ] ``` - Nested `verificationChecks` **dihapus** (itu penyebab load seluruh row per kategori). - Kalau UI butuh daftar check per kategori, ambil via endpoint check yang ada. - `verifiedCounter` sebelumnya juga ada? Tidak — ini pengganti data yang sebelumnya dihitung klien dari nested array. Endpoint web category lain **tidak berubah shape**: - status per project (`findAllStatuses`): tetap `[{ "projectId": "...", "verified": "VERIFIED" | "UNVERIFIED" | "REJECTED" }]` — hanya lebih cepat (internal `groupBy`, presedens: REJECTED > UNVERIFIED > VERIFIED). - detail (`findOne`): tetap category + `verificationChecks` + `attachments`, epoch seconds. --- ## 4. Mobile category `findOne` — sekarang berfungsi **Sebelum (bug):** `id` tidak pernah terbaca dari route → query selalu miss → endpoint error/404 untuk semua id. **Sesudah:** `@Param('id')` benar → return kategori sesuai id seperti endpoint lain. - Klien yang punya workaround (mis. pakai endpoint lain untuk detail kategori mobile) boleh dihapus. - Klien yang pernah mengandalkan error-nya: tidak ada — ini strictly perbaikan. --- ## 5. Mobile category import — response berisi `POST .../import` (mobile category, multipart `file`). **Sebelum (bug):** response body **selalu `[]`** berapapun isi Excel. **Sesudah:** array kategori yang ter-create/ter-find: ```jsonc [ { "id": "...", "name": "...", "projectId": "...", "ownerId": "...", "createdAt": ..., "updatedAt": ... } ] ``` Import check (verification-checks `processImport`) juga di-batch — **shape response tetap**, hanya lebih cepat dan aman untuk file besar. --- ## 6. Error responses | kasus | sebelum | sesudah | |---|---|---| | JSON body rusak di create/update check mobile (field `verificationCheck`) | 500 (SyntaxError unhandled) | **400** `"Invalid JSON payload"` | | record tidak ditemukan (Prisma P2025) | 404 | 404 (tidak berubah) | | error server tak terduga | 500 + detail internal Prisma bocor (`meta`: query/model) | **500** body generik: `"An unexpected error occurred."` | Contoh 400: ```json { "statusCode": 400, "message": "Invalid JSON payload", "error": "Bad Request" } ``` Jangan parse `message` 500 untuk logika — isinya selalu generik sekarang. --- ## 7. Upload (multipart) Berlaku di semua endpoint upload (check attachments, category import, dsb): | batas | sebelum | sesudah | |---|---|---| | jumlah file per request | praktis unlimited (1000 × 40MB) | **maks 10 file** | | ukuran per file | 200MB (Excel) / 40MB | **10 MB** | | ekstensi file | apa pun yang klien kirim | **dipaksa dari mimetype**: hanya `jpg/jpeg/png/pdf` (upload dokumen) | - Upload melebihi batas → ditolak multer (HTTP 4xx), bukan dipotong. - Nama file asli klien tidak lagi dipakai untuk ekstensi — server yang menentukan dari mimetype. Rename file di sisi klien tidak berpengaruh. - Request JSON dibatasi **1 MB**. --- ## 8. CORS — action needed per environment `origin: '*'` dihapus. Sekarang dari env: ``` CORS_ORIGINS="https://app.example.com,https://admin.example.com" ``` - `CORS_ORIGINS="*"` → semua origin diizinkan (transisi sementara; ganti ke daftar asal begitu lengkap). - Kosong/tidak di-set → CORS mati (same-origin only) → browser frontend cross-origin akan block. - **Wajib diisi di `.env` setiap environment sebelum deploy.** --- ## 9. Env baru (ops) ``` REDIS_URL="redis://default:password@localhost:6379" # prioritas; support username+password #REDIS_HOST="localhost" # fallback kalau REDIS_URL kosong #REDIS_PORT="6379" CORS_ORIGINS="" # wajib diisi untuk akses cross-origin ``` --- ## Catatan backend (bukan urusan frontend) - `prisma migrate dev` perlu dijalankan (index baru + kolom panjang `@db.Text`). Belum ada migration. - Auth/JWT: sengaja belum diimplementasi (keputusan owner). Semua endpoint masih publik.