Skip to content

dimasalvin/POS-react

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

11 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

πŸ₯ Apotek Moro Mari β€” Sistem Manajemen Farmasi

Alamat: Jalan Gamers No. 8, Semarang | Telp: (024) 1234567

Sistem informasi manajemen apotek berbasis web fullstack untuk mengelola stok obat, pembelian dari PBF/supplier, penjualan kasir (HV & Resep), laporan harian, dan closing kasir per shift.


πŸ“ Tech Stack

Layer Teknologi
Frontend React 18 + Vite + TailwindCSS + React Router v6
Backend Node.js + Express.js
Database MySQL 5.7+ / MariaDB 10.3+
Auth JWT (JSON Web Token, expire 12h)
HTTP Client Axios (dengan interceptor token otomatis)
Icons Lucide React
Notifikasi React Hot Toast
Tanggal date-fns

Target deployment:

  • Backend β†’ Shared Hosting via cPanel Node.js Selector, atau Railway/Render
  • Frontend β†’ Vercel (static build dist/) atau subdomain shared hosting

πŸ—‚οΈ Struktur Direktori

apotek-moro-mari/
β”œβ”€β”€ backend/
β”‚   β”œβ”€β”€ index.js                    # Entry point server Express
β”‚   β”œβ”€β”€ .env.example                # Template konfigurasi environment
β”‚   β”œβ”€β”€ config/
β”‚   β”‚   β”œβ”€β”€ database.js             # MySQL connection pool (promise-based)
β”‚   β”‚   └── schema.sql              # DDL lengkap + seed data awal
β”‚   β”œβ”€β”€ middleware/
β”‚   β”‚   └── auth.js                 # JWT verify middleware + role guard
β”‚   └── routes/
β”‚       β”œβ”€β”€ auth.js                 # POST /login, POST /change-password
β”‚       β”œβ”€β”€ barang.js               # CRUD obat, harga otomatis, stock opname
β”‚       β”œβ”€β”€ pembelian.js            # Pembelian, supplier, histori, retur
β”‚       └── penjualan.js            # Kasir, laporan, closing, kas apotek
β”‚
└── frontend/
    β”œβ”€β”€ index.html
    β”œβ”€β”€ vite.config.js
    β”œβ”€β”€ tailwind.config.js
    β”œβ”€β”€ postcss.config.js
    └── src/
        β”œβ”€β”€ main.jsx
        β”œβ”€β”€ App.jsx                 # Router utama + ProtectedRoute
        β”œβ”€β”€ context/
        β”‚   └── AuthContext.jsx     # Global auth state, login/logout action
        β”œβ”€β”€ utils/
        β”‚   └── api.js              # Axios instance + semua fungsi API call
        β”œβ”€β”€ hooks/
        β”‚   └── useAuth.js          # Hook untuk konsumsi AuthContext
        β”œβ”€β”€ components/
        β”‚   β”œβ”€β”€ Layout.jsx          # Sidebar + header wrapper + <Outlet>
        β”‚   β”œβ”€β”€ Sidebar.jsx         # Navigasi sidebar dengan active state
        β”‚   β”œβ”€β”€ ProtectedRoute.jsx  # Guard route berdasar login + role
        β”‚   └── ui/
        β”‚       β”œβ”€β”€ Button.jsx
        β”‚       β”œβ”€β”€ Modal.jsx
        β”‚       β”œβ”€β”€ Table.jsx
        β”‚       β”œβ”€β”€ Badge.jsx       # Badge warna grup obat
        β”‚       β”œβ”€β”€ Input.jsx
        β”‚       └── Select.jsx
        └── pages/
            β”œβ”€β”€ Login.jsx
            β”œβ”€β”€ Dashboard.jsx       # Summary + peringatan stok kritis
            β”œβ”€β”€ stock/
            β”‚   β”œβ”€β”€ DaftarBarang.jsx
            β”‚   β”œβ”€β”€ SettingHarga.jsx
            β”‚   └── StockOpname.jsx
            β”œβ”€β”€ pembelian/
            β”‚   β”œβ”€β”€ DaftarSupplier.jsx
            β”‚   β”œβ”€β”€ InputPembelian.jsx
            β”‚   β”œβ”€β”€ HistoriPembelian.jsx
            β”‚   └── ReturPembelian.jsx
            β”œβ”€β”€ penjualan/
            β”‚   β”œβ”€β”€ KasirHV.jsx
            β”‚   β”œβ”€β”€ KasirResep.jsx
            β”‚   β”œβ”€β”€ LaporanPenjualan.jsx
            β”‚   └── ClosingKasir.jsx
            └── laporan/
                └── KasApotek.jsx

