first init
This commit is contained in:
@@ -0,0 +1,8 @@
|
|||||||
|
FROM nginx:alpine
|
||||||
|
|
||||||
|
COPY index.html /usr/share/nginx/html/index.html
|
||||||
|
|
||||||
|
EXPOSE 80
|
||||||
|
|
||||||
|
HEALTHCHECK --interval=30s --timeout=5s --start-period=5s --retries=3 \
|
||||||
|
CMD wget -qO- http://localhost/ || exit 1
|
||||||
@@ -0,0 +1,270 @@
|
|||||||
|
# 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.*
|
||||||
+179
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user