Skip to content
Software Modules Programming

Signing Platform Web App

By Romi Fadli, S.Kom. 10 min read Software Design
On this page
A memory chip holding a key, circled by refresh arrows, beside a browser window where a signature stamp is being dragged into place on a PDF page

Signing Platform Web App adalah aplikasi browser dari platform penandatanganan dokumen: tempat orang login, membuktikan identitasnya, menaruh stempel di PDF lalu menandatanganinya, mengelola sertifikatnya, dan menyetujui sistem yang menandatangani atas nama mereka — serta tempat administrator menjalankan organisasi, user, peninjau, dan sistem client. Ia single-page application berbahasa Vue dan TypeScript yang berbicara dengan satu backend, yaitu core API platform, dan menjaga seseorang tetap login tanpa pernah menyimpan access token-nya di tempat yang bisa ditemukan script belakangan.

Saya membangunnya sebagai pasangan inti: inti memegang aturan dan data, dan aplikasi ini mengubahnya menjadi layar. Sebagian besar keputusan di dalamnya menyangkut dua urusan yang tak boleh keliru di produk penandatanganan — menjaga sesi tetap aman tanpa membuat orang login berulang-ulang, dan menaruh stempel persis di tempat yang dilihat penanda tangan.

Sekilas

Bahasa & frameworkTypeScript, dengan Vue 3, Pinia, vue-router, vue-i18n, Tailwind CSS, dan Vite; pdf.js untuk dokumen
ArsitekturFeature-Based Frontend Architecture
Versi2.13.2
StatusStabil, berjalan di production
BentukSingle-page application yang dilayani di path-nya sendiri, di samping halaman beranda publik yang dirender di server
Kode sumberPrivat
Apa module ini dan bagaimana keadaannya.

Yang dikerjakannya

A. Menandatangani dokumen di browser

Dokumen di-upload langsung ke storage lewat link berumur pendek dan diberi penanda tangan dalam tahap berurutan. Penanda tangan membukanya di PDF viewer dengan render beresolusi tinggi, zoom, dan dukungan sentuh, menyeret dan mengubah ukuran stempelnya di halaman, memilih sertifikat, mengisi alasan, lokasi, dan passphrase-nya, lalu menandatangani. Satu halaman publik memverifikasi PDF bertanda tangan apa pun yang diseret, ditempel, atau dipilih dari disk.

B. Menjaga orang tetap login, dengan aman

Sesi bertahan melewati reload dan access token yang kedaluwarsa tanpa meminta password lagi, dan tanpa token itu pernah ditulis ke storage browser. Login bisa dengan password, lewat identity provider eksternal, dengan autentikasi dua faktor, dan dengan perlindungan bot yang tak terlihat.

C. Membuktikan identitas

Sebelum seseorang boleh memegang sertifikat tanda tangan, ia mengirim data pribadinya dan dua foto, lalu menyelesaikan tantangan wajah langsung yang tertanam di halaman. Kartu status dan banner memberi tahu sampai di mana verifikasinya, dan mengingatkan paling banyak sekali per sesi.

D. Mengelola stempel dan sertifikat

Penanda tangan menggambar atau meng-upload gambar tanda tangannya atau membuat stempel QR, mengajukan sertifikat yang dilindungi passphrase miliknya sendiri, dan melihat status tiap sertifikat. Konflik, misalnya sertifikat yang sudah ada, dijelaskan di dialog khusus, bukan sekadar error polos.

E. Menyetujui sistem yang menandatangani lewatnya

Ketika sistem client ingin bertindak atas nama seorang user, user itu melihat persis sistem mana dan izin apa, lalu mengizinkan atau menolak di dialog persetujuan. Sistem client juga bisa mengirim user langsung ke dokumen yang harus ditandatangani dan menerimanya kembali setelah selesai. User bisa melihat dan mencabut setiap sistem yang tertaut ke akunnya.

F. Menjalankan platform bagi administrator

Administrator mendapat dashboard yang disesuaikan dengan role-nya, dan mengelola organisasi beserta unitnya, anggota dan allowlist e-mail hingga seribu alamat, user, peninjau identitas, account manager, sertifikat, dan sistem client. Tindakan yang merusak atau berhak istimewa meminta password administrator sekali lagi.

Antarmuka