πŸ—„οΈ Database Schema

Tabel & Fungsi

Tabel Fungsi
users Akun login dengan role RBAC
barang Master data obat/produk apotek
kelas_terapi Kategori terapi obat
supplier Data PBF / distributor
pelanggan Data member / pasien
pembelian Header faktur pembelian dari PBF
pembelian_detail Item per baris faktur pembelian
retur_pembelian Header retur barang ke PBF
retur_pembelian_detail Item retur
penjualan Header transaksi kasir (HV/Resep)
penjualan_detail Item per transaksi penjualan
stock_opname Rekam fisik vs sistem per periode
kas_apotek Jurnal kas harian (debit/kredit)
closing_kasir Rekap pendapatan per shift

Relasi Utama

supplier ──< pembelian ──< pembelian_detail >── barang
supplier ──< retur_pembelian ──< retur_pembelian_detail >── barang
pelanggan ──< penjualan ──< penjualan_detail >── barang
users ──< penjualan
users ──< pembelian
barang ──< stock_opname

Enum & Nilai Khusus

users.role         β†’ 'apoteker' | 'apoteker_pendamping' | 'admin' | 'asisten_apoteker'

barang.grup        β†’ 'hijau'  -- obat bebas, bebas terbatas
                   β†’ 'merah'  -- obat keras, narkotika, psikotropika
                   β†’ 'biru'   -- barang konsinyasi

penjualan.tipe     β†’ 'hv' | 'resep'
penjualan.shift    β†’ 'pagi' | 'siang'
penjualan.status   β†’ 'draft' | 'confirmed' | 'void'

kas_apotek.jenis   β†’ 'debit' | 'kredit'

πŸ’° Logika Harga Otomatis

Dihitung di backend setiap kali barang dibuat/diupdate:

harga_beli   β†’ HNA (Harga Netto Apotek, sebelum PPN)
    Γ— 1.10
harga_jual   β†’ HNA + PPN 10%
    Γ— 1.10
harga_hv     β†’ harga_jual + margin 10% (untuk penjualan bebas/HV)
    Γ— 1.08
harga_resep  β†’ harga_hv + margin 8% (untuk penjualan dengan resep dokter)

Frontend menampilkan preview kalkulasi secara real-time saat input harga_beli di form barang.


πŸ” Role-Based Access Control

Role Stok Pembelian Kasir Laporan Master Data
apoteker βœ… Full βœ… Full βœ… Full βœ… Full βœ… Full
apoteker_pendamping βœ… Full βœ… Full βœ… Full βœ… Full ❌
admin πŸ‘ View βœ… Full βœ… Full βœ… Full ❌
asisten_apoteker πŸ‘ View ❌ βœ… Kasir saja πŸ‘ View ❌

Guard diimplementasi di:

  • Backend: middleware roleMiddleware(...roles) pada route tertentu
  • Frontend: komponen ProtectedRoute + hide/disable tombol berdasarkan user.role

πŸ”’ Format Nomor Nota

Kasir       : A{DDMMYY}{3-digit-seq}    contoh: A140420065
Resep (via modal) menggunakan nota yang sama (tipe tetap 'hv')
Retur PBF   : RT{YYYYMMDD}{3-digit-seq} contoh: RT202004140001

Nomor nota di-generate otomatis oleh backend. Urutan (seq) dihitung dari jumlah transaksi di tanggal dan tipe yang sama + 1.


πŸ”Œ API Endpoints

Semua endpoint (kecuali /api/auth/login dan /api/health) memerlukan header:

Authorization: Bearer <jwt_token>

Auth

POST   /api/auth/login
       Body: { username, password }
       Response: { token, user: { id, username, nama, role } }

POST   /api/auth/change-password    [auth]
       Body: { old_password, new_password }

Barang / Stok

GET    /api/barang                  ?search=&grup=hijau|merah|biru&low_stock=true
GET    /api/barang/:id
POST   /api/barang
       Body: { kode, nama_barang, satuan, pabrik, grup, kelas_terapi_id,
               stock_minimum, harga_beli }
PUT    /api/barang/:id
       Body: (sama seperti POST, minus kode)
DELETE /api/barang/:id              β†’ soft delete (is_active = 0)
POST   /api/barang/stock-opname/submit
       Body: { periode, tanggal, items: [{ barang_id, stock_sistem, stock_fisik, keterangan }] }

