Lompat ke konten
dokumentasi.id
Commit 32b2830
v1
Star0

Kamu membaca versi lama. Halaman ini hanya bisa dibaca.

1

Ringkasan Proyek Hydro

Hydro adalah website internal untuk mencatat produk, stok per batch, pembelian pelanggan, pembayaran, retur, piutang, dan laporan pada perusahaan air minum kemasan. Repository ini memisahkan tiga bagian: backend/ berisi Django 5.2 LTS dengan Django REST Framework beserta aturan bisnis dan hak akses, frontend/ berisi Next.js statis dengan TypeScript, Tailwind, dan shadcn/ui, sedangkan deploy/ memuat Nginx, skrip rilis, backup, dan pemulihan. README.md:1-11

Dua berkas compose melayani dua keperluan berbeda. compose.yaml mencoba aplikasi di komputer sendiri dengan satu perintah, sementara compose.prod.yaml menjalankan produksi dengan tiga service web, api, dan db. README.md:1-11

Peta modul

Diagram berikut memetakan modul yang benar-benar terdaftar di INSTALLED_APPS beserta ketergantungannya pada database dan lapisan deploy. Modul inti menjadi tempat izin, paginasi, dan skema bersama; akun menyimpan model pengguna kustom akun.Pengguna; produk, stok, pembelian, dan laporan memikul pencatatan harian. backend/config/settings.py:26-45

graph TD
  WEB["web: Nginx"]
  API["api: gunicorn config.wsgi"]
  DB[("PostgreSQL 18.1")]

  subgraph FE["frontend"]
    KLIEN["src/lib/api.ts"]
    HALAMAN["src/app/(app)"]
  end

  subgraph BE["backend"]
    INTI["inti"]
    AKUN["akun"]
    PRODUK["produk"]
    STOK["stok"]
    BELI["pembelian"]
    LAPOR["laporan"]
  end

  DEPLOY["deploy: rilis.sh, backup.sh"]

  HALAMAN --> KLIEN
  KLIEN -->|"fetch + CSRF"| WEB
  WEB --> API
  API --> INTI
  API --> AKUN
  API --> PRODUK
  API --> STOK
  API --> BELI
  API --> LAPOR
  INTI --> DB
  AKUN --> DB
  PRODUK --> DB
  STOK --> DB
  BELI --> DB
  LAPOR --> DB
  DEPLOY -->|"pull image GHCR"| WEB
  DEPLOY -->|"manage.py migrate"| API

  style DB fill:#336791,color:#fff
  style INTI fill:#f59e0b,color:#000
  style WEB fill:#f59e0b,color:#000
  style API fill:#f59e0b,color:#000
  style DEPLOY fill:#8b5cf6,color:#fff
  style BELI fill:#2d7d46,color:#fff
  style STOK fill:#2d7d46,color:#fff
%% fig: Peta modul Hydro
%% desc: Halaman frontend memanggil Nginx lalu gunicorn; setiap app Django membaca dan menulis ke PostgreSQL, sedangkan skrip deploy menarik image dan menjalankan migration.
Fig. 1: Peta modul HydroHalaman frontend memanggil Nginx lalu gunicorn; setiap app Django membaca dan menulis ke PostgreSQL, sedangkan skrip deploy menarik image dan menjalankan migration.
LapisanModul atau berkasPeran
Backendintiizin, paginasi, format, skema OpenAPI bersama
Backendakunmodel Pengguna dan alur 2FA lewat allauth.mfa
BackendprodukKategori, Produk, SatuanProduk, HargaProduk
BackendstokBarangMasuk, BatchProduk, MutasiStok, StokOpname
BackendpembelianPelanggan, Transaksi, Pembayaran, Retur
Backendlaporandata.py untuk angka laporan dan ekspor.py untuk berkas
Frontendsrc/lib/api-types.tshasil openapi-typescript dari backend/schema.yaml
Deploydeploy/rilis.shbackup, ganti tag versi, migrate, lalu up -d

Baris tabel di atas bersandar pada daftar app di setelan dan pada nama berkas nyata di laporan/ serta frontend/src/lib/. backend/config/settings.py:26-45 Tipe TypeScript dibangkitkan ulang oleh skrip tipe-api yang membaca ../backend/schema.yaml dan menulis src/lib/api-types.ts. frontend/package.json:5-11 Skrip rilis.sh sendiri menjalankan bash deploy/backup.sh, memperbarui APP_VERSION di .env, docker compose pull web api, docker compose run --rm api python manage.py migrate, lalu docker compose up -d. deploy/rilis.sh:1-13

Cara menjalankan

CaraBerkasServiceAkses
Coba lokalcompose.yamlweb, api, dbport 8080 pada host
Developmentcompose.dev.yamlweb, api, dbport 3000 untuk Next.js
Produksicompose.prod.yamlweb, api, dbport 443 diikat ke IP Tailscale

