Desain Sistem · Arsitektur · Design System · Prototipe

ApotekHijau — kasir apotek
yang tetap jalan saat internet mati

Point of Sale untuk apotek Indonesia: offline-first, sadar interaksi obat, paham stok pecahan sampai butir tablet, dan berbicara HL7 FHIR R4 ke SATUSEHAT, KFA, serta BPJS.

OFFLINE-FIRST SATUSEHAT KFA BROWSER HL7 FHIR R4 BPJS CLAIM KEYPAD-ONLY PORTRAIT → TABLET

TESIS Satu keputusan yang menentukan segalanya

Apotek tidak menjual "produk", ia menyerahkan dosis. Pasien membeli ½ strip, apoteker meracik 1½ tablet per bungkus, dan stok harus tetap benar. Karena itu satuan penyimpanan sistem ini bukan strip melainkan butir tablet — dan seluruh harga, stok, racikan, serta laporan diturunkan dari satu angka itu.

Keputusan kedua: kasir apotek bekerja di layar sentuh dengan tangan sibuk dan koneksi tidak menentu. Maka tidak ada keyboard bawaan (semua lewat keypad kustom), dan tidak ada layar yang menunggu jaringan — transaksi selesai di lokal, sinkronisasi menyusul.

1 strip = 10
butir tablet sebagai satuan atom penyimpanan
0 ms
ketergantungan jaringan untuk menyelesaikan transaksi
7 mesin
aturan inti yang menjaga keselamatan & pembukuan
Coba di sini · model stok atom

Blister Paracetamol 500 mg

Ketuk butiran untuk menjual eceran. Angka di bawah adalah cara sistem menyimpan dan menampilkan stok.

116 strip tampilan kasir st = 1160 tab
Stok awal: 116 strip utuh. Menjual 3 butir membuat satu strip “terbuka”.

Masalah yang dipecahkan

Empat kondisi nyata di apotek yang membuat kasir ritel biasa gagal dipakai.

01 Obat bisa saling melawan

Ibuprofen bersama Aspirin menaikkan risiko perdarahan lambung. Dua produk berbeda bisa memuat parasetamol yang sama hingga dosis harian terlampaui. Kasir tidak boleh menjadi satu-satunya penjaga; sistem harus mengingatkan saat barang masuk keranjang, bukan setelah struk tercetak.

02 Yang dibeli sering bukan satu kemasan

"Beli paracetamol 5 butir saja" adalah transaksi normal. Begitu pula racikan puyer dengan ½ atau 1½ tablet per bungkus. Stok yang disimpan per strip akan langsung salah pada transaksi pertama.

03 Obat keras tidak boleh lepas tanpa resep

Golongan Keras dan pelayanan BPJS punya syarat administratif yang wajib lengkap. Sistem harus menolak, bukan sekadar memperingatkan, dan menawarkan jalan yang benar.

04 Internet apotek tidak bisa diandalkan

Kewajiban lapor ke SATUSEHAT tidak boleh menghentikan pelayanan. Transaksi harus tuntas di perangkat, lalu diantrekan dan dikirim ulang otomatis dengan jejak yang bisa diaudit.

Konsekuensi desain. Empat kondisi di atas melahirkan tujuh mesin aturan di tab Mesin Inti. Setiap mesin punya satu tanggung jawab dan bisa diuji terpisah — itulah alasan sistem ini dirancang sebagai kumpulan aturan, bukan kumpulan formulir.

Prinsip perancangan

Lima aturan yang dipakai untuk memutuskan saat ada pilihan yang saling bertentangan.

PrinsipPenerapan konkret di produk
Keselamatan mendahului kecepatanInteraksi obat dan duplikasi zat aktif diperiksa pada setiap penambahan item, bukan di akhir. Obat keras diblokir di jalur OTC, dengan satu ketukan untuk pindah ke jalur resep.
Lokal dulu, jaringan menyusulSumber kebenaran ada di perangkat. Sinkronisasi berupa antrean dengan status, percobaan ulang, dan tabel audit yang bisa dibuka petugas.
Satuan terkecil sebagai kebenaranStok disimpan dalam butir. Strip hanyalah cara menampilkan. Pecahan tablet selalu dibulatkan ke atas untuk stok dan harga, dan pembulatan itu ditampilkan terbuka.
Tidak ada uang yang berpindah tanpa jejakLaci dicatat bruto–kembalian–net, bukan hanya net. Buku kas, selisih penutupan, dan klaim non-tunai dipisahkan.
Satu tangan, layar sentuhSemua masukan lewat keypad kustom dan pemilih ber-pencarian. Tidak ada dropdown bawaan, tidak ada keyboard OS yang menutupi setengah layar.

