# File Manager # Uploading New File Sebelum hit API, FE ambil data per file: - `name` (contoh: `spidey.png`) - `content_type` (contoh: `image/png`) - `size_bytes` (contoh: `42170`) ## Step 1 - FE minta upload intent ke BE, lalu upload langsung ke storage ## A. Minta Upload Intent ke Backend ### Endpoint - `POST /api/v1/file-manager/files/upload` ### FE kirim request ini - Single File ```json { "data": [ { "type": "file_manager_file_upload_intent", "attributes": { "name": "image.png", "content_type": "image/png", "size_bytes": 123 } } ] } ``` - Bulk File ```json { "data": [ { "type": "file_manager_file_upload_intent", "attributes": { "name": "image1.png", "content_type": "image/png", "size_bytes": 123 } }, { "type": "file_manager_file_upload_intent", "attributes": { "name": "image2.png", "content_type": "image/png", "size_bytes": 456 } } ] } ``` ### Backend akan balas per file - `upload_intent_uuid` - `upload_url` - `method` (`PUT`) - `required_headers` - `object.bucket` - `object.key` - `expires_at` - `expires_in_seconds` Contoh response: ```json { "data": [ { "index": 0, "success": true, "resource": { "type": "file_manager_file_upload_intent", "id": "019d8215-c622-7576-86bd-3ddeecaf4867", "attributes": { "upload_intent_uuid": "019d8215-c622-7576-86bd-3ddeecaf4867", "upload_url": "http://localhost:4566/...", "method": "PUT", "required_headers": { "content-type": "image/png" }, "object": { "bucket": "wucher-file-dev", "key": "fm/objects/files/2026/04/12/019d8215c6227a1aa20fc21f99f36584.png" }, "file": { "name": "spidey.png", "mime_type": "image/png", "size_bytes": 42170 }, "expires_at": "2026-04-12T14:40:58Z", "expires_in_seconds": 899 } } } ], "meta": { "total": 1, "success": 1, "failed": 0, "partial_success": false } } ``` ## B. FE Handle langsung Upload Binary Langsung ke S3 Untuk setiap item `success: true` dari step 1: 1. Ambil `upload_url` 2. Ambil `method` 3. Ambil `required_headers` (jika ada) 4. Lakukan request upload file ke S3 Contoh yang akan dilakukan FE: ```js await fetch(upload_url, { method: method, // "PUT" headers: { "Content-Type": file.type }, body: file, }); ``` atau pseudo ```js const intents = await api.requestUploadIntents(files) // bulk const readyToUpload = intents.data.filter(i => i.success) const uploadResults = await parallelLimit(readyToUpload, 4, putToS3) // paralel const succeeded = uploadResults.filter(r => r.success) if (succeeded.length > 0) { await api.createFilesBulk(succeeded.map(toCreatePayload)) } ``` Catatan penting: - **1 file = 1 PUT ke S3** - boleh paralel (disarankan pakai concurrency limit) - file yang gagal PUT **jangan** dikirim ke step create ## Step 2 - Upload Cancel (opsional) ### Endpoint - `DELETE /api/v1/file-manager/files/cancel-upload` ### FE kirim request ini ```json { "data": [ { "type": "file_manager_file_cancel_upload", "attributes": { "upload_intent_uuid": "019d8215-c622-7576-86bd-3ddeecaf4867" } } ] } ``` ### Kapan dipakai - user sudah request upload intent - tapi user batal sebelum create - FE bisa cancel upload intent supaya flow lebih bersih ### Contoh response ```json { "data": [ { "index": 0, "success": true, "resource": { "type": "file_manager_file_cancel_upload_result", "id": "019d8215-c622-7576-86bd-3ddeecaf4867", "attributes": { "status": "canceled" } } } ], "meta": { "total": 1, "success": 1, "failed": 0, "partial_success": false } } ``` ## Step 3 - FE Panggil Create ke Backend (Finalisasi) Setelah PUT S3 sukses, FE gunakan: ### Endpoint - `POST /api/v1/file-manager/files/create` ### FE kirim request ini ```json { "data": [ { "type": "file_manager_file_create", "attributes": { "upload_intent_uuid": "019d8215-c622-7576-86bd-3ddeecaf4867", "name": "spidey.png", "folder_id": null } } ] } ``` Aturan: - `upload_intent_uuid`: wajib - `name`: wajib - `folder_id`: opsional (kalau mau dimasukkan ke folder) - `null` atau tidak dikirim = root ## Step 4 - Process Create (BE) Untuk setiap item: 1. Ambil upload intent dari `upload_intent_uuid` 2. Verify object benar-benar ada di storage 3. Verify metadata object (size/content type) sesuai intent 4. Simpan metadata file ke DB 5. Simpan outbox durable 6. Set status awal file menjadi `uploaded` ## Step 5 - Proses Async Lanjutan (Backend) Setelah status `uploaded`, worker akan lanjut: - `uploaded -> processing -> validated -> ready` - atau `uploaded -> processing -> failed` ## Step 6 - FE Handle Response Create Response create adalah bulk per item. - Kalau semua sukses: HTTP `201` - Kalau campuran sukses + gagal: HTTP `207` dengan `partial_success: true` Contoh sukses: ```json { "data": [ { "index": 0, "success": true, "message": "created", "resource": { "type": "file_manager_file", "id": "019d628a-8d92-7949-b355-95de506da3b7", "attributes": { "folder_id": "019d4309-4dc8-78be-bb0c-3ebb8f3056ba", "name": "spidey01.png", "extension": "png", "size_bytes": 42170, "mime_type": "image/png", "status": "uploaded", "created_at": "2026-04-06T11:25:40Z", "updated_at": "2026-04-06T11:25:40Z" } } } ], "meta": { "total": 1, "success": 1, "failed": 0, "partial_success": false } } ```