Backend REST API untuk Sistem Manajemen Stok & Kedaluwarsa Obat Rumah Sakit (SIMRS) berbasis logika FEFO (First Expired, First Out).
Project ini dibangun menggunakan Go (Golang), Gin Web Framework, GORM ORM, PostgreSQL, dan JWT Authentication.
- Frontend App: README Frontend Module
- Bahasa Pemrograman: Go
1.26+ - Framework Web: Gin Web Framework
- Database & ORM: PostgreSQL & GORM
- Autentikasi: JWT (
github.com/golang-jwt/jwt/v5) &bcrypt - Konfigurasi Environment:
github.com/joho/godotenv
server/
├── config/
│ ├── db.go # Koneksi PostgreSQL & inisialisasi GORM
│ └── seed.go # Seeder data dummy Obat & Batch FEFO otomatis
├── handlers/
│ ├── auth_handlers.go # Handler registrasi & login user
│ └── medicine_handlers.go # Handler CRUD Obat & Pemotongan Stok FEFO
├── middleware/
│ ├── auth.go # Middleware verifikasi JWT Bearer Token (RequireAdmin)
│ └── cors.go # Middleware Cross-Origin Resource Sharing (CORS)
├── models/
│ ├── User.go # Struct data User (Admin/Staff)
│ ├── Medicine.go # Struct data Master Obat
│ └── medicineBatch.go # Struct data Batch Stok & Expired Date
├── routes/
│ └── route.go # Router API Gin (/api/v1) & proteksi JWT
├── services/
│ └── medicine_service.go # Logika bisnis pemotongan stok FEFO (DB Transaction & Lock)
├── utils/
│ ├── jwt.go # Generasi token JWT
│ └── password.go # Hashing & verifikasi password bcrypt
├── .env # File environment variabel database & JWT
├── go.mod # File definisi Go Module
├── go.sum # File checksum dependency Go
└── main.go # Entry point aplikasi server
Prinsip FEFO memastikan bahwa obat dengan tanggal kedaluwarsa (expired date) paling dekat akan selalu diambil/dipotong terlebih dahulu.
Logika pemotongan berada di services/medicine_service.go:
- Membuka transaksi database (
tx := config.DB.Transaction). - Mengambil batch obat yang aktif (
stock > 0danexpired_date > NOW()). - Mengurutkan batch berdasarkan tanggal expired secara ascending (
ORDER BY expired_date ASC). - Mengunci baris data menggunakan
SELECT FOR UPDATE(clause.Locking{Strength: "UPDATE"}) untuk mencegah data race akibat permintaan bersamaan. - Memotong jumlah stok berurutan hingga kuantitas yang diminta terpenuhi.
Buat file .env di dalam folder server/:
PORT=8080
DB_HOST=localhost
DB_USER=postgres
DB_PASSWORD=123
DB_NAME=sistem-obat
DB_PORT=5432
JWT_SECRET=supersecretkey_simrs_123- Go 1.26+ terinstall.
- Database PostgreSQL sudah berjalan dan database bernama
sistem-obattelah dibuat.
cd server
go mod tidygo run main.goServer akan otomatis melakukan Auto-Migrate tabel database dan menjalankan Seeder data dummy obat jika database masih kosong. HTTP Server berjalan pada http://localhost:8080.
- Endpoint:
POST /api/v1/auth/register - Request Body:
{ "username": "admin_farmasi", "password": "password123" } - Response (
201 Created):{ "message": "Registrasi pengguna berhasil" }
- Endpoint:
POST /api/v1/auth/login - Request Body:
{ "username": "admin_farmasi", "password": "password123" } - Response (
200 OK):{ "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." }
- Endpoint:
GET /api/v1/medicines - Query Parameter (Opsional):
?search=paracetamol - Response (
200 OK):{ "data": [ { "ID": 1, "name": "Paracetamol 500mg", "code": "OBT-PCT-500", "batches": [ { "ID": 1, "batch_number": "PCT-2026-B1", "stock": 40, "expired_date": "2026-10-01T00:00:00Z" } ] } ] }
- Endpoint:
GET /api/v1/medicines/:id - Response (
200 OK):{ "data": { "ID": 1, "name": "Paracetamol 500mg", "code": "OBT-PCT-500", "batches": [...] } }
- Endpoint:
POST /api/v1/medicines - Request Body:
{ "name": "Paracetamol 500mg", "code": "OBT-PCT-500", "batches": [ { "batch_number": "BATCH-202608-01", "stock": 50, "expired_date": "2026-10-31T00:00:00Z" } ] } - Response (
201 Created):{ "data": { "ID": 1, "name": "Paracetamol 500mg", "code": "OBT-PCT-500" } }
- Endpoint:
PUT /api/v1/medicines/:id - Request Body:
{ "name": "Paracetamol Forte 650mg", "code": "OBT-PCT-650" } - Response (
200 OK):{ "message": "Data obat berhasil diperbarui", "data": { ... } }
- Endpoint:
DELETE /api/v1/medicines/:id - Response (
200 OK):{ "message": "Obat berhasil dihapus" }
- Endpoint:
POST /api/v1/medicines/deduct-fefo - Request Body:
{ "medicine_id": 1, "quantity": 30 } - Response (
200 OK):{ "message": "Pemotongan stok FEFO berhasil dilaksanakan!" }
Ketika server pertama kali dinyalakan dan tabel medicines kosong, seeder akan memasukkan data awal secara otomatis:
- Paracetamol 500mg (
OBT-PCT-500) — 3 Batch (Stok: 40, 100, 150) - Amoxicillin 500mg (
OBT-AMX-500) — 2 Batch (Stok: 30, 80) - Cefadroxil 500mg (
OBT-CFD-500) — 1 Batch (Stok: 60) - Ibuprofen 400mg (
OBT-IBU-400) — 1 Batch (Stok: 90) - Vitamin C 1000mg (
OBT-VTC-1000) — 1 Batch (Stok: 200)
Untuk menjalankan antarmuka pengguna berbasis React, silakan buka dokumentasi frontend: ➡️ Instruksi Jalankan Frontend Module