Peran & hak akses

Sistem dipakai tiga peran dengan kewenangan berbeda; back-office terpisah dari kasir.

🩺 Apoteker (APA) SIPA
  • Buka / tutup shiftpenuh
  • Layani resep & racikanpenuh
  • Konfirmasi interaksi obatwajib
  • Serah obat keras / OWApenuh
👤 TTK / Kasir STRTTK
  • Transaksi OTCpenuh
  • Racikanbutuh apoteker
  • Kas masuk / keluardengan catatan
  • Tutup shifthitung kas wajib
🗂️ Back-office CRUD
  • Master obat & hargasumber KFA
  • Paket obatkurasi
  • Master signaetiket
  • Aturan interaksikurasi apoteker
Kasir mengunci diri sendiri saat shift tertutup: seluruh penambahan item, pembayaran, dan pelanjutan pesanan diblokir sampai ada modal awal kas yang tercatat. Ini membuat setiap rupiah punya pemilik shift.

Peta layar

Enam layar tetap plus satu layar yang hanya muncul bila mode debug dinyalakan. Navigasi memakai bilah bawah pada ponsel dan rail samping pada tablet.

🧾 Kasir

Jalur utama transaksi. Pemilih jenis penjualan, paket siap jual, pencarian, grid obat dengan stok & tombol eceran, tombol racik, dan keranjang.

gerbang jenisgerbang obat keraseceran ½ stripbuilder racikankunci shift
💊 Obat

Master obat hasil sinkron KFA: komposisi zat aktif sebagai chip, kode KFA, golongan, harga strip & eceran, stok, dan daftar interaksi yang diketahui.

cari zat aktifdetail + FHIR idefek kombinasi
📦 Paket

Bundel racikan back-office (Paket Flu, Maag, Diare…) dengan rincian isi, penghematan, dan pemeriksaan keamanan kombinasi.

jual satu ketukancek interaksi paket
📥 Pesanan

Satu antrean untuk tiga sumber: draft kasir, pesanan online/WhatsApp, dan resep digital SATUSEHAT. Bendera warna + filter berhitung.

flag sumberfilterlanjutkan ke keranjang
🔁 Shift

Buka/tutup shift, buku kas, dan laporan. Riwayat shift berpaginasi; ketuk untuk detail berisi ringkasan kas dan transaksi shift itu (paginasi kedua) dengan tombol kembali.

bruto → kembalian → netselisih kasdrill-down
⚙️ Setelan

Tema, status integrasi SATUSEHAT/KFA/FHIR, sinkron otomatis, dan sakelar mode debug.

temastatus integrasisakelar debug
🐞 Debug
bersyarat

Muncul hanya bila mode debug aktif. Tabel antrean sinkron berpaginasi dengan filter status, arah push/pull, jumlah percobaan, dan ukuran payload; plus simulasi offline dan pemicu data masuk.

audit sinkronsimulasi offlinekirim antrean

Arsitektur lapis

Empat lapis dengan satu aturan keras: lapis aplikasi tidak pernah memanggil jaringan secara langsung. Semua keluar-masuk data melalui antrean sinkron.

Antarmuka kasirLapis 1 · perangkat

Layar sentuh apotek: ponsel portrait sampai tablet. Menyusun tampilan dari state lokal dan tidak pernah menunggu balasan server.

KasirKeranjangKeypad kustomPicker ber-pencarianBuilder racikanShift & laporan
▼ ▼ ▼
Mesin aturanLapis 2 · domain

Seluruh keputusan klinis dan pembukuan. Murni fungsi terhadap state — mudah diuji, tidak bergantung DOM maupun jaringan.

interaksi_obatstok_atomgerbang_jenisracikankas_lacishiftantrean_pesanan
▼ ▼ ▼
Penyimpanan lokal & antrean sinkronLapis 3 · offline-first

Sumber kebenaran saat berjalan. Menyimpan master obat, transaksi, shift, draft, dan antrean keluar-masuk beserta status & jumlah percobaan.

master_obattransaksishiftpesanan_draftantrean_sinkronaudit_log
▼ ▼ ▼
Integrasi eksternalLapis 4 · luar

Diakses hanya oleh pekerja sinkron, dengan idempotensi berbasis id lokal agar pengiriman ulang tidak menggandakan data.

SATUSEHAT · FHIR R4KFA BrowserBPJS · ClaimWhatsApp BusinessBack-office

ALIRAN Jalur sebuah transaksi