Pada compose.yaml service web membangun image dari deploy/web.Dockerfile, memetakan port 127.0.0.1:8080:8080, dan menunggu api berstatus service_healthy. Service api menjalankan migrate --noinput, isi_demo, lalu gunicorn config.wsgi --bind 0.0.0.0:8000 --workers 2. compose.yaml:3-33 Service db memakai image postgres:18.1 dengan healthcheck pg_isready -U hydro -d hydro setiap 3 detik dan 20 kali retry. compose.yaml:35-46

Di produksi, image diambil dari GHCR dengan tag ${APP_VERSION}, web diikat ke ${TAILSCALE_IP}:443:8443, dan kedua service aplikasi berjalan read_only dengan cap_drop: [ALL]. Jaringan app dan data bersifat internal, sehingga hanya edge yang menghadap luar. compose.prod.yaml:1-63

Setelan Django membaca konfigurasi dari environment. SECRET_KEY diambil dari DJANGO_SECRET_KEY dan sengaja gagal saat start bila variabel itu kosong ketika DEBUG mati. Koneksi database default memakai django.db.backends.postgresql dengan CONN_MAX_AGE 60 detik. backend/config/settings.py:77-89

Aturan pencatatan inti

Stok disimpan dalam botol per batch. BatchProduk menegakkan sisa >= 0 lewat constraint sisa_tidak_minus dan menjaga satu nomor batch unik per produk lewat batch_unik_per_produk. backend/stok/models.py:34-54 Setiap perubahan stok wajib melewati ubah_stok() di backend/stok/layanan.py, yang menolak sisa minus dengan pesan Stok batch {nomor_batch} tidak boleh minus. dan langsung menulis baris MutasiStok. backend/stok/layanan.py:21-44 Jenis mutasi yang tercatat adalah masuk, penjualan, retur, rusak, kedaluwarsa, opname, dan batal. backend/stok/models.py:57-79

Saat penjualan, baris batch dikunci lebih dulu lewat kunci_batch(), yang mengurutkan select_for_update() berdasarkan id supaya dua transaksi tidak saling menunggu. backend/stok/layanan.py:47-50 Nota dibuat oleh buat_transaksi(). Fungsi itu memeriksa kunci_idempoten lebih dahulu, sehingga klik ganda atau kirim ulang mengembalikan nota yang sudah ada, dan seluruh penulisan berjalan di dalam satu transaction.atomic(). backend/pembelian/layanan.py:31-46

graph LR
  BM["catat_barang_masuk"] --> B["BatchProduk"]
  B --> U["ubah_stok"]
  U --> M["MutasiStok"]
  T["buat_transaksi"] --> K["kunci_batch"]
  K --> U
  T --> N["Transaksi + ItemTransaksi"]
  N --> S["sisa_tagihan"]
  X["ke_xlsx"] --> F["berkas .xlsx"]

  style B fill:#336791,color:#fff
  style M fill:#336791,color:#fff
  style N fill:#336791,color:#fff
  style U fill:#2d7d46,color:#fff
  style K fill:#f59e0b,color:#000
  style S fill:#8b5cf6,color:#fff
  style F fill:#8b5cf6,color:#fff
%% fig: Jalur tulis stok dan nota
%% desc: Barang masuk membentuk batch, perubahan sisa selalu lewat ubah_stok dan tercatat di mutasi_stok, sedangkan transaksi mengunci batch sebelum menulis nota dan sisa tagihan.
Fig. 2: Jalur tulis stok dan notaBarang masuk membentuk batch, perubahan sisa selalu lewat ubah_stok dan tercatat di mutasi_stok, sedangkan transaksi mengunci batch sebelum menulis nota dan sisa tagihan.

Piutang tidak dihitung ulang di aplikasi. Kolom sisa_tagihan pada Transaksi adalah GeneratedField dari total - total_retur - terbayar dengan db_persist=True, dan constraint tagihan_tidak_minus menjaga nilainya tidak negatif. backend/pembelian/models.py:34-57 Harga jual dibaca dari HargaProduk terbaru yang berlaku_mulai tidak melewati tanggal transaksi, lewat manager SatuanQuerySet.dengan_harga. backend/produk/models.py:46-80

⚠️ compose.yaml memakai password contoh dan berjalan tanpa HTTPS, jadi jangan dipakai untuk produksi. Hentikan dengan docker compose down; menambahkan -v ikut menghapus volume datanya. README.md:13-23

Ekspor laporan menghasilkan berkas unduhan. ke_xlsx() menulis satu lembar dengan header tebal, mengubah Decimal menjadi float, memberi format #,##0.00 untuk kolom uang, dan memaksa data_type = "s" pada sel teks supaya isian pengguna tidak terbaca sebagai rumus Excel. backend/laporan/ekspor.py:24-49 Rincian tiap alur ada di Alur Stok, Batch FEFO, dan Opname serta Alur Transaksi, Pembayaran, Retur, dan Piutang.