Files
2026-04-30 16:47:23 +07:00

400 lines
13 KiB
Markdown

# 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://<domain-server>/dashboard-files/
```
Checklist:
- Gunakan `https` (bukan `http`)
- Akhiri dengan slash `/`
- Restart service setelah ubah `.env`
Perintah cepat:
```bash
ssh one@<server> "grep -n '^PDF_BASE_URL=' /home/one/project/cpone-dashboard/.env"
ssh one@<server> "systemctl --user restart cpone-dashboard"
ssh one@<server> "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.