ketuk obat │ ├─ gerbang_jenis OTC / Resep / BPJS sudah dipilih? ──tidak──▶ minta pilih jenis ├─ gerbang_keras golongan Keras di jalur OTC? ──ya────▶ tawarkan pindah ke Resep ├─ stok_atom tersedia ≥ kebutuhan butir? ──tidak──▶ tolak / sarankan eceran ├─ interaksi_obat ada interaksi / duplikasi baru? ──ya────▶ konfirmasi apoteker │ ▼ keranjang ──▶ kas_laci hitung bruto/kembalian/net ──▶ simpan lokal │ ┌────────────────────────────────────────┴───────────┐ ▼ ▼ potong stok butir antrean_sinkron (pending) catat mutasi ke layar sukses MedicationDispense · InventoryReport + Claim (BPJS) · MedicationRequest (resep)
Kenapa antrean, bukan panggilan langsung. Dengan antrean, kegagalan jaringan menjadi kondisi normal yang punya status dan tombol coba-lagi — bukan kesalahan yang membatalkan transaksi. Petugas melihat sendiri berapa data yang belum terkirim.

Model data

Sembilan entitas inti. Perhatikan stok pada Obat: satuannya butir, bukan kemasan — di situlah seluruh ketelitian sistem bermula.

Obat Medication
  • id · kode_kfaidentitas
  • nama · bentuktampilan
  • zat_aktif[]kunci interaksi
  • golonganbebas…keras
  • harga_kemasanrupiah
  • stokbutir (atom)
  • satuan · isi_kemasanstrip = 10
Aturan Interaksi kurasi
  • zat_a · zat_bpasangan
  • tingkatberat/sedang/ringan
  • efekteks chip
  • sarantindakan apoteker
Paket back-office
  • nama · deskripsikurasi
  • item[]obat + jumlah
  • harga_paket< jumlah satuan
Racikan compound
  • namaetiket
  • bentukpuyer/kapsul/sirup
  • jumlahbungkus
  • komponen[]obat + dosis/bungkus
  • signadari master
  • jasa_racikrupiah
Baris Keranjang line
  • jenisobat/paket/racikan
  • satuankemasan / butir
  • jumlahsesuai satuan
Pesanan / Draft order
  • sumberkasir/online/resep
  • pasiennama + WA
  • jenis_penjualanotc/resep/bpjs
  • data_resepno · dokter · BPJS
  • isi[]baris keranjang
Shift PaymentRecon
  • petugas · buka · tutupjejak
  • kas_awalmodal
  • tunai_brutoditerima
  • kembaliandiserahkan
  • qris · bpjsnon-laci
  • kas_aktual · selisihhitung fisik
Transaksi MedDispense
  • nomor · waktuidentitas
  • jenis_penjualanotc/resep/bpjs
  • metodetunai/qris/bpjs
  • tunai_diterimabruto
  • kembaliankeluar laci
  • mutasi_stok[]butir per obat
  • catatan_interaksiaudit klinis
Antrean Sinkron queue
  • id_lokalidempotensi
  • entitas · resourceFHIR
  • arahpush / pull
  • status4 keadaan
  • percobaan · ukuranaudit
Aturan turunan. Harga eceran per butir = harga kemasan ÷ isi kemasan, dibulatkan ke Rp100 agar tidak muncul pecahan rupiah yang tak bisa dibayar. Konversi tampilan stok: strip = ⌊butir ÷ 10⌋, sisa ditampilkan sebagai tablet lepas.

Mesin sinkronisasi

Empat status, dua arah, dan satu prinsip: kegagalan tidak pernah menghalangi pelayanan.

STATUS pending ──kirim──▶ synced │ ├──gagal──▶ failed ──coba ulang otomatis──▶ pending └──versi server lebih baru──▶ conflict ──▶ tinjauan petugas ARAH push ⬆ transaksi · stok · klaim BPJS · penyelesaian resep pull ⬇ master obat (KFA) · harga · resep digital · pesanan online PEMICU (1) selesai transaksi → antrekan otomatis (2) timer berkala → kirim antrean saat online (3) tombol manual → "Kirim antrean" di layar Debug (4) kembali online → antrean dikirim menyusul

Idempotensi

Setiap baris antrean membawa id_lokal yang dikirim sebagai identifier. Pengiriman ulang setelah timeout tidak menciptakan penyerahan obat ganda di SATUSEHAT.

Urutan yang dijaga

Penyelesaian resep tidak boleh terkirim sebelum penyerahan obatnya. Antrean karena itu diproses berdasarkan urutan pembuatan per entitas, bukan paralel bebas.

Konflik data master

Master obat dan harga selalu pull — perangkat tidak pernah menang. Jika harga berubah setelah transaksi terjadi, transaksi tetap memakai harga saat penjualan dan perbedaan itu terlihat di audit.

