Pernah kaga lu bayangin, narik ribuan data stok gudang bahan kimia sambil nge-render grafik real-time di layar HP, tapi aplikasinya tetep jalan mulus 60fps tanpa ngelag sedikitpun?
Selamat dateng di series mahakarya gua. Di sini kita bakal ngebangun sistem manajemen gudang kelas enterprise dari nol, case study nya: PT Putra Armssy Perkasa (Pabrik deterjen, softener, dan pewangi laundry).
Total ada 10 sesi di series ini, mulai dari setup arsitektur awal sampe bikin sistem Role-Based Access dan Cloud Sync. Siapin kopi lu yang paling item, buka Code Editor, dan mari kita obrak-abrik mesinnya!
sesi 1: Setup & Arsitektur Inti
Di sesi 1 ini, kita bakal setting arsitektur awalnya dulu. Kita bakal sikat pake React Native sebagai framework cross-platform nya. Kenapa? Biar gampang jembatanin UI ke C++ (buat core logic yang butuh kalkulasi berat dan ngebut) terus kita pake Swift buat bikin native module khusus di ekosistem iOS.
Bahan baku racikan kayak MES, Texapon, dan LABS sampai ke produk jadi, semuanya bakal aman kecatat di sistem ini. Yuk, langsung kita bedah dalemannya!
1. C++ Core Engine (Otak Gudangnya)
Kita mulai dari mesin bawahnya. C++ di mari tugasnya ngurusin mutasi barang yang masuk dan keluar. Karena transaksi gudang bisa rame, kita pake konsep Multithreading dan Mutex di C++ biar kaga terjadi Race Condition pas aplikasi lagi narik data stok bahan kimia barengan.
#include <iostream>
#include <string>
#include <unordered_map>
#include <mutex>
class InventoryEngine {
private:
std::unordered_map<std::string, int> stock;
std::mutex mtx;
public:
// Fungsi buat nambah stok masuk gudang
void addStock(const std::string& item, int qty) {
std::lock_guard<std::mutex> lock(mtx); // Kunci data biar kaga bentrok
stock[item] += qty;
std::cout << "Gudang Update: " << item << " nambah " << qty << " liter/kg.\n";
}
// Fungsi buat cek sisa stok
int checkStock(const std::string& item) {
std::lock_guard<std::mutex> lock(mtx);
return stock[item];
}
};
Gudang Update: LABS nambah 20 liter/kg.
Status: Mesin gudang siap, stok aman kaga bakal tabrakan datanya pas diakses.
2. Swift Native Module (Jembatan ke iOS)
Nah, biar aplikasi lu jalan mulus jaya di iPhone, kita harus bungkus fungsi C++ tadi terus kita panggil pake Swift buat dijadiin bridge (jembatan) ke tampilan React Native-nya.
import Foundation
import React
@objc(WarehouseBridge)
class WarehouseBridge: RCTEventEmitter {
// Fungsi yang bakal dipanggil dari React Native
@objc func updateStockIOS(_ itemName: String, quantity: Int) {
// Di sini harusnya kita manggil instance dari InventoryEngine C++
// Buat tutorial awal, kita simulasikan sukses balikan datanya dulu
let statusMessage = "Sukses update \(itemName) sebanyak \(quantity) drum via iOS Native Bridge."
print(statusMessage)
// Kirim event notifikasi balik ke UI
sendEvent(withName: "onStockUpdated", body: ["message": statusMessage])
}
// Daftarin event biar dikenali sama JavaScript
override func supportedEvents() -> [String]! {
return ["onStockUpdated"]
}
}
3. Cross-Platform UI (Tampilan Layar HP)
Biar kaga usah ngoding dua kali buat Android sama iOS, front-end nya kita rakit pake React Native (JavaScript/TypeScript). Tampilannya kita bikin cakep, minimalis, dan yang pasti ringan biar kaga ada drama aplikasi nge-lag.
import React, { useState, useEffect } from 'react';
import { View, Text, TouchableOpacity, StyleSheet, NativeEventEmitter, NativeModules } from 'react-native';
const { WarehouseBridge } = NativeModules;
const warehouseEmitter = new NativeEventEmitter(WarehouseBridge);
const App = () => {
const [stockLog, setStockLog] = useState<string>('Gudang masih anteng, belum ada pergerakan.');
useEffect(() => {
// Dengerin bisikan dari Swift
const subscription = warehouseEmitter.addListener(
'onStockUpdated',
(event) => {
setStockLog(event.message);
}
);
return () => subscription.remove();
}, []);
const handleUpdateStock = () => {
// Lempar data dari UI ke Swift, terus diterusin ke C++
WarehouseBridge.updateStockIOS('Softener Wangi Bunga', 50);
};
return (
<View style={styles.container}>
<Text style={styles.headerTitle}>Gudang PT Putra Armssy Perkasa</Text>
<View style={styles.card}>
<Text style={styles.logText}>{stockLog}</Text>
</View>
<TouchableOpacity style={styles.button} onPress={handleUpdateStock}>
<Text style={styles.buttonText}>TAMBAH STOK SOFTENER</Text>
</TouchableOpacity>
</View>
);
};
Gudang PT Putra Armssy Perkasa
Sukses update Softener Wangi Bunga sebanyak 50 drum via iOS Native Bridge.
sesi 2: Database Storage & UI List Barang
Masa iya tiap nutup aplikasi, data stoknya nguap gitu aja? Bikin puyeng ntar orang gudang. Makanya, di sesi 2 ini kita bakal pasang Database Lokal (SQLite) langsung di level C++. Kenapa di C++? Biar urusan query data bahan baku racikan kayak MES, Texapon, LABS, sampe ke produk jadi tetep ngacir kaga pake loading lama.
1. C++ SQLite Engine (Gudang Ingatan)
#include <iostream>
#include <sqlite3.h>
#include <string>
class DatabaseEngine {
private:
sqlite3* db;
char* zErrMsg = 0;
public:
// Buka atau bikin file database baru
void initDB() {
int rc = sqlite3_open("gudang_armssy.db", &db);
if (rc) {
std::cerr << "Waduh, gagal buka DB: " << sqlite3_errmsg(db) << "\n";
} else {
std::cout << "Mantap, Database gudang_armssy.db sukses kebuka!\n";
// Bikin tabel kalo belom ada
std::string sql = "CREATE TABLE IF NOT EXISTS INVENTORY("
"ID INTEGER PRIMARY KEY AUTOINCREMENT,"
"NAMA_BARANG TEXT NOT NULL,"
"KATEGORI TEXT NOT NULL,"
"QTY INT NOT NULL);";
sqlite3_exec(db, sql.c_str(), 0, 0, &zErrMsg);
}
}
};
sesi 3: Form Input Barang & Validasi
Kalo ada barang baru masuk dari supplier (kayak drum Texapon baru), gimana cara masukin datanya? Kita bikin form inputan yang cakep di React Native, terus datanya kita lempar lewat jembatan Swift, dan berujung dieksekusi sama C++ buat disimpen ke SQLite.
import React, { useState } from 'react';
import { View, Text, TextInput, TouchableOpacity, Alert, NativeModules } from 'react-native';
const { InventoryInputBridge } = NativeModules;
const AddInventoryScreen = () => {
const [namaBarang, setNamaBarang] = useState('');
const [qty, setQty] = useState('');
const handleSimpanData = async () => {
if (!namaBarang || !qty) {
Alert.alert('Eitss!', 'Isi dulu dong kolom nama sama jumlahnya, ngab.');
return;
}
try {
const response = await InventoryInputBridge.addNewItem(namaBarang, 'Bahan Baku', parseInt(qty, 10));
Alert.alert('Mantap!', response);
} catch (error) {
Alert.alert('Error', error.message);
}
};
// UI Render logic...
};
sesi 4: Scan Barcode/QR Code Biar Sat-Set!
Kalo orang gudang PT Putra Armssy Perkasa suruh ngetik satu-satu pake jari, bisa keriting tuh tangan, rawan typo pula. Mending kita manfaatin kamera iPhone/Android buat nge-jepret QR Code yang nempel di drumnya.
class QRParserEngine {
public:
// Fungsi utama nerima scan dari HP
bool processScannedData(const std::string& rawQR) {
// Kita belek teksnya pake pembatas '|' misal: TEXAPON|Bahan Baku|200
std::vector<std::string> data = splitQRData(rawQR, '|');
if (data.size() != 3) {
std::cerr << "Waduh, format QR Code kaga valid ngab!\n";
return false;
}
std::cout << "C++ Berhasil nge-decode QR: " << data[0] << " - " << data[2] << " Liter/Kg.\n";
return true;
}
};
sesi 5: Fitur Barang Keluar & Validasi Anti-Minus!
Kalo stok di gudang sisa 50 jerigen, tapi mau ngeluarin 100 jerigen, sistem harus tereak: "Eitss, stok kaga cukup bray!" biar kaga terjadi yang namanya stok minus.
C++: Mantap! 15 Deterjen Cair Matic sukses dikeluarin dari gudang.
Status: Logika pertahanan C++ udah jalan. Gudang lu sekarang anti boncos.
sesi 6: Dashboard Analytics & Chart Kece!
Kita bakal tarik datanya pake C++, balut di Swift, dan kita gambar jadi Grafik Visual (Bar Chart) di React Native. Biar bureh dan decision making jadi sat-set!
// Fungsi narik Top 5 Barang Paling Laris
std::vector<ItemStat> getTopMovingItems() {
std::string sql = "SELECT NAMA_BARANG, SUM(QTY) as TOTAL "
"FROM OUTBOUND_LOG "
"GROUP BY NAMA_BARANG "
"ORDER BY TOTAL DESC LIMIT 5;";
// Eksekusi ke SQLite trus return datanya ke Swift
}
sesi 7: Auto-Generate Laporan PDF Buat Rapat Bos!
Cuma modal sekali pencet, sistem bakal ngerangkum semua data, nyetak jadi file PDF yang rapih, dan siap di-share ke WhatsApp grup pabrik!
let fmt = UIMarkupTextPrintFormatter(markupText: htmlStringFromCPP)
let render = UIPrintPageRenderer()
render.addPrintFormatter(fmt, startingAtPageAt: 0)
// Proses Nggambar PDF ukuran A4
let pdfData = NSMutableData()
UIGraphicsBeginPDFContextToData(pdfData, .zero, nil)
UIGraphicsBeginPDFPage()
render.drawPage(at: 0, in: UIGraphicsGetPDFContextBounds())
UIGraphicsEndPDFContext()
// Simpen ke Documents iOS
sesi 8: Integrasi Printer Thermal Bluetooth
Kita bakal nyulap aplikasi lu biar bisa Konek ke Printer Thermal Bluetooth. Kita bakal pake standar bahasa mesin printer namanya ESC/POS.
// Kode ESC/POS (Standar mesin printer)
std::string INIT = "\x1B\x40"; // Reset printer
std::string BOLD_ON = "\x1B\x45\x01"; // Huruf tebal nyala
std::string CUT_PAPER = "\x1D\x56\x41\x10"; // Potong kertas
receipt += INIT + BOLD_ON + "PT PUTRA ARMSSY PERKASA\n";
sesi 9: Sistem Login & Hak Akses (Role System)
Kalo berhasil masuk, kita simpen Role nya, trus kita pake logic sederhana buat nyembunyiin tombol "Tambah/Keluar Barang" buat si Viewer.
C++: Ditolak! Username atau password salah ngab.
sesi 10: Cloud Sync - Backup Data ke Server
C++ bakal ngerangkum semua isi gudang jadi format teks JSON, lempar ke Swift, trus Swift bakal ngirim data itu lewat jalur internet (HTTP POST) ke server pusat PT Putra Armssy Perkasa.
var request = URLRequest(url: urlServer)
request.httpMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.httpBody = payloadJSONFromCPP.data(using: .utf8)
// Terbangin data ke awan ☁️