BidangYang bisa dilakukan orang di sana
Loginlogin, mendaftar, verifikasi e-mail, reset password, memakai provider eksternal, menyelesaikan dua faktor
Dokumenupload, menambah penanda tangan bertahap, menaruh stempel, menandatangani, mengunduh file bertanda tangan
Verifikasimemeriksa PDF bertanda tangan apa pun, tanpa akun
Profildata pribadi, password, dua faktor, verifikasi identitas
Stempel dan sertifikatgambar tanda tangan, stempel QR, pengajuan dan status sertifikat
Clientmemberi persetujuan ke sistem client, meninjau dan mencabutnya
Administrasidashboard, organisasi, user, peninjau, sertifikat, sistem client — di layar desktop
Bidang-bidang aplikasi; tiap route baru dimuat saat pertama dikunjungi.

Standar

StandarYang dijaminnya di sini
OAuth 2.0 dan OpenID Connect dengan PKCE (RFC 7636)login lewat provider eksternal tanpa client secret di browser, dengan pemeriksaan state, nonce, dan issuer
JSON Web Tokenaccess token berumur pendek yang hanya disimpan di memori dan diperbarui diam-diam
TOTP (RFC 6238)autentikasi dua faktor dengan aplikasi authenticator apa pun, disiapkan dari kode QR
PDF, dirender dengan pdf.jsdokumen ditampilkan persis seperti yang akan ditandatangani, dengan posisi stempel dikonversi ke koordinat PDF
Pesan antar-jendela (postMessage)tantangan wajah yang tertanam melaporkan hasilnya ke halaman yang membukanya
TypeScript ketatsetiap build memeriksa tipe seluruh aplikasi sebelum menghasilkannya
Standar yang dipatuhi aplikasi, dan yang dijamin masing-masing.

Di dalamnya

Aplikasi ini mengikuti Feature-Based Frontend Architecture: tiap fitur — login, dokumen, profil, stempel, sertifikat, client, dashboard, administrasi — punya view, component, dan composable miliknya sendiri, dan fitur tak pernah saling meng-import. Component tak pernah memanggil jaringan sendiri; setiap request lewat satu lapisan service dengan satu HTTP client, dan state sesi serta antarmuka tinggal di beberapa store bersama. Tampilan visualnya berasal dari paket design system terpisah di balik satu alias, jadi seluruh tampilan bisa ditukar tanpa menyentuh satu fitur pun.

Keputusan rancangan

Access token tinggal di memori dan tidak di tempat lain. Saya menyimpan sesi di memori, di dalam store Pinia, dan membiarkan credential refresh yang tak bisa dibaca script mana pun membawanya melewati reload. Saat aplikasi start, ia meminta token baru bahkan sebelum router dipasang, jadi reload mengembalikan orang ke tempatnya semula dalam keadaan login, dan refresh yang gagal cukup membuatnya mulai dalam keadaan logout.

Satu refresh, berapa pun request yang gagal bersamaan. Access token berumur pendek, jadi beberapa request sering mendapati token kedaluwarsa pada saat yang sama. HTTP client menangkap jawaban unauthorized pertama, memulai satu refresh, dan memarkir setiap request gagal lainnya di antrean; begitu token baru tiba, tiap request di antrean diulang dengan token itu. Satu versi awal mengulang request di antrean dengan header basi yang sudah mereka simpan, dan gagal lagi; kini token baru diserahkan ke masing-masing secara eksplisit. Bila refresh-nya sendiri gagal, sesi dibersihkan dan orang itu dibawa ke halaman login.

Login eksternal mengikuti spesifikasi sampai ke byte-nya. Login lewat provider eksternal memakai PKCE dengan verifier yang dibuat dari byte acak dan di-encode dalam base64 aman-URL. Versi pertama saya memakai base64 biasa, yang ditolak identity provider yang ketat sebagai code verifier tak sah. State dan nonce dibuat acak, issuer diperiksa saat kembali untuk mencegah kekeliruan provider, dan setiap nilai sementara dibersihkan begitu pertukarannya berhasil atau gagal.

