# Deployment Guide — cpone-dashboard Dokumen ini mencatat semua yang dilakukan dari awal sampai app berjalan di server, lengkap dengan langkah untuk deploy ulang atau deploy ke server baru. --- ## Ringkasan Yang Dikerjakan ### Fitur yang diimplementasi | Fitur | File | |-------|------| | Result menu — list pasien + View PDF modal | `menu/result/query.go`, `menu/result/handler.go`, `templates/result/index.html` | | PDF base URL via env | `config/config.go`, `.env`, `main.go` | | BASE_PATH — akses via sub-path tanpa port | `config/config.go`, semua handler, semua template | | Login path `/mcu-login` (hindari konflik Apache) | `menu/auth/route.go`, `menu/auth/handler.go`, `menu/auth/middleware.go`, `templates/login/index.html` | | Demo data seed (1500 pasien MCU DEMO 2026) | `scripts/demo_seed.py` | | Live simulation script | `scripts/demo_live.sh` | | Deploy ke devcpone via systemd user service | `Makefile`, `.config/systemd/user/cpone-dashboard.service` | ### Perubahan kode ``` config/config.go → tambah PDFBaseURL + BasePath field .env / .env.example → tambah PDF_BASE_URL + BASE_PATH main.go → b() template func, mount routes kondisional, SetBasePath ke semua package menu/auth/route.go → /login → /mcu-login menu/auth/handler.go → SetBasePath, redirect pakai basePath menu/auth/middleware.go → redirect ke basePath+/mcu-login menu/result/query.go → full implementation (ResultRow, GetResultRows, filter) menu/result/handler.go → full implementation (pageData, Index, SetPDFBaseURL, SetBasePath) menu/dashboard/handler.go → SetBasePath, redirect pakai basePath menu/arrival/handler.go → SetBasePath, redirect pakai basePath menu/progress/handler.go → SetBasePath, redirect pakai basePath menu/abnormal/handler.go → SetBasePath, redirect pakai basePath menu/projects/handler.go → SetBasePath, redirect pakai basePath templates/layout/base.html → semua nav link pakai {{b "/..."}} templates/login/index.html → src + action pakai {{b "/..."}} templates/auth/password.html → semua link pakai {{b "/..."}} templates/projects/index.html → semua link pakai {{b "/..."}} templates/dashboard/index.html → sse-connect, form action, fetch() pakai {{b "/..."}} templates/arrival/index.html → link + form action pakai {{b "/..."}} templates/progress/index.html → link + form action pakai {{b "/..."}} templates/abnormal/index.html → tab links pakai {{b "/..."}} templates/result/index.html → full template (4 section + PDF modal dialog) scripts/demo_seed.py → generate 1500 pasien demo + kelainan + published scripts/demo_live.sh → simulasi live MCU (checkin, station, validasi, publish) scripts/demo_cleanup.sql → hapus semua data demo scripts/README.md → panduan penggunaan demo scripts Makefile → update deploy target (systemd), tambah logs + status ``` --- ## Arsitektur ``` ┌─────────────────────────────────────────────────────────┐ │ devcpone server │ │ │ │ cpone-dashboard (Go binary, port 8090) │ │ │ │ │ └── MySQL 3306 → cpone_dashboard (DB utama) │ │ ├── mcu_project │ │ ├── mcu_patient │ │ ├── mcu_checkinout │ │ ├── mcu_station_progress │ │ ├── mcu_patient_resume_status │ │ ├── published_mcu_dashboard_sync │ │ ├── kelainan_details │ │ └── ... (lihat db/migrations/) │ │ │ │ /home/one/project/one/dashboard-files/ ← file PDF │ └─────────────────────────────────────────────────────────┘ Di laptop (dev): DB diakses via SSH tunnel → localhost:3307 → devcpone:3306 make start (buka tunnel + jalankan app lokal) ``` **Tech stack:** Go 1.21, Chi router, HTML templates (embed), HTMX, Tailwind CDN, ECharts CDN, MySQL 8 --- ## Prerequisites ### Di laptop (build) - Go 1.21+ (`/usr/local/go/bin/go`) - SSH access ke `one@devcpone.aplikasi.web.id` - Python 3 (untuk generate demo data) ### Di server tujuan - Ubuntu/Linux x86_64 - MySQL 8 dengan database `cpone_dashboard` sudah ada dan migration sudah dijalankan - Systemd user service tersedia (`systemctl --user`) - User dengan akses ke MySQL (`admin:password@127.0.0.1:3306`) - Direktori untuk file PDF: `/path/to/dashboard-files/` bisa diakses via HTTP --- ## Deploy Pertama Kali (Server Baru) ### 1. Persiapan database Pastikan database `cpone_dashboard` sudah ada dan semua migration dijalankan: ```bash ssh user@server "mysql -u admin -pPASSWORD -e 'SHOW DATABASES;'" ``` Jalankan migration satu per satu jika belum: ```bash ssh user@server "mysql -u admin -pPASSWORD cpone_dashboard < /path/migration/001_init_schema.sql" # dst untuk 002 - 011 ``` Migration ada di: `db/migrations/001_init_schema.sql` sampai `011_patient_resume_status.sql` ### 2. Buat direktori deploy di server ```bash ssh user@server "mkdir -p /home/user/project/cpone-dashboard" ``` ### 3. Buat file .env di server ```bash ssh user@server "cat > /home/user/project/cpone-dashboard/.env << 'EOF' APP_PORT=8090 DB_DSN=admin:PASSWORD@tcp(127.0.0.1:3306)/cpone_dashboard?parseTime=true&loc=Local AUTH_SECRET=ganti-dengan-string-random-32-karakter PDF_BASE_URL=http://domain-server/dashboard-files/ EOF" ``` Sesuaikan: - `APP_PORT` — port yang belum dipakai di server (cek dengan `ss -tlnp`) - `DB_DSN` — sesuaikan host, port, user, password, nama database - `AUTH_SECRET` — string random minimal 32 karakter, bisa generate: `openssl rand -hex 32` - `PDF_BASE_URL` — URL publik ke folder tempat file PDF disimpan ### 4. Buat systemd user service ```bash ssh user@server "mkdir -p ~/.config/systemd/user && cat > ~/.config/systemd/user/cpone-dashboard.service << 'EOF' [Unit] Description=CpOne Dashboard ConditionPathExists=/home/user/project/cpone-dashboard/cpone-dashboard After=network.target StartLimitIntervalSec=60 [Service] Type=simple Restart=on-failure RestartSec=10 WorkingDirectory=/home/user/project/cpone-dashboard ExecStart=/home/user/project/cpone-dashboard/cpone-dashboard EnvironmentFile=/home/user/project/cpone-dashboard/.env [Install] WantedBy=default.target EOF" ``` Ganti `/home/user` dengan home directory user yang dipakai. ### 5. Update Makefile untuk server baru Edit bagian atas `Makefile`: ```makefile SERVER=user@server-baru.domain.com DEPLOY_DIR=/home/user/project/cpone-dashboard ``` ### 6. Build dan deploy ```bash cd /path/to/cpone-dashboard make deploy ``` Perintah ini: 1. Cross-compile binary untuk linux/amd64 2. Upload ke server via SCP 3. Restart systemd service ### 7. Enable service agar auto-start saat reboot ```bash ssh user@server "systemctl --user enable cpone-dashboard" ``` ### 8. Verifikasi ```bash make status # cek status service make logs # lihat log live # Atau langsung dari browser: # http://server-domain:PORT ``` --- ## Deploy Ulang (Update Kode) Cukup jalankan: ```bash cd /Users/fajrihardhitamurti/REPO_CPONE_DASHBOARD/cpone-dashboard make deploy ``` Itu saja. Build → upload → restart otomatis. --- ## Development Lokal ```bash cd /Users/fajrihardhitamurti/REPO_CPONE_DASHBOARD/cpone-dashboard # Jalankan (buka SSH tunnel ke devcpone:3306 → localhost:3307, lalu start app) make start # Stop (tutup tunnel + kill app) make stop # Akses di browser: http://localhost:8080 ``` File `.env` lokal menggunakan: ``` DB_DSN=...@tcp(127.0.0.1:3307)/cpone_dashboard... ← via tunnel port 3307 APP_PORT=8080 PDF_BASE_URL=http://devcpone.aplikasi.web.id/dashboard-files/ ``` --- ## Konfigurasi .env | Key | Keterangan | Contoh | |-----|-----------|--------| | `APP_PORT` | Port HTTP server | `8090` | | `DB_DSN` | MySQL DSN (Go format) | `user:pass@tcp(host:3306)/dbname?parseTime=true&loc=Local` | | `AUTH_SECRET` | Secret untuk session cookie JWT | string random 32+ karakter | | `PDF_BASE_URL` | Base URL untuk file PDF resume individu | `http://domain/dashboard-files/` | `PDF_BASE_URL` harus diakhiri `/`. File PDF disimpan di server dengan path relatif misal `2026/04/R2604xxxx_resume_individu.pdf`, sehingga full URL = `PDF_BASE_URL + relative_path`. --- ## Struktur File di Server ``` /home/one/project/cpone-dashboard/ ├── cpone-dashboard ← binary (hasil build) └── .env ← konfigurasi (jangan commit ke git) /home/one/.config/systemd/user/ └── cpone-dashboard.service ← systemd unit file /home/one/project/one/dashboard-files/ └── 2026/ └── 04/ └── R2604xxxx_resume_individu.pdf ← file PDF hasil MCU ``` --- ## Troubleshooting **Service gagal start:** ```bash journalctl --user -u cpone-dashboard -n 30 --no-pager ``` **Port sudah dipakai:** ```bash ss -tlnp | grep PORT # Ganti APP_PORT di .env, lalu restart systemctl --user restart cpone-dashboard ``` **Terlalu banyak restart (failed state):** ```bash systemctl --user stop cpone-dashboard systemctl --user reset-failed cpone-dashboard systemctl --user start cpone-dashboard ``` **Database tidak bisa connect:** - Pastikan `DB_DSN` di `.env` benar - Cek MySQL berjalan: `mysql -u admin -pPASS -e "SELECT 1;"` - Kalau pakai tunnel (dev lokal): pastikan tunnel aktif **Binary tidak update:** ```bash # Cek binary sudah ter-upload ssh one@devcpone.aplikasi.web.id "ls -lh /home/one/project/cpone-dashboard/cpone-dashboard" # Force build ulang cd /path/to/repo && make deploy ``` --- ## Demo Data (Opsional) Untuk demo ke client dengan data realistis (MCU PROJECT DEMO 2026, 1500 pasien): ```bash # Seed data python3 scripts/demo_seed.py | ssh one@devcpone.aplikasi.web.id \ "mysql -u admin -pSasone\!102938 cpone_dashboard" # Buat PDF demo di server ssh one@devcpone.aplikasi.web.id " mkdir -p /home/one/project/one/dashboard-files/2026/04 SRC=/home/one/project/one/dashboard-files/2024/09/R2409170003_resume_individu.pdf for i in \$(seq 1 80); do cp \"\$SRC\" \"/home/one/project/one/dashboard-files/2026/04/R2604\$(printf '%04d' \$i)_resume_individu.pdf\" done " # Upload live script scp scripts/demo_live.sh one@devcpone.aplikasi.web.id:/home/one/demo_live.sh ssh one@devcpone.aplikasi.web.id "chmod +x /home/one/demo_live.sh" # Jalankan simulasi live saat demo ssh one@devcpone.aplikasi.web.id "/home/one/demo_live.sh 5" ``` Detail lengkap lihat `scripts/README.md`. --- ## Catatan Deploy 2026-04-30 (devcpone) Perubahan yang dideploy: - Commit: `00389df` - Scope: SSE highlight per-baris (bukan per-section) untuk `Station Status` + `Arrival List`, plus audio `pluk`. Hasil: - `git push origin main` sukses. - Service `cpone-dashboard` di `devcpone` berhasil restart dan status `active (running)`. Kendala yang terjadi: - `make deploy` gagal di step `scp` dengan error: - `dest open "/home/one/project/cpone-dashboard/cpone-dashboard": Failure` Workaround yang dipakai (sukses): ```bash cd /Users/fajrihardhitamurti/REPO_CPONE_DASHBOARD/cpone-dashboard env GOCACHE=/tmp/cpone-gocache make build scp cpone-dashboard-linux one@devcpone.aplikasi.web.id:/tmp/cpone-dashboard-linux ssh one@devcpone.aplikasi.web.id ' mv /tmp/cpone-dashboard-linux /home/one/project/cpone-dashboard/cpone-dashboard && chmod +x /home/one/project/cpone-dashboard/cpone-dashboard && systemctl --user restart cpone-dashboard && systemctl --user --no-pager --full status cpone-dashboard | sed -n "1,18p" ' ``` Catatan tambahan: - Di mesin lokal ini, build Go lebih stabil pakai `GOCACHE=/tmp/cpone-gocache`. ### Tambahan penting: PDF modal kosong di HTTPS (mixed content) Gejala: - Klik `View PDF` di modal terlihat kosong, tetapi link `Buka di tab baru` bisa dibuka. Penyebab: - Aplikasi dibuka via `https://...` tetapi `PDF_BASE_URL` masih `http://...`. - Browser memblokir `http` di dalam `iframe` halaman HTTPS. Setelan yang wajib di server: ```env PDF_BASE_URL=https:///dashboard-files/ ``` Checklist: - Gunakan `https` (bukan `http`) - Akhiri dengan slash `/` - Restart service setelah ubah `.env` Perintah cepat: ```bash ssh one@ "grep -n '^PDF_BASE_URL=' /home/one/project/cpone-dashboard/.env" ssh one@ "systemctl --user restart cpone-dashboard" ssh one@ "systemctl --user --no-pager --full status cpone-dashboard | sed -n '1,14p'" ``` Catatan implementasi: - Frontend sekarang punya fallback: jika halaman HTTPS dan URL PDF HTTP, URL akan di-upgrade ke HTTPS sebelum dimuat ke iframe. - Tetap disarankan set `PDF_BASE_URL` benar di `.env` tiap server agar konsisten.