Yang dilihat petugas

Lencana di kepala layar: Tersinkron, n antre sinkron, atau Offline · n antre. Satu ketukan membuka tabel audit lengkap.

Simulasi antrean offlineinteraktif
● tersinkron · 0 antre
IDEntitasResource FHIRArahStatusCoba
Matikan koneksi, lalu buat beberapa transaksi — pelayanan tetap jalan dan antrean menumpuk dengan status pending.

Mesin 1 · Interaksi & duplikasi zat aktif

Mesin klinis paling penting. Bekerja pada level zat aktif, bukan nama produk — sehingga tetap menangkap bahaya walau pasien membeli merek berbeda.

Cara kerja

  • Ratakan keranjang. Paket diurai jadi obat penyusunnya; racikan diurai jadi komponennya. Hasilnya satu daftar zat aktif beserta produk asalnya.
  • Cari pasangan berbahaya. Setiap aturan interaksi diuji terhadap daftar itu; kecocokan hanya dihitung bila kedua zat berasal dari produk berbeda.
  • Cari duplikasi. Satu zat aktif yang muncul dari dua produk berbeda ditandai berat — inilah penyebab overdosis parasetamol yang paling sering terjadi.
  • Bandingkan sebelum & sesudah. Yang dikonfirmasi ke apoteker hanya temuan baru akibat item yang sedang ditambahkan, supaya tidak ada peringatan berulang.

Titik pemunculan

KapanBentuk
Sebelum item masukKartu obat diberi tanda ⚠ interaksi pada grid kasir
Saat item ditambahkanModal konfirmasi berisi chip temuan + saran; butuh persetujuan
Di keranjangPanel ringkasan berat vs. perlu-perhatian, atau tanda aman
Saat meracikCek antar komponen langsung di dalam builder
Di master obatDaftar interaksi yang diketahui pada detail obat
Setelah transaksiJumlah catatan interaksi tersimpan sebagai jejak audit klinis
Coba mesin interaksiinteraktifpilih beberapa obat seperti isi keranjang
Kenapa chip, bukan paragraf. Kasir membaca sambil melayani. Chip berwarna dengan tingkat keparahan di depan bisa dipindai dalam satu detik; penjelasan panjang diletakkan sesudahnya sebagai saran tindakan.

Mesin 2 · Stok atom & penjualan pecahan

Satu obat bisa terjual sebagai strip utuh, ½ strip, butiran lepas, bagian dari paket, atau komponen racikan — semuanya memotong stok yang sama.

PENYIMPANAN stok disimpan dalam butir 116 strip → st = 1160 TAMPILAN ⌊st ÷ 10⌋ strip + sisa tab 1155 → "115 strip + 5 tab" HARGA ECERAN ⌈(harga_strip ÷ 10) ÷ 100⌉ × 100 Rp3.500 → Rp400 / butir KETERSEDIAAN tersedia = stok − seluruh butir yang sudah dipesan di keranjang (baris strip · baris eceran · komponen paket · komponen racikan) PECAHAN kebutuhan butir = ⌈dosis × jumlah⌉ 1½ tab → dibebankan 2 tab pembulatan ditampilkan terbuka di builder racikan & layar sukses

Sebelum pembelian

Kartu obat menampilkan stok terbaca (116 strip) dan, untuk sediaan tablet, tombol +½ strip beserta harga per butir. Detail obat memuat harga kemasan, harga eceran, dan stok dalam dua satuan.

Saat pembelian

Eceran menjadi baris tersendiri: 5 tab (½ strip) · Rp400/tab, dengan stepper per butir. Strip dan eceran obat yang sama hidup berdampingan sebagai dua baris, dan lencana kartu menulis 1+5t.

Sesudah pembelian

Layar sukses menampilkan panel mutasi stok per obat: −16 tab → sisa 114 strip + 4 tab. Kelipatan sepuluh ditulis sebagai strip agar cocok dengan cara petugas menghitung fisik.

📋
Implikasi stok opname. Karena strip yang sudah dibuka tercatat sebagai butir lepas, penghitungan fisik gudang bisa dicocokkan persis: sistem tahu ada berapa strip utuh dan berapa butir terbuka.
Kalkulator stok & pembulataninteraktif
Dosis per bungkus:
× jumlah:

Mesin 3 · Gerbang jenis penjualan

Jenis transaksi ditentukan lebih dulu, karena ia mengubah obat apa yang boleh keluar, data apa yang wajib, dan siapa yang menagih.