Stempel mendarat persis di tempat penanda tangan menaruhnya. Viewer menggambar halaman pada kepadatan piksel layar yang sebenarnya, sehingga stempel yang ditaruh di layar tajam tak bergeser akibat skala antara piksel layar dan piksel kanvas — bug yang saya perbaiki sejak awal. Ketika penanda tangan mengonfirmasi, kotak stempel dikonversi dari koordinat layar, diukur dari kiri-atas dalam piksel, ke koordinat PDF, diukur dari kiri-bawah dalam point, bersama nomor halamannya, memakai konversi milik viewer itu sendiri. Stempel menjaga proporsinya saat diubah ukurannya, dan pratinjau stempel diletakkan di atas putih murni, karena latar kotak-kotak menyembunyikan tanda tangan yang digambar dengan pena.

Persetujuan dan serah-terima lewat redirect, bukan lewat penyematan. Sistem client dulu menyematkan halaman tanda tangan di dalam frame. Saya menggantinya dengan redirect: client mengirim user ke aplikasi dengan token sekali pakai, user memberi persetujuan atau menandatangani di dalam aplikasi yang sudah dipercayainya, lalu dikirim kembali ke client dengan state aslinya dan hasilnya. Persetujuan pindah dari halaman penuh ke dialog di layar client, tempat user juga melihat setiap sistem yang sudah tertaut kepadanya.

Design system berupa paket, bukan folder style. Aplikasi ini dibangun ulang secara bertahap menjadi module per fitur di atas paket design system yang terpisah. Paket itu dirujuk lewat alias, dan mengarahkan alias ke build tema lain mengganti tampilan seluruh aplikasi — sudah diuji dengan melakukannya persis seperti itu. Saya sempat memakainya sebagai git submodule lalu kembali ke salinan hasil kompilasi yang disimpan di repository, supaya source tema tetap privat.

Setiap label mengikuti bahasa yang aktif. Semua teks antarmuka pindah ke file terjemahan dalam sepuluh langkah yang terukur. Definisi kolom dan navigasi yang dulu dibuat sekali saat start diubah menjadi nilai computed, karena kalau tidak, labelnya membeku dalam bahasa apa pun yang aktif saat aplikasi boot. Satu script mencocokkan setiap key yang dipakai di kode dengan file terjemahan, karena sistem tipe tak bisa melakukannya. Satu suntingan massal menghasilkan binding cacat yang diam-diam menyembunyikan tombol satu dialog — tombol kirim identitas lenyap — dan baik pemeriksaan tipe maupun build tak menangkapnya, jadi pola itu kini dicari secara eksplisit. Teks yang berakhir di dalam PDF bertanda tangan, seperti kata-kata stempel, sengaja tak diterjemahkan: ia menjadi bagian dari dokumen permanen.

Bundle browser hanya menerima yang memang untuknya. Hanya variabel berawalan publik milik aplikasi yang sampai ke bundle; masing-masing diberi tipe dan dinormalkan di satu module konfigurasi.

Setiap layar tahu tempatnya. Halaman beranda publik pindah keluar dari aplikasi ini ke inti yang dirender di server, supaya mesin pencari bisa mengindeksnya, dan aplikasi kini tinggal di path-nya sendiri. Tiap route baru dimuat saat dikunjungi. Bagian administrasi ditujukan untuk layar desktop dan menyatakannya di layar yang lebih kecil, sementara layar penandatanganan dibangun untuk sentuhan, dengan navigasi bawah dan ruang untuk safe area ponsel. Kolom pencarian memakai satu input debounced bersama yang tak pernah kehilangan fokus selagi hasil dimuat.

Tak ada jawaban yang membocorkan apa yang ada. Reset password dan e-mail verifikasi selalu menampilkan pesan yang sama, entah akunnya ada atau tidak, dan tautan yang datang lewat e-mail diperiksa terhadap origin API sendiri sebelum diikuti aplikasi.

Spesifikasi

Berbicara denganSatu backend — core API platform — dengan credential disertakan untuk pembaruan sesi; file langsung ke storage lewat link berumur pendek
SesiAccess token hanya di memori; refresh senyap saat start; satu refresh berantrean untuk kegagalan bersamaan
LoginPassword, provider eksternal dengan PKCE, dua faktor dengan kode pemulihan, perlindungan bot tak terlihat
DokumenPDF hingga 50 MB; penanda tangan dalam tahap berurutan; penempatan stempel dikonversi ke koordinat PDF
AntarmukaTema gelap dan terang; layar penandatanganan ramah sentuhan; administrasi di desktop; terjemahan dengan pencocokan key
BuildVite dengan pemeriksaan tipe TypeScript ketat di setiap build; route dipecah per halaman
Yang dibutuhkan, dipegang, dan diberikan aplikasi.

