# Local build deployment (temporary — CI bypass) GitHub Actions untuk org ini sedang terblokir (spending limit), jadi image `ghcr.io/tarulab/*:latest` tidak ikut berubah. Panduan ini membangun image **di VPS langsung dari repo checkout** lewat compose override `docker-compose.localbuild.yml` — tanpa mengubah `docker-compose.yml` dan tanpa mengubah alur rollback. ## Prasyarat di VPS - Keempat repo ada di satu induk, default override mengasumsikan susunan ini (beda susunan? set `BACKEND_DIR`/`B2B_DIR`/`ERP_DIR`/`POS_DIR`): ``` ~/keluargamart/keluargamart-backend <- compose dijalankan dari sini ~/keluargamart/keluargamart-b2b-frontend ~/keluargamart/keluargamart-erp-frontend ~/keluargamart/keluargamart-pos-frontend ``` - **Tarik kode terbaru dulu di KEEMPAT repo** (`git pull`), karena image dibangun dari working copy masing-masing. - Docker dengan BuildKit (default pada versi modern; `docker compose version` ≥ v2.20 aman). ## PENTING — `PGDATA_DIR` dan `UPLOADS_DIR` harus diisi `.env` **wajib** memuat dua baris ini, dengan path absolut ke direktori yang memang dipakai stack production: ```bash PGDATA_DIR=/opt/stacks/keluargamart-backend/data/postgres UPLOADS_DIR=/opt/stacks/keluargamart-backend/data/uploads ``` Kalau tidak diisi, compose jatuh ke default `./data/postgres` — direktori yang **berbeda** dari yang production pakai. `docker compose up` akan menyalakan Postgres yang tampak bersih: dia hidup, `/health` balas 200, tidak ada error — tapi datanya kosong, sementara data asli masih aman di `/opt/stacks/...` dan tidak dibaca siapa pun. Gejalanya hanya "row-nya hilang", dan itu baru ketahuan karena kebetulan dicek. Verified: DB salah itu balas 211 order / migrasi 108, padahal yang benar 215 / 109. `.env` sendiri gitignored, jadi baris ini tidak ikut ter-commit — makanya `deploy/LOCAL-BUILD.md` ini yang menjadi pencatatannya. Cek cepat sebelum deploy: ```bash docker compose -f docker-compose.yml -f docker-compose.localbuild.yml config \ | grep -A2 'source:.*postgres' # harus /opt/stacks/..., bukan ./data/postgres ``` ## Catatan: `up` tidak selalu dipakai di mesin ini Di host yang berjalan dengan podman socket, `docker compose ... up -d ` sering gagal dengan: ``` container name "keluargamart-postgres" is already in use by ``` Compose v2 tidak mengenali container yang dibuat di luar label-nya (misalnya dibuat manual lewat `podman run`, atau dari `podman-compose` yang lebih lawas), jadi ia mencoba membuat ulang dan nabrak. Build + `podman run` manual dengan flag yang sama seperti `compose.yaml` jadi jalur yang andal; `docker compose build` sendiri tetap dipakai untuk build image. Yang penting: **jangan** hapus container postgres/redis yang sedang jalan hanya agar `up` mau berhasil — itu justru sumber kehilangan akses ke PGDATA. ## PERINGATAN KEDUA — `data/postgres` yang stale Sekali `up` sempat me-recreate postgres memakai default `./data/postgres`, terbentuk direktori PGDATA **lama** berisi 211 order (snapshot sebelum data production pindah). Direktori itu masih ada di `data/postgres/` dan **berisi data yang salah** — dan karena `.env` sekarang mengarahkan ke `/opt/stacks`, compose tidak akan menyentuhnya lagi. Kenapa ini penting: kalau `PGDATA_DIR` pernah kosongkan lagi (mis. `.env` di-overwrite, atau deploy dari mesin tanpa file itu), compose akan diam-diam kembali ke `./data/postgres` dan menyajikan 211 order yang basi sebagai kalau benar. Itu lebih berbahaya daripada DB kosong, karena tidak ada yang gagal. Setelah data production dipulihkan, hapus direktori basi itu: ```bash rm -rf data/postgres # HANYA setelah PGDATA_DIR terverifikasi & DB hidup ``` Sudah dilakukan di mesin ini, tapi dicatat di sini supaya tidak ada yang mengRestore-nya tanpa sengaja. Double-check sebelum hapus: ```bash docker compose ... config | grep source.*postgres # harus /opt/stacks/... docker compose ... exec postgres psql -U erp -d erp -c 'SELECT count(*) FROM sales_orders' ``` ## Build + deploy Dari root repo **backend**: ```bash # 1. Bangun keempat image secara lokal (backend, b2b, erp, pos) docker compose -f docker-compose.yml -f docker-compose.localbuild.yml \ build backend b2b erp pos # 2. Naikkan stack dengan konfigurasi yang sama docker compose -f docker-compose.yml -f docker-compose.localbuild.yml up -d ``` Migrasi DB tetap otomatis: container backend menjalankan `migrations/*.sql` yang dibawa image saat boot (`AUTO_MIGRATE=true` default), sama seperti sebelumnya — tidak ada langkah tambahan. Hanya sebagian service? Sebutkan namanya: ```bash docker compose -f docker-compose.yml -f docker-compose.localbuild.yml build backend docker compose -f docker-compose.yml -f docker-compose.localbuild.yml up -d backend ``` ## Verifikasi ```bash docker compose ps # semua Up/healthy docker inspect keluargamart-backend --format '{{.Image}}' | cut -c8-19 docker images | grep keluargamart # tag _*> baru curl -sf https://api-km.trl.my.id/health # backend OK ``` Cek fitur yang barusan diperbaiki (contoh: kolom Kas Masuk di POS > Shifts, konfirmasi terima barang di B2B). ## Kembali ke image CI (setelah org diaktifkan ulang) ```bash git pull # pastikan komit lokal masuk main docker compose -f docker-compose.yml pull # tarik ghcr.io:latest terbaru docker compose -f docker-compose.yml up -d # tanpa -f override ``` `docker-compose.yml` tidak pernah diubah, jadi ini exactly alur lama. File override boleh dibiarkan di repo (tidak berefek tanpa flag `-f`), atau dihapus bersama dokumen ini saat CI normal. ## Catatan & jebakan - **Satu repo, satu sumber build.** Image dibangun dari *working copy*, bukan dari commit yang sudah dites CI. Jangan build dari tree dengan perubahan eksperimen yang belum di-commit — `git status` bersih dulu di tiap repo. - **Windows → VPS:** pastikan tidak ada file yang berubah line ending saat disalin. Untuk backend, `atlas.sum` peka CRLF (lihat catatan di workflow CI). Clone langsung di VPS lebih aman daripada rsync dari Windows. - **Tag ganda:** image lokal otomatis menimpa nama `keluargamart-backend` dll. di daemon VPS. `pull_policy: always` pada base file *tidak* berlaku saat override ini aktif (`pull_policy: build` menang), jadi stack tidak akan menimpa image lokal dengan ghcr.io di balik punggung. - **Rollback cepat** ke image production sebelumnya tetap lewat `deploy/ROLLBACK.md` — compose biasa tanpa override.