# POSMANT — Technical Overview **Point of Sale Manajemen Aset Niaga Terpadu** Aplikasi POS + manajemen stok native Android, offline-first, untuk UMKM daerah terpencil. --- ## Tech Stack ``` Mobile → Flutter (Android-first) Local DB → SQLite via Drift Background → WorkManager (via flutter_workmanager) Backend → Node.js + Fastify Server DB → PostgreSQL + Prisma ORM Bahasa → Dart (mobile) + TypeScript (backend) ``` ### Kenapa Flutter, bukan PWA | | PWA | Flutter (dipilih) | |---|---|---| | Startup | Load browser dulu | Langsung buka | | Offline storage | IndexedDB — bisa dihapus sistem | SQLite — permanen | | Background sync | Tidak reliable | WorkManager — reliable | | Printer Bluetooth | Terbatas | Native, mudah | | Low-end device | Oke | Lebih baik | > Risiko kritis PWA: Android otomatis hapus cache browser saat storage penuh. 7 hari transaksi yang belum sync bisa hilang seketika — tidak bisa ditoleransi untuk warung terpencil. --- ## Arsitektur Umum ``` [Device Android] [Server] [Data Layer] ┌──────────────────┐ ┌──────────────┐ ┌─────────────────┐ │ Flutter App │ sync │ Fastify API │ proses │ Operational DB │ │ - UI/UX │ ────────► │ │ ───────► │ (per warung) │ │ - SQLite/Drift │ (silent, │ Agregasi │ │ retensi 12 bln │ │ - WorkManager │ malam) │ per │ ├─────────────────┤ │ │ │ kecamatan │ │ Agregat DB │ └──────────────────┘ └──────────────┘ │ (permanen) │ └─────────────────┘ ``` --- ## Platform **Flutter — Android-first** - Target device: Android kelas menengah ke bawah - Distribusi: APK sideload (via pengabdian masyarakat) atau Play Store - iOS: tidak dalam scope awal, namun codebase Flutter siap bila diperlukan --- ## Struktur Proyek ``` posmant/ ├── mobile/ ← Flutter app (Android) │ ├── lib/ │ │ ├── features/ │ │ │ ├── pos/ │ │ │ ├── stok/ │ │ │ ├── laporan/ │ │ │ └── sync/ │ │ ├── core/ ← database, network, shared logic │ │ └── main.dart │ └── pubspec.yaml ├── server/ ← Node.js + Fastify backend │ ├── src/ │ │ ├── routes/ │ │ ├── jobs/ ← agregasi & cleanup scheduler │ │ └── prisma/ │ └── package.json └── README.md ``` --- ## Strategi Offline-First ### Prinsip Dasar App dirancang untuk berjalan **tanpa internet sebagai kondisi default**. Koneksi internet hanya dibutuhkan untuk sync. ### Teknologi Offline | Komponen | Package | Fungsi | |---|---|---| | **SQLite** | `drift` | Database lokal permanen — menyimpan semua transaksi | | **WorkManager** | `flutter_workmanager` | Jadwalkan sync otomatis tengah malam | | **HTTP Client** | `dio` | Kirim data ke server saat online | | **Connectivity** | `connectivity_plus` | Deteksi status jaringan | ### Alur Sync ``` Seharian → Transaksi tersimpan di SQLite lokal Tengah malam → WorkManager cek koneksi → ada sinyal? sync otomatis, diam-diam Pagi → Semua tersinkron, pengguna tidak perlu tahu ``` ### Sync Window (Batas Offline) ``` Hari 1-4 → Normal, tidak ada notifikasi Hari 5 → Banner kuning: "Segera hubungkan ke internet" Hari 7 → Banner merah: "Harap sinkron hari ini" Hari 8+ → Mode read-only: hanya bisa lihat data, tidak bisa input transaksi baru ``` ### Conflict Resolution Jika dua device edit data yang sama saat offline: - Strategi: **last-write-wins** dengan audit log - Semua perubahan dicatat dengan timestamp --- ## Template Bisnis (Onboarding) Saat registrasi, pengguna memilih jenis usaha. App otomatis menyiapkan data awal yang relevan. | Template | Pre-fill Kategori | Satuan Default | Mode | |---|---|---|---| | Warung | Sembako, snack, minuman | pcs, sachet, kg, liter | Produk | | Kafe | Menu minuman, makanan ringan | gelas, porsi, cup | Produk | | Katering | Paket nasi box, prasmanan | porsi, paket, orang | Produk* | | Laundry | Cuci reguler, express, setrika | kg, pcs, paket | Produk* | | Umum | Kosong | pcs | Produk | > *Katering dan Laundry menggunakan model produk disederhanakan di MVP. Mode order dengan status (masuk → proses → selesai) masuk fase berikutnya. Template juga memperkaya data riset — setiap agregat per kecamatan diketahui distribusi jenis usahanya. --- ## Data Architecture ### Lapis 1 — Operational (Private per Warung) ``` Entitas utama: - Warung (nama, jenis usaha, lokasi kecamatan) - Produk (nama, kategori, harga, satuan, stok) - Transaksi (waktu, produk, jumlah, total) - StokOpname (penyesuaian stok manual + alasan) ``` - Hanya bisa diakses oleh pemilik warung sendiri - Disimpan di server maksimal **12 bulan** - Setelah 12 bulan: di-aggregate lalu raw data dihapus otomatis ### Lapis 2 — Research (Agregat per Kecamatan) ``` Contoh data agregat: - Total transaksi per kategori produk per kecamatan per bulan - Rata-rata harga jual per kategori per wilayah - Distribusi jenis usaha per kecamatan - Pola stok (kelangkaan, kelebihan) per kategori ``` - Tidak dapat mengidentifikasi warung atau individu manapun - Disimpan **permanen** — aset riset utama - Jadi bahan laporan, dataset, jurnal, dan produk data ### Alur Agregasi (Server) ``` Raw data masuk → disimpan di Operational DB Setiap malam → job agregasi → update Agregat DB per kecamatan Setiap bulan → cek data > 12 bulan → hapus raw (pastikan agregat sudah tersimpan) ``` --- ## Fitur Inti (MVP) ### Modul Onboarding - [ ] Pilih template bisnis (warung, kafe, katering, laundry, umum) - [ ] Data produk awal ter-pre-fill sesuai template - [ ] Tutorial singkat alur penggunaan ### Modul POS - [ ] Input transaksi penjualan - [ ] Pilih produk dari daftar - [ ] Hitung total otomatis - [ ] Struk digital (simpan di app) - [ ] Dukungan printer thermal Bluetooth ### Modul Stok - [ ] Daftar produk dengan stok real-time - [ ] Notifikasi stok menipis - [ ] Stok opname manual - [ ] Riwayat perubahan stok ### Modul Laporan - [ ] Ringkasan penjualan harian / mingguan / bulanan - [ ] Produk terlaris - [ ] Export CSV (backup darurat) ### Modul Sync - [ ] Background sync otomatis tengah malam (WorkManager) - [ ] Status sync terakhir - [ ] Warning sistem (hari ke-5, ke-7, mode read-only hari ke-8) - [ ] Manual sync (tombol opsional) --- ## Privasi & Keamanan - Enkripsi data in-transit (HTTPS) - Enkripsi data at-rest di server - Consent eksplisit saat registrasi (penggunaan data untuk riset) - Hak hapus data (right to erasure) — pengguna bisa hapus akun + data - Data retention policy otomatis (12 bulan raw → hapus) - Kepatuhan UU PDP No. 27/2022 - Ethical clearance institusi untuk jalur publikasi akademik --- ## Yang Masih Perlu Didiskusikan - [ ] **User roles** — apakah ada perbedaan akses kasir vs pemilik warung? - [ ] **Multi-device** — satu warung bisa pakai lebih dari satu HP? - [ ] **Satuan lokal** — ikat, kodi, pak — bagaimana sistem satuannya? - [ ] **Infrastruktur** — hosting di mana? (VPS, Railway, dll.) - [ ] **Distribusi app** — APK sideload via pengabdian, atau Play Store? - [ ] **Printer struk** — model printer thermal Bluetooth yang disupport? - [ ] **Fitur fase 2** — mode order untuk laundry/katering, multi-outlet, dll. --- ## Deploy — Landing Page (Coolify) Landing page statis di-serve via nginx dalam Docker container. ### File ``` index.html ← landing page Dockerfile ← build config untuk Coolify ``` ### Dockerfile ```dockerfile FROM nginx:alpine COPY index.html /usr/share/nginx/html/index.html EXPOSE 80 HEALTHCHECK --interval=30s --timeout=5s CMD wget -qO- http://localhost/ || exit 1 ``` ### Langkah Deploy di Coolify 1. **Push repo ke GitHub/Gitlab** (pastikan `Dockerfile` dan `Posmant Landing Page.html` ikut ter-commit) 2. **Buka Coolify** → New Resource → Application 3. Pilih repo dan branch 4. **Build Pack:** Dockerfile *(Coolify akan auto-detect)* 5. **Port:** `80` 6. Klik **Deploy** ### Environment Tidak ada environment variable yang dibutuhkan — ini halaman statis murni. ### Update Landing Page Ganti file `index.html` → push → Coolify auto-redeploy (aktifkan auto-deploy di settings). --- ## Status `v0.2 — Perencanaan (stack dikonfirmasi)` --- *README ini adalah dokumen hidup yang akan diperbarui seiring diskusi pengembangan.*