item pertama ditambahkan │ ▼ jenis sudah dipilih? ──tidak──▶ modal pilih jenis ──▶ item tertunda ikut masuk otomatis │ ya ▼ ┌─────────────┬──────────────────────┬───────────────────────────────┐ │ OTCRESEPBPJS │ ├─────────────┼──────────────────────┼───────────────────────────────┤ │ bebas ✓ │ semua golongan ✓ │ semua golongan ✓ │ │ terbatas ✓ │ no. resep wajib │ no. resep + dokter wajib │ │ OWA ✓ dicatat│ nama dokter wajib │ no. kartu BPJS wajib │ │ keras ditolak│ racikan ✓ │ racikan ✓ │ │ racikan ditolak│ bayar tunai/QRIS │ tagihan pasien Rp0 │ │ │ │ → terbit SEP + FHIR Claim │ └─────────────┴──────────────────────┴───────────────────────────────┘ penolakan selalu menawarkan jalan keluar: "Ganti ke Resep" (satu ketukan, item langsung masuk) pindah balik ke OTC ditolak selama keranjang masih memuat obat keras
Coba gerbang penjualaninteraktif
Jenis:

Mesin 4 · Racikan

Racikan adalah produk yang dibuat saat itu juga: punya komposisi, bentuk sediaan, jumlah, aturan pakai, dan jasa peracikan.

Struktur builder

  • Nama racikan — keypad teks, dipakai di etiket dan struk.
  • Bentuk sediaan — puyer, kapsul, atau sirup; mengubah satuan (bungkus/kapsul/botol) dan tarif jasa racik.
  • Jumlah & jasa racik — keypad angka.
  • Aturan pakai (signa) — dipilih dari master, bukan diketik bebas, agar etiket konsisten.
  • Komponen — dicari lewat keypad, dosis diatur stepper pecahan ¼ / ½ / ¾ / 1.
Kenapa stepper, bukan keypad, untuk dosis. Pecahan tidak bisa diketik di papan angka tanpa memaksa kasir berpikir desimal. Stepper menghilangkan pengetikan sekaligus mencegah dosis tak lazim seperti 0,37 tablet.

Perhitungan & keamanan

butir dibebankan = ⌈dosis × jumlah⌉ per komponen harga komponen = butir_dibebankan × harga_eceran total racikan = Σ harga komponen + jasa racik ½ tab × 3 bungkus = 1½ tab → dibulatkan 2 tab ditampilkan di builder sebagai peringatan oranye
  • Cek interaksi antar komponen berjalan langsung di dalam builder — dua NSAID dalam satu puyer langsung tertangkap.
  • Validasi stok per komponen sebelum simpan; saat mengedit racikan yang sudah di keranjang, reservasi lama dibebaskan dulu agar tidak menghitung ganda.
  • Signa wajib — racikan tanpa aturan pakai tidak boleh masuk keranjang.
  • Di keranjang, racikan tampil sebagai kartu dengan komposisi dan tombol Edit, bukan stepper jumlah.

Mesin 5 · Kas laci & kembalian

Uang fisik bergerak dua arah dalam satu transaksi. Mencatat hanya nilainya membuat selisih kas mustahil ditelusuri.

total Rp45.000 · pelanggan bayar Rp100.000 laci ⬅ masuk +Rp100.000 (tunai_bruto) laci ➡ keluar −Rp55.000 (kembalian) ──────────────────────────────── net = +Rp45.000 (= penjualan tunai) kas laci seharusnya = kas_awal + net tunai + kas masuk lain − kas keluar selisih = kas aktual dihitung − kas laci seharusnya QRIS & BPJS dicatat terpisah sebagai non-laci: menambah omzet, tidak menambah uang fisik.
Simulasi kembalianinteraktif
Total:
Dibayar:
Layar sukses menampilkan kembalian dalam ukuran besar plus saran pecahan uang (1 × Rp50.000, 1 × Rp5.000) — mengurangi salah serah pada jam ramai, dan mempercepat kasir baru.

Mesin 6 & 7 · Shift dan antrean pesanan

6 Siklus shift

tertutup ──buka (modal awal wajib)──▶ berjalan ▲ │ │ transaksi · kas masuk/keluar │ │ └──tutup (hitung kas fisik wajib)──────┘ │ ├─ bekukan laporan → riwayat └─ antrekan PaymentReconciliation

Saat tertutup, kasir tertutup lapisan kunci: menambah item, membayar, dan melanjutkan pesanan semuanya diblokir. Riwayat shift berpaginasi; ketuk untuk melihat ringkasan kas dan daftar transaksi shift tersebut yang juga berpaginasi.

7 Antrean pesanan tiga sumber