Pembelian & Supplier

GET    /api/pembelian               ?from=YYYY-MM-DD&to=YYYY-MM-DD&supplier_id=
GET    /api/pembelian/:id           β†’ include detail items
POST   /api/pembelian
       Body: { no_faktur, tanggal, supplier_id,
               items: [{ barang_id, jumlah, harga_hna, diskon_persen, diskon_nominal,
                         harga_netto, jumlah_harga }] }
GET    /api/pembelian/histori/barang/:barang_id  ?from=&to=
GET    /api/pembelian/supplier/list
POST   /api/pembelian/supplier/create
       Body: { kode, nama_pbf, alamat, kota, no_telp, jatuh_tempo }
PUT    /api/pembelian/supplier/:id
POST   /api/pembelian/retur/create
       Body: { no_retur, tanggal, supplier_id, keterangan,
               items: [{ barang_id, jumlah, harga_satuan, jumlah_harga }] }
GET    /api/pembelian/retur/list

Penjualan / Kasir

GET    /api/penjualan               ?from=&to=&shift=pagi|siang&tipe=hv|resep
GET    /api/penjualan/:id           β†’ include detail items
POST   /api/penjualan
       Body: { tanggal, shift, tipe, pelanggan_id (opsional),
               items: [{ barang_id, jumlah, harga_satuan, subtotal }],
               tunai, non_tunai }
       Response: { no_nota, id, kembalian }
POST   /api/penjualan/:id/void      β†’ kembalikan stok
GET    /api/penjualan/laporan/per-barang  ?from=&to=&barang_id=&shift=
GET    /api/penjualan/closing/summary     ?from=&to=&shift=
GET    /api/penjualan/kas/list            ?from=&to=
POST   /api/penjualan/kas/create
       Body: { tanggal, keterangan, jenis, nominal, tanggal_transaksi }

Umum

GET    /api/dashboard               β†’ summary hari ini + stok kritis
GET    /api/kelas-terapi
GET    /api/pelanggan               ?search=
POST   /api/pelanggan               Body: { kode, nama, no_hp, alamat, tipe }
GET    /api/health

πŸ“¦ Variabel Environment

Backend .env

PORT=5000
DB_HOST=localhost
DB_USER=root
DB_PASSWORD=your_db_password
DB_NAME=apotek_moro_mari
JWT_SECRET=ganti_dengan_string_acak_panjang
FRONTEND_URL=http://localhost:5173

Frontend .env

VITE_API_URL=http://localhost:5000/api

πŸš€ Cara Menjalankan

# 1. Setup database
mysql -u root -p < backend/config/schema.sql

# 2. Backend
cd backend && cp .env.example .env
# edit .env
npm install && npm run dev

# 3. Frontend
cd frontend && cp .env.example .env
# edit .env β†’ VITE_API_URL
npm install && npm run dev

πŸ”‘ Akun Default (Seed)

Username Password Role
admin 1234 admin
dyah 1234 apoteker

⚠️ Wajib ganti password setelah login pertama kali.


🚒 Deployment Guide

Frontend β†’ Vercel

  1. Push repo ke GitHub
  2. Import project di vercel.com
  3. Set root directory: frontend
  4. Set environment variable: VITE_API_URL=https://your-backend-domain.com/api
  5. Deploy β€” Vercel otomatis build dengan npm run build

Backend β†’ cPanel Shared Hosting

  1. Login cPanel β†’ Setup Node.js App
  2. Buat app baru:
    • Node.js version: 18+
    • Application root: backend
    • Application startup file: index.js
  3. Upload folder backend/ ke server via File Manager
  4. Buat file .env di folder backend (isi sesuai .env.example)
  5. Import schema.sql via phpMyAdmin
  6. Klik "Run NPM Install" di panel Node.js App
  7. Start/Restart app

Backend β†’ Railway / Render

  1. Push repo ke GitHub
  2. Connect repo di Railway/Render
  3. Set root directory: backend
  4. Set environment variables (DB_HOST, DB_USER, dll)
  5. Start command: npm start
  6. Deploy

Backend β†’ VPS

# Clone repo
git clone <repo-url> && cd kasir-react/backend

# Install
cp .env.example .env && nano .env
npm install

# Run with PM2
npm install -g pm2
pm2 start index.js --name apotek-backend
pm2 save && pm2 startup

About

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages