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.