🏪 draft kasir simpan keranjang berjalan 🌐 online/WA masuk sebagai CommunicationRequest 🩺 resep SATUSEHAT masuk sebagai MedicationRequest │ ▼ satu antrean · bendera warna + filter berhitung │ "Lanjutkan / Proses / Layani" │ ▼ keranjang terisi + jenis penjualan & data pasien ikut dipulihkan (resep berkartu → langsung BPJS)

Bila kasir sedang memegang keranjang lain, keranjang itu otomatis diamankan menjadi draft sebelum pesanan baru dimuat — tidak ada pesanan yang hilang karena tergesa.

Fondasi 01 · Warna

Hijau apotek sebagai warna kerja, ditambah satu set warna yang bukan pilihan estetis: penandaan golongan obat mengikuti simbol resmi yang sudah dikenal apoteker.

Palet inti

Hijau apotek#0E9F6EAksi utama, status aktif, nilai positif
Hijau dalam#0A6B4AHarga, judul angka, gradien tombol
Hijau lembut#DFF3EALatar terpilih, thumbnail, chip aktif
Tinta#0A2318Teks utama, toast, bilah gelap
Redup#5B7268Teks sekunder, label, satuan
Kertas mint#EFF6F1Latar aplikasi & dokumen

Penandaan golongan obat — mengikuti simbol resmi

Obat Bebas #1E9E52 Bebas Terbatas #1E5EE5 Obat Keras #D0021B OWA #7A3FD1

Lingkaran hijau, biru, dan merah-ber-K adalah bahasa yang sudah dipakai apoteker setiap hari di kemasan. Memakainya di layar berarti tidak ada yang perlu dihafal ulang — dan kesalahan membaca golongan menjadi jauh lebih kecil.

Warna status

Aman / tersinkron#0E8A5FTanpa interaksi, kas pas, terkirim
Perlu perhatian#B96A00Interaksi sedang, antrean pending, pembulatan
Bahaya / gagal#D93843Interaksi berat, stok habis, sinkron gagal
BPJS & eceran#1E5EE5Klaim, tombol ½ strip, sumber online
Mode gelap memakai token yang sama dengan nilai berbeda; seluruh komponen menarik warna dari variabel, sehingga tidak ada warna yang ditulis langsung di komponen.

Fondasi 02 · Tipografi

Dua wajah huruf dengan tugas terpisah, plus satu wajah mono khusus data yang harus bisa dieja: kode KFA, nomor resep, dan nama resource FHIR.

DisplaySpace Grotesk 700
Rp1.245.000 · Shift 2 berjalan
Judul layarSpace Grotesk 700 · 20px
Pesanan & Draft
IsiInter 400/600 · 15px
Paracetamol 500 mg — komposisi: Parasetamol. Stok 116 strip.
Label & satuanInter 600 · 11px · huruf besar
Kas laci seharusnya
Data & kodeJetBrains Mono 500 · 11–12px
KFA 93001019 · MedicationDispense · RX/2026/0742
Angka selalu tabular. Seluruh nominal memakai font-variant-numeric: tabular-nums agar kolom rupiah pada laporan dan tabel sinkron tetap lurus saat nilainya berubah.

Fondasi 03 · Bentuk, jarak & gerak

Radius & jarak

TokenNilaiDipakai
--r-s8–9pxTag, tombol kecil, sel keypad
--r-m13–14pxKartu obat, tombol utama, panel
--r-l16–22pxSheet, modal, kartu ringkasan
Chip99pxChip interaksi, filter, bendera sumber
Ritmekelipatan 4Padding 8/12/16, jarak antar kartu 9–12

Target sentuh

Tombol keypad 52px, sel kartu obat ≥ 96px, tombol aksi utama 44px. Semua dirancang untuk ibu jari, bukan kursor.

Gerak — bertema perawatan

Garis EKGLayar masuk — menandai sistem hidup
2.6s linear
Denyut jantungTitik status shift & peringatan interaksi
1.8s
Jatuh tabletItem masuk keranjang, baris antrean baru
.3s ease
Kapsul berputarSedang mengirim antrean sinkron
.8s linear
Seluruh animasi berhenti bila sistem operasi meminta prefers-reduced-motion. Gerak hanya dipakai untuk menandai perubahan keadaan — tidak ada animasi dekoratif pada jalur transaksi.

Komponen inti

Sembilan komponen yang menyusun hampir seluruh antarmuka.

