Jangan Pakai URL Absolut untuk Embed Gambar Komentar Plane
Embed gambar di komentar Plane API gagal total pakai URL absolut (401). Pipeline terverifikasi: helper dalam container, node image-component, asset_id mentah.
Ringkasan
Gambar di Plane emang sengaja nggak bisa dibuka lewat URL publik, makanya selalu error 401. Jadi harus bikin komentar dulu, upload file lewat helper di container plane-api, terus tempel pakai node image-component dengan src isi asset_id mentah aja. Jangan lupa ambil HTML lama dulu sebelum update biar nggak kehapus, dan ceknya lewat baca ulang komentar bukan curl anonim.
Butuh bukti visual untuk tiket QA, jadi saya sematkan 34 screenshot ke 8 komentar Plane. Komentar pertama saya tulis manual pakai tag img dengan URL absolut dari konfigurasi WEB_URL. Path-nya benar, file-nya ada di bucket, tapi gambar tidak pernah muncul. Tab Network cuma menampilkan satu baris merah: 401.
Tebakan pertama saya adalah soal izin: mungkin bucket MinIO belum terbuka untuk publik. Tapi setelah membaca ulang cara Plane menyajikan aset, tebakan itu runtuh. Plane memang dirancang supaya gambar tidak pernah dimuat lewat URL publik. Anonymous GET ke URL aset selalu dijawab 401, dan itu perilaku yang diharapkan, bukan bug [5].
Tebakan URL absolut yang salah
Alur lama di catatan saya menempelkan URL absolut hasil helper ke tag img. Kelihatannya masuk akal: URL-nya valid, browser tinggal fetch. Tapi browser tidak punya sesi Plane yang valid untuk endpoint aset, dan endpoint itu memang menuntut sesi. Hasilnya selalu sama: gambar rusak, konsol penuh 401.
Jalan keluarnya justru membatasi, bukan membuka. Gambar harus dimuat lewat proxy lokal, dan cara menyematkannya bukan tag img dengan URL lengkap, melainkan node image-component bawaan editor dengan src berisi asset_id mentah. Renderer menyelesaikan src itu relatif terhadap origin saat ini, sehingga request jatuh ke proxy lokal dan URL publik tidak pernah disentuh.
Empat langkah pipeline yang terverifikasi
Pipeline ini sudah saya verifikasi end-to-end: 34 gambar di 8 komentar, semuanya render lokal. Ada empat langkah yang tidak bisa dilompati.
Pertama, buat komentarnya dulu. Aset terikat ke ID komentar, bukan ke work item. Objek komentar resmi memuat comment_html sebagai versi string HTML dari komentar, plus comment_json dan daftar attachments [1].
Kedua, upload lewat helper di dalam container. Server MCP tidak punya tool upload file, jadi satu-satunya jalur andal adalah helper yang menyalin file ke dalam container plane-api, membuat baris FileAsset dengan tipe entitas COMMENT_DESCRIPTION dan comment_id terisi, lalu mengunggah ke bucket. Objek attachment resmi memang punya field comment berisi ID komentar bila aset terikat ke komentar, dan asset sebagai path/identifier penyimpanan [2]. Helper mencetak satu baris JSON berisi asset_id, asset_url, dan url; yang dipakai untuk embed hanya asset_id mentahnya.
Ketiga, sematkan dengan node editor native, bukan tag img. Ekstensi gambar Tiptap merender node gambar lewat tag HTML-nya sendiri; ekstensi ini hanya menampilkan, upload ditangani terpisah [3]. Bentuk node yang dipakai Plane:
<image-component data-id="<unique-uuid>" src="<asset_id>" id="<unique-uuid>" width="640px" height="360px" aspectratio="1.7777777777777777" alignment="left" status="uploaded"></image-component>data-id dan id cukup berupa UUID unik yang valid secara sintaks, satu per node. Jangan pernah menaruh URL absolut hasil helper ke src: URL itu berbasis WEB_URL sehingga menembak ke publik, melanggar aturan akses lokal saja.
Keempat, verifikasi dua lapis. Baca ulang komentar lewat MCP dan pastikan HTML-nya round-trip verbatim, lalu konfirmasi di browser bahwa gambar render lengkap dengan dimensi terbaca. Jangan verifikasi dengan curl anonim ke URL aset: 401 di sana adalah noise yang diharapkan.
Dua jebakan yang menghabiskan waktu tebakan
Jebakan pertama: update comment_html mengganti seluruh field. Endpoint update komentar mengubah konten komentar yang ada lewat body comment_html [4]. Kirim HTML baru berisi cuma node gambar, dan seluruh teks lama hilang. Wajib ambil dulu HTML aslinya secara verbatim, lalu kirim balik utuh dengan embed ditambahkan di ujung. Tulisan API disimpan verbatim; kanonikalisasi hanya terjadi saat disimpan lewat UI.
Jebakan kedua: jangan fetch dari JavaScript halaman. Pengambilan same-origin ke endpoint API dari JS halaman ditolak karena autentikasi cookie sesi tidak diterima. Seluruh pipeline ini adalah helper-script plus MCP, bukan browser fetch.
Jadi kalau kamu perlu bukti visual di komentar Plane yang self-hosted, ikuti urutannya: buat komentar dulu, upload lewat helper dalam container, sematkan node native dengan asset_id mentah, baca ulang untuk verifikasi. Meninggalkan URL absolut terasa seperti jalan memutar di awal, tapi ini satu-satunya cara yang membuat 34 dari 34 gambar tampil konsisten lewat proxy lokal.