Skip to content
Rafi Akmal Widikta

frontend

Bovenstad Menu

Papan menu digital yang me-refresh dirinya sendiri untuk coffee shop Belanda, disajikan lewat proxy CMS yang di-cache.

Peran
Software Engineer
Tanggal
Januari 2026

Teknologi

  • vue
  • vite
  • typescript
  • contentful
  • sanity
  • aws amplify
  • aws lambda
  • dynamodb
  • vuetify
  • unocss
  • vue-router

Masalah

Menu sebuah coffee shop berganti mengikuti musim, tapi menu di dinding tidak boleh ikut berubah sendiri. Layar di dalam toko menyala sepanjang hari di perangkat yang tidak ingin dirawat siapa pun, dan satu hal yang tidak boleh terjadi adalah menampilkan harga bulan lalu. Menarik konten langsung dari CMS di setiap refresh adalah cara yang paling jelas, sekaligus cara paling jelas untuk membebani CMS-nya.

Konten menunya juga sedang dipindahkan dari Contentful ke CMS baru, dan skema yang sudah disusun untuk perpindahan itu ditulis untuk kodenya, bukan untuk orang yang nanti harus memakainya. Product, kind, dan menu adalah tipe generik yang dirantai lewat referensi: product menunjuk kind, kind menunjuk menu, dan filter yang seharusnya menjaga sebuah kind tetap di dalam menunya justru diisi identifier milik kind itu sendiri di tempat identifier menu induknya, sehingga tidak pernah memfilter apa pun. Penamaannya tidak konsisten: satu export bernama adType sementara schema-nya bernama menuAd, dan tipe menunya sama sekali tidak berprefix. Hampir tidak ada field yang punya title, jadi editor bertemu nama field mentah seperti strength di sidebar Studio, dan tidak ada preview sama sekali sehingga setiap dokumen di daftar tampak sama. Migrasinya sendiri belum tuntas: frontend-nya masih membaca Contentful sementara tipe hasil generate masih menggambarkan skema lama; persis celah yang nanti berubah jadi bug saat runtime.

Solusi

Menunya adalah aplikasi Vue satu halaman yang statis di AWS Amplify: tidak ada server yang harus dijaga tetap hidup, tidak ada yang perlu di-patch. Kontennya ada di Contentful. Di antara keduanya berdiri sebuah Lambda kecil di belakang API Gateway yang mem-proxy Contentful dan menyimpan responsnya di DynamoDB, sehingga refresh layar yang berulang dilayani dari cache alih-alih dari CMS.

Kesegarannya ditangani dengan cara yang sengaja tumpul: <meta http-equiv="refresh" content="300">, jadi setiap layar memuat ulang dirinya tiap lima menit. Untuk papan menu itu sudah cukup: tanpa perangkat lunak kiosk, tanpa websocket, tanpa operator. Tata letaknya disesuaikan untuk layar yang benar-benar dipakai, bukan untuk jendela browser, dan carousel untuk memutar promo adalah satu-satunya tempat library komponen benar-benar berguna.

Skemanya lalu dibangun ulang sesuai tujuan sebenarnya. Empat document type menggantikan tiga tipe generik, masing-masing membawa domainnya di nama (menuProduct, menuProductBlock, menuAd, dan menuColumn): satu produk, satu blok berisi array referensi ke produk, satu iklan, dan satu kolom yang menampung blok atau iklan. Karena penyarangannya kini mengalir ke bawah sebagai array referensi (produk milik blok, blok dan iklan milik kolom), filter induk yang rusak itu tidak punya tempat tinggal lagi; sesuatu yang tidak pernah bisa diungkapkan filter kini diungkapkan oleh struktur. Setiap field mendapat title yang manusiawi dan validasi eksplisit, dengan blok wajib memuat minimal satu produk, dan setiap tipe mendapat preview yang menampilkan harga, jumlah produknya, atau penanda untuk item baru, sehingga daftar dokumen di Studio terbaca seperti menu, bukan seperti daftar berkas. Satu export diganti namanya supaya nama tipenya akhirnya cocok dengan nama schema yang bersangkutan, dan format berkasnya dinormalkan.

Yang tersisa adalah pekerjaan yang jujur, bukan sisa yang tak ada yang menyadari. Mengganti nama tipenya membuat dokumen lama di dataset produksi jadi yatim, jadi isinya perlu migrasi yang belum ada. Tipe hasil generate belum dibuat ulang, sehingga masih menggambarkan skema lama, dan frontend-nya masih membaca Contentful: hari ini migrasinya baru benar di sisi skema, belum yang lain. Satu detail rapuh juga sebaiknya diganti sebelum ada yang bergantung padanya: tipe kolom menentukan field mana yang disembunyikan dari title yang diketik editor sendiri, jadi salah ketik “Ads” atau “AD” akan diam-diam mengubah perilakunya. Itu tempatnya di field khusus dengan pilihan tetap.

Kontak

Tertarik untuk bekerja sama?

Ceritakan apa yang sedang Anda bangun dan apa yang dibutuhkan. Catatan singkat sudah cukup.

Back to top