1
Ringkasan Proyek
Hydro adalah website internal untuk mencatat produk, stok per batch, pembelian pelanggan, pembayaran, retur, piutang, dan laporan pada perusahaan air minum kemasan. README.md:31
Repository ini terdiri atas tiga bagian: backend/ berisi Django 5.2 LTS dan Django REST Framework dengan aturan bisnis serta hak akses, frontend/ berisi Next.js statis dengan TypeScript, Tailwind, dan shadcn/ui, sedangkan deploy/ menyimpan Nginx, skrip rilis, backup, dan pemulihan. Di akar repository ada compose.yaml untuk mencoba aplikasi di komputer sendiri dan compose.prod.yaml untuk produksi dengan layanan web, api, dan db. README.md:5-112
Bentuk tumpukan
Tiga layanan Docker membentuk satu jalur tetap: browser masuk ke container web yang hanya berisi Nginx dan berkas statis hasil next build, container itu meneruskan /api/ ke container api yang menjalankan gunicorn di atas config.wsgi, lalu api menyimpan data ke db PostgreSQL dan berkas ke volume media. compose.yaml:3-463
graph TD
browser["Browser"] --> web["web: nginx-unprivileged 1.29-alpine"]
web --> api["api: gunicorn config.wsgi"]
api --> django["Django 5.2.18 + DRF 3.18.3"]
api --> media["volume media"]
django --> db["db: postgres:18.1"]
style browser fill:#8b5cf6,color:#fff
style web fill:#f59e0b,color:#000
style api fill:#2d7d46,color:#fff
style django fill:#2d7d46,color:#fff
style db fill:#336791,color:#fff
style media fill:#336791,color:#fff
%% fig: Tumpukan layanan Hydro
%% desc: Browser masuk lewat web Nginx, diteruskan ke api gunicorn yang menjalankan Django, lalu data disimpan di Postgres dan berkas di volume media.Build web berlangsung dua tahap: tahap node:26-slim menjalankan npm ci lalu npm run build, dan image akhir hanya memuat Nginx serta hasil output: "export" dari Next.js, tanpa Node.js. deploy/web.Dockerfile:1-144 Mode ekspor statis itu hanya aktif ketika NODE_ENV bernilai production; saat development, next.config.ts justru memasang rewrites() yang meneruskan /api/:path* ke API_DEV yang bawaannya http://127.0.0.1:8000. frontend/next.config.ts:18-365
Image api dibangun dari python:3.13-slim-bookworm. Image itu memasang libpango dan libharfbuzz-subset0 untuk WeasyPrint, berjalan sebagai user 10001, dan menjalankan gunicorn dengan tiga worker serta --timeout 60. backend/Dockerfile:1-24
Pustaka utama
| Sisi | Pustaka | Versi |
|---|---|---|
| backend | Django | 5.2.18 |
| backend | djangorestframework | 3.18.3 |
| backend | django-allauth[mfa] | 65.21.1 |
| backend | drf-spectacular | 0.30.0 |
| backend | psycopg[binary] | 3.3.6 |
| backend | gunicorn | 26.2.0 |
| backend | weasyprint / openpyxl | 70.0 / 3.1.5 |
| frontend | next / react | 16.4.3 / 19.3.0 |
| frontend | @tanstack/react-query | ^5.105.0 |
| frontend | zod | ^4.6.7 |
Isi daftar di atas diambil langsung dari berkas kebutuhan backend. backend/requirements.txt:1-116
Berkas requirements-dev.txt menumpang di atas requirements.txt, lalu menambah pytest, pytest-django==4.14.0, ruff==0.17.3, mypy==2.4.1, django-stubs==6.1.2, djangorestframework-stubs==3.18.1, dan pyotp. backend/requirements-dev.txt:1-107
Di sisi frontend, package.json mendefinisikan lima script: dev, build, start, tipe-api, dan typecheck. Script tipe-api menjalankan openapi-typescript ../backend/schema.yaml -o src/lib/api-types.ts, sehingga tipe TypeScript diturunkan dari schema OpenAPI backend. frontend/package.json:5-118 Ketergantungan runtime yang tercatat antara lain @tanstack/react-table, recharts, react-hook-form, dan qrcode.react. frontend/package.json:12-329
Modul backend dan endpoint
config/settings.py mendaftarkan enam aplikasi lokal di INSTALLED_APPS: inti, akun, produk, stok, pembelian, dan laporan. Di daftar yang sama ada rest_framework, drf_spectacular, allauth, auditlog, dan axes. backend/config/settings.py:26-4510
Setiap modul memasang view-nya di config/urls.py. SimpleRouter menerima empat belas router.register, sedangkan laporan dan akun juga memasang view tunggal lewat urlpatterns. backend/config/urls.py:22-4711
| Modul | View | Terdaftar sebagai |
|---|---|---|
produk | KategoriViewSet, ProdukViewSet, SatuanViewSet, HargaViewSet | kategori, produk, satuan, harga |
stok | BatchViewSet, MutasiViewSet, BarangMasukViewSet, OpnameViewSet | batch, mutasi, barang-masuk, opname |
pembelian | PelangganViewSet, TransaksiViewSet, ReturViewSet | pelanggan, transaksi, retur |
akun | PenggunaViewSet, PeranViewSet, LogAktivitasViewSet, SesiView, kesehatan | pengguna, peran, log-aktivitas, api/auth/sesi/ |
laporan | DasborView, LaporanPenjualanView, LaporanTerlarisView, LaporanStokView, LaporanPiutangView | api/dasbor/, api/laporan/*/ |
graph TD
urls["config/urls.py"] --> produk["produk"]
urls --> stok["stok"]
urls --> pembelian["pembelian"]
urls --> akun["akun"]
urls --> laporan["laporan"]
settings["config/settings.py"] --> izin["inti.izin.PunyaIzin"]
izin --> akun
pembelian --> stok
stok --> db["PostgreSQL"]
style urls fill:#f59e0b,color:#000
style settings fill:#f59e0b,color:#000
style izin fill:#f59e0b,color:#000
style produk fill:#2d7d46,color:#fff
style stok fill:#2d7d46,color:#fff
style pembelian fill:#2d7d46,color:#fff
style akun fill:#2d7d46,color:#fff
style laporan fill:#8b5cf6,color:#fff
style db fill:#336791,color:#fff
%% fig: Ketergantungan modul backend
%% desc: config/urls.py memetakan setiap modul ke router, settings memasang PunyaIzin sebagai izin bawaan, dan pembelian membaca stok yang tersimpan di PostgreSQL.Izin dideklarasikan per view lewat atribut izin, dan inti/izin.py memetakan tiga peran bawaan ke himpunan izin: admin_penjualan mendapat lihat_produk dan kelola_transaksi, staf_gudang mendapat lihat_produk dan kelola_stok, sedangkan pemilik memegang seluruh SEMUA_IZIN. backend/inti/izin.py:31-3512
Aturan pencatatan yang berlaku menyeluruh
Lima aturan ini berlaku lintas modul, jadi perlu diketahui sebelum membaca halaman lain. Stok hanya berubah lewat ubah_stok() di backend/stok/layanan.py dan setiap perubahan menulis mutasi_stok. Stok disimpan dalam botol per batch, dan database menolak sisa minus lewat CHECK (sisa >= 0). Penjualan mengunci baris batch lalu mengambil batch kedaluwarsa terdekat secara FEFO, dan batch kedaluwarsa tidak ikut terjual. Harga serta total selalu dihitung di server sebelum disalin ke nota. Setiap view wajib mendeklarasikan izin, dan view tanpa deklarasi selalu ditolak. README.md:69-7513
Mencoba dengan satu perintah
Dengan Docker saja, docker compose up --build menyalakan ketiga layanan, menjalankan migrate --noinput dan isi_demo, lalu membuka aplikasi di http://localhost:8080. Akun contoh pemilik, admin, dan gudang memakai password hydro-demo-123, dan akun pemilik akan diminta mengaktifkan 2FA. compose.yaml:3-463
⚠️ Mode ini memakai password contoh dan tanpa HTTPS, jadi jangan dipakai untuk produksi.
docker compose down -vjuga menghapus volumepgdatabeserta seluruh datanya. README.md:13-2314
Langkah development memakai compose.dev.yaml dengan nama proyek hydro-dev, ditambah Python 3.13+, Node.js 26, dan manage.py isi_demo untuk mengisi data contoh. Di Windows, PDF nota dan laporan membutuhkan pustaka GTK/Pango, sementara image Docker sudah memuatnya. README.md:25-4715
Konfigurasi dan deploy
.env.example menjadi cetakan .env di VPS. Isinya menetapkan COMPOSE_FILE=compose.prod.yaml, APP_VERSION, TAILSCALE_IP, kredensial POSTGRES_*, DJANGO_SECRET_KEY, DJANGO_ALLOWED_HOSTS, identitas perusahaan, HARI_HAMPIR_KEDALUWARSA=60, serta tujuan backup BACKUP_AGE_RECIPIENT dan BACKUP_RCLONE_TUJUAN. .env.example:1-2316
Settings membaca variabel yang sama. DATABASES memakai POSTGRES_DB, POSTGRES_USER, POSTGRES_PASSWORD, POSTGRES_HOST, dan POSTGRES_PORT, dengan CONN_MAX_AGE 60 detik. backend/config/settings.py:77-8717 Ketika DJANGO_DEBUG kosong, SECRET_KEY diambil dari environment dan proses sengaja gagal saat start bila nilainya belum diisi. backend/config/settings.py:15-2418
Ke mana membaca selanjutnya
Rincian lapisan dan batas antarmodul ada di Arsitektur Sistem, termasuk Modul Domain dan Model Data serta Autentikasi, 2FA, dan Izin. Cara memasang dan mengisi variabel lingkungan dibahas di Memulai dan Konfigurasi, sedangkan rilis, sertifikat, dan backup di Deploy Produksi dan Operasi.