Terkait

Core API di balik setiap layar: token, data, dan aturan platform.

Tantangan wajah yang tertanam di form verifikasi identitas.

Signer yang menghasilkan tanda tangan PDF jangka panjang yang ditempatkan, diunduh, dan diverifikasi aplikasi ini.

Istilah

Single-page application
Aplikasi web yang dimuat sekali lalu mengganti layarnya di dalam browser, hanya meminta data ke server.
Refresh token
Credential berumur panjang yang hanya dipakai untuk mendapatkan access token baru yang berumur pendek, di sini disimpan di tempat yang tak bisa dibaca script mana pun.
Interceptor
Kode yang melihat setiap request atau response dari HTTP client dan bisa mengubah, mengulang, atau menolaknya.
PKCE
Proof Key for Code Exchange: rahasia sekali pakai yang membuktikan bahwa aplikasi yang menuntaskan login adalah aplikasi yang memulainya.
Design system
Kumpulan style dan component bersama yang memberi setiap layar tampilan dan perilaku yang sama.

Technologies covered

  • TypeScript
  • Pinia
  • Vite
  • Vue
  • OAuth 2.0

About the author

Photo of Romi Fadli

Romi Fadli, S.Kom.

Solution Architect · Backend Engineer · Embedded Systems

In my day job I work as a solution architect. I design the system, lead the team that builds it — quality assurance, backend developers, a UI developer, DevOps and DevSecOps — and write the most critical modules myself, such as a certificate authority, a long-term PDF signer, and the core API of a personnel system.

I work across the whole stack that a running system actually needs. On the hardware side that means PCB design, microcontrollers, and embedded firmware — including RISC-V boards running FreeRTOS and Embassy, speaking MQTT over mutually authenticated TLS on a microcontroller with 64 KB of SRAM.

Most of my day-to-day work is software: Rust backends and API modules built on Clean Architecture, an OAuth2/OpenID Connect authorization server written from scratch, PAdES document signing, and certificate authorities — root CAs, timestamping authorities, and OCSP responders. I also build the frontends that sit on top of them.

Running all of that means infrastructure: Docker Compose stacks, networking, Mikrotik and RADIUS, observability with OpenTelemetry, and a steady habit of writing command-line tools and utilities for Linux when the existing ones do not fit.

Share

Enjoyed this?

Get an email when a new article is published.

Referenced by

A purple root circle linked to a blue and an orange intermediate circle, which lead to a signed document with a green seal and to a clock.

Aurograf

DevOps

Platform tanda tangan digital Pemerintah Kota Tangerang Selatan: penanda tangan membuktikan identitasnya, menandatangani PDF hingga PAdES B-LTA dengan sertifikat dari otoritas milik platform sendiri, dan siapa pun bisa memverifikasinya — versi 2, yang saya rancang, bangun, dan operasikan.

10 min read Read more →

Related Articles

A central core holding people, organisations, documents, and certificates, connected to eight surrounding services for storage, addresses, certificates, timestamps, the root, signing, thumbnails, and face challenges

Inti Laravel dari platform penandatanganan dokumen: memegang user, identitas, organisasi, sistem client, dokumen beserta versi bertanda tangannya, stempel, dan sertifikat, serta mengorkestrasi service yang menandatangani, menstempel waktu, merender, dan menyimpan — tanpa pernah memegang file.

9 min read Read more →
A signed PDF with a QR stamp, wrapped in four nested frames for the signature, its timestamp, the embedded validation data, and the archive timestamp

Service Python yang menandatangani PDF sampai PAdES B-LTA dengan stempel yang terlihat — menanamkan stempel waktu, sertifikat, dan bukti pencabutan, lalu stempel waktu arsip — supaya tanda tangan tetap bisa diverifikasi lama setelah sertifikatnya kedaluwarsa, dan memverifikasi PDF bertanda tangan.

10 min read Read more →
A document's fingerprint passing through a clock, signed by a certificate below it, and returning as a time seal stamped on the same document

Timestamp authority berbahasa Rust yang menstempel hash dokumen dengan waktu bertanda tangan berbasis NTP sesuai RFC 3161, supaya tanda tangan PDF tetap bisa diverifikasi setelah sertifikatnya kedaluwarsa — menerbitkan sendiri sertifikat penanda tangannya, dengan OCSP dan CRL publik.

9 min read Read more →