Bebas Keras · Resep OWA beratIbuprofen × Aspirin — perdarahan lambung sedangCTM × Setirizin — kantuk berlebih
KomponenPeran & aturan
Keypad kustomDua mode: angka (dengan 000, Hapus, ⌫) dan teks QWERTY. Mode raw untuk nomor HP & kartu BPJS agar tidak diberi pemisah ribuan. Batal mengembalikan nilai semula.
Picker ber-pencarianDropdown master dengan pencarian keypad, pencocokan ke label maupun keterangan, tanda ✓ pada pilihan aktif, dan jalan keluar "ketik manual".
Kartu obatEmoji sediaan, nama, harga kemasan, golongan, stok terbaca, tombol eceran, lencana jumlah di keranjang, dan tanda interaksi.
Chip interaksiTingkat keparahan di depan, lalu pasangan zat dan efeknya. Warna mengikuti token status.
Sheet keranjangMuncul dari bawah pada ponsel, mengambang di tengah pada tablet. Memuat data pasien, baris item, panel interaksi, dan ringkasan.
KomponenPeran & aturan
Stepper pecahanKhusus dosis racikan; melangkah ¼ tablet dan menampilkan lambang pecahan, bukan desimal.
Tabel berpaginasiDipakai antrean sinkron, riwayat shift, dan transaksi per shift. Pola sama: filter berhitung, ukuran halaman, nomor ringkas dengan elipsis.
Bendera sumberMenandai asal pesanan (kasir / online / resep) di antrean, keranjang, dan baris laporan.
Layar suksesKembalian besar, saran pecahan uang, arus laci tiga kolom, mutasi stok, dan catatan integrasi.
Keypad angka
Bendera sumber
🏪 Kasir 🌐 Online · WA 🩺 Resep SATUSEHAT

Responsif — portrait sampai tablet

Satu tata letak yang berubah pada tiga titik henti; kasir apotek memakai ponsel, tablet meja, atau keduanya bergantian.

< 640px
Ponsel portrait

Bilah tab di bawah, grid obat 2 kolom, sheet naik dari bawah, keranjang mengambang di atas bilah tab.

≥ 640px
Ponsel besar

Sheet dan modal menjadi kartu mengambang dengan sudut penuh, bukan menempel di tepi bawah.

≥ 760px
Tablet portrait

Grid obat 3 kolom, kartu statistik 4 kolom, isi dokumen melebar.

≥ 900px
Tablet landscape

Bilah tab bawah berganti menjadi rail navigasi vertikal di kiri; bilah keranjang pindah ke pojok kanan bawah agar tidak menutupi grid.

≥ 1100px
Meja kasir lebar

Grid obat 4 kolom dengan lebar isi dibatasi supaya jarak baca tetap nyaman.

Alur 01 · Penjualan OTC dengan kembalian

Jalur tersibuk. Tujuh ketukan dari layar kunci sampai struk, tanpa satu pun keyboard sistem.

buka shift modal awal kas via keypad → kasir terbuka, laci punya pemilik │ pilih jenis OTC (muncul otomatis saat item pertama) │ tambah obat kartu obat · atau tombol +½ strip untuk eceran │ └─ mesin interaksi memeriksa keranjang setiap kali │ buka keranjang isi data pasien (nama + WA) bila ingin struk WhatsApp │ bayar total Rp45.000 · terima Rp100.000 via keypad │ └─ catatan hidup: "masuk +100.000 · keluar −55.000 · net +45.000" ▼ layar sukses kembalian Rp55.000 besar + saran pecahan (1×50rb, 1×5rb) arus laci 3 kolom · mutasi stok per obat antrean: MedicationDispense + InventoryReport

Alur 02 · Resep digital dari SATUSEHAT

SATUSEHAT ──pull MedicationRequest──▶ antrean Pesanan (bendera 🩺) │ no. resep · dokter · faskes │ pasien + no. WA ▼ ketuk "Layani" │ ┌──────────────────────────────────────┴─────────────────────────┐ │ keranjang terisi jenis penjualan dipilih otomatis │ │ data pasien terisi ada no. kartu BPJS? → BPJS, jika tidak → Resep │ │ obat keras diizinkan data resep terisi dari berkas │ └──────────────────────────────────────┬─────────────────────────┘ ▼ bayar / terbitkan SEP │ push MedicationDispense ─┼─ push MedicationRequest (selesai dilayani) └─ push Claim bila BPJS
Resep yang datang lewat jalur ini tidak bisa dilayani sebagai OTC — jenis penjualannya sudah ditentukan berkas, bukan oleh kasir.

Alur 03 · Racikan puyer anak

ketuk 🧪 Racik │ ├─ jenis belum dipilih? → minta pilih jenis ─┐ ├─ jenis = OTC? → "racikan wajib resep" → Ganti ke Resep (1 ketukan) │ │ ▼ ▼ builder nama · bentuk (puyer/kapsul/sirup) · jumlah · jasa racik signa ← dipilih dari master, dicari lewat keypad komponen ← cari obat → stepper ¼ ½ ¾ 1 │ ├─ interaksi antar komponen dicek langsung └─ ½ tab × 3 bungkus = 1½ tab → dibulatkan 2 tab (ditandai oranye) ▼ simpan → kartu racikan di keranjang (dengan tombol Edit) ▼ bayar → stok komponen dipotong dalam butir, tampil di mutasi stok

Alur 04 · Pesanan online / WhatsApp

pelanggan chat WA ──▶ CommunicationRequest ──pull──▶ antrean Pesanan (bendera 🌐) │ nama · no. WA · catatan ▼ ketuk "Proses" │ keranjang aktif sedang terpakai? → diamankan jadi draft dulu ▼ lanjut seperti transaksi biasa ▼ struk & pengingat minum obat dikirim balik ke WA

Tiga sumber pesanan hidup di satu layar karena beban kerjanya sama: keranjang yang menunggu diselesaikan. Yang berbeda hanya asal-usul dan syaratnya — itulah yang dibawa oleh bendera warna dan filter berhitung.

Peta integrasi

Empat sistem luar, masing-masing dengan sumber daya dan arah yang jelas.

SistemResource / kanalArahDipicu oleh
KFA BrowserMedication⬇ pullSinkron master obat: nama, kode KFA, komposisi, golongan
Back-officeChargeItemDefinition⬇ pullHarga, paket obat, master signa, aturan interaksi
SATUSEHATMedicationRequest⬇ pullResep digital masuk dari faskes
SATUSEHATMedicationDispense⬆ pushSetiap transaksi selesai — penyerahan obat
SATUSEHATMedicationRequest⬆ pushMenandai resep selesai dilayani
InternalInventoryReport⬆ pushMutasi stok dalam satuan butir
BPJS KesehatanClaim⬆ pushTransaksi BPJS — tagihan pasien Rp0, SEP terbit
ShiftPaymentReconciliation⬆ pushPenutupan shift beserta selisih kas
WhatsApp BusinessCommunicationRequest⬇ pullPesanan pelanggan masuk sebagai draft
WhatsApp Businesspesan keluar⬆ pushStruk digital & pengingat minum obat
Kepatuhan. Golongan obat, kewajiban resep, pencatatan pelayanan OWA, dan pelaporan penyerahan obat mengikuti ketentuan Kemenkes. Standar pertukaran datanya HL7 FHIR R4 — perhatikan penulisannya HL7, bukan FL7.

Sifat non-fungsional

≤ 1 dtk
dari ketukan bayar sampai layar sukses, tanpa jaringan
100%
transaksi tuntas saat offline; antrean menyusul otomatis
4 status
pending · synced · failed · conflict, semuanya bisa diaudit petugas
0 dropdown
bawaan sistem — seluruh masukan lewat keypad & picker kustom

Keamanan & jejak

  • Masuk dengan PIN per petugas; peran menentukan kewenangan.
  • Kasir terkunci di luar shift — tidak ada transaksi tanpa pemilik.
  • Setiap konfirmasi interaksi tersimpan sebagai catatan klinis pada transaksi.
  • Kas: bruto, kembalian, buku kas, dan selisih penutupan tercatat terpisah.

Ketahanan

  • Sumber kebenaran lokal; jaringan bersifat tambahan.
  • Pengiriman ulang idempoten berbasis id lokal.
  • Draft menahan keranjang yang belum selesai, termasuk racikan utuh.
  • Mode debug membuka audit sinkron tanpa perlu alat luar.

Peta jalan

Urutan yang dipilih mengikuti risiko: keselamatan dan ketelitian stok lebih dulu, otomatisasi menyusul.

Fase 1 · selesai
Kasir yang aman

Interaksi obat, gerbang jenis penjualan, paket, racikan, stok atom, shift & kas, antrean pesanan tiga sumber, audit sinkron.

Fase 3
Gudang & kedaluwarsa

Stok opname dengan penghitungan strip terbuka, batch & tanggal kedaluwarsa, peringatan stok menipis, usulan pemesanan.

Fase 4
Percakapan dua arah

Konfirmasi pesanan WA (terima/tolak), pengingat tebus ulang obat rutin, riwayat pembelian per pasien.

Fase 5
Banyak cabang

Sinkron antar cabang, transfer stok, laporan gabungan, dan peran pengawas dengan tampilan ringkas.

Catatan untuk halaman pendarat. Empat demo interaktif di dokumen ini — blister stok, pemeriksa interaksi, gerbang penjualan, dan kembalian — dirancang agar bisa dipindahkan apa adanya ke halaman pemasaran. Masing-masing berdiri sendiri, tidak butuh data server, dan menjelaskan satu nilai jual dalam satu ketukan.