A free, offline-first, open source Point of Sale (POS) Progressive Web App built for Indonesian Micro, Small, and Medium Enterprises (UMKM). All data is stored locally on the user's device β no server, no registration, no cost.
- POS / Cashier β Full cashier interface with cart, per-item & per-transaction discounts, payment method selection, and automatic change calculation
- Open Bill β Save transactions as open bills for later checkout, with customer name, table number, per-item notes, and remarks (also shown on the receipt)
- Multi-User Mode β Optional opt-in mode with owner + staff roles and granular per-staff permissions (e.g. manage products, view reports, do refunds). Staff log in with username + 4-6 digit PIN
- Multi-Language β Full Bahasa Indonesia, English, and Bahasa Malaysia translations via i18next. Language can be switched from Settings or during onboarding
- Responsive Layout β Mobile-first phone UI with landscape/tablet mode featuring side-by-side cashier (products + cart) and adaptive grid columns
- Barcode Scanning β Scan product barcodes via camera (supports EAN-13, EAN-8, UPC-A, UPC-E, Code-128, Code-39, ITF, Code-93, QR) with robust permission handling for installed PWAs, or manual keyboard entry
- Product Management β Complete CRUD with categories, SKU (unique & required), units, optional descriptions (searchable, previewable in cashier), photos, and barcode support
- Master Data Satuan (Units) β Manage units of measurement with CRUD; safe deletion blocked when in use by products
- Stock Management β Stock in (from suppliers) and stock out (damaged, lost, returned, etc.)
- Automatic COGS (HPP) β Cost of Goods Sold is automatically calculated using the weighted average method on each stock-in
- Sales Reports β 7/30 day sales charts, top products, total revenue & profit
- Transaction History β Browse completed transactions with open bill filter tabs; delete transactions with optional stock restore
- Supplier Management β Manage supplier contacts and details
- Backup & Restore β Export/import all data as JSON, with automatic backup reminders
- PWA β Installable to home screen, fully offline with Service Worker (Workbox), supports any orientation. Install button is also available from Settings with adaptive instructions for iOS Safari and Chrome/Edge
- Android APK β Ships as a native Android app via Capacitor from the same codebase, running in parallel with the PWA. Includes app icon, splash screen, and native status bar handling
- Bluetooth Thermal Printing β Print receipts to ESC/POS thermal printers. PWA uses Web Bluetooth (Chrome on Android); the Android APK uses Classic Bluetooth, with a configurable default printer selection (APK-only setting)
- Onboarding β Interactive tutorial for first-time users (the PWA install step is automatically skipped in the APK)
- Dark Mode β Full dark theme support
- Theme Customization β Pick your preferred accent color
| Layer | Technology |
|---|---|
| Framework | React 18 + TypeScript |
| Build Tool | Vite |
| Styling | Tailwind CSS + shadcn/ui |
| Theming | next-themes (dark mode) |
| Database | IndexedDB via Dexie.js |
| Charts | Recharts |
| Routing | React Router DOM v6 |
| Forms & Validation | React Hook Form + Zod |
| State | @tanstack/react-query |
| Icons | Lucide React |
| i18n | i18next + react-i18next |
| Date | date-fns (id, en-US, ms locales) |
| PWA | vite-plugin-pwa (Workbox) |
| Barcode | html5-qrcode (camera scanner + manual input) |
| Receipt | html2canvas (to PNG), Web Bluetooth Print (PWA), Bluetooth Classic (Android APK via Capacitor) |
| Font | Plus Jakarta Sans |
| Native Wrapper | Capacitor 8 (Android) |
# Clone the repository
git clone https://github.com/user/kasirgratisan.git
cd kasirgratisan
# Install dependencies
npm install
# Start the development server
npm run devThe app will be running at http://localhost:8080.
npm run build
npm run previewThis project can also run as a native Android app using Capacitor while keeping the PWA/web version working from the same codebase.
Requirements:
- Android Studio installed
- Android SDK configured
- JDK 21 (Android Studio bundled JBR works)
macOS / Linux:
export JAVA_HOME="/Applications/Android Studio.app/Contents/jbr/Contents/Home"Windows (PowerShell):
$env:JAVA_HOME = "C:\Program Files\Android\Android Studio\jbr"Adjust the path if your Android Studio is installed elsewhere.
npm run build
npx cap sync android
cd android
./gradlew assembleDebugOutput: android/app/build/outputs/apk/debug/app-debug.apk
npm run build
npx cap sync android
cd android
./gradlew bundleReleaseOutput: android/app/build/outputs/bundle/release/app-release.aab
The release AAB must be signed before uploading to Google Play. See Android signing docs.
npm run cap:sync # build web bundle and sync Capacitor
npm run cap:android # build, sync, then open Android Studio
npm run cap:run # build, sync, then run on connected Android device/emulatorsrc/
βββ App.tsx # Root component & routing
βββ main.tsx # Entry point
βββ index.css # Design tokens (HSL CSS variables)
βββ lib/
β βββ db.ts # Dexie database schema, interfaces, seed data
β βββ auth.ts # Multi-user auth helpers (PIN hashing, sessions, validation)
β βββ utils.ts # Utility functions (cn, etc.)
β βββ image-utils.ts # Image compression utility
β βββ version-check.ts # Version check webhook
βββ components/
β βββ layout/
β β βββ AppLayout.tsx # Main layout (responsive: max-w-lg mobile, max-w-6xl tablet/landscape)
β β βββ BottomNav.tsx # Bottom nav (5 tabs, center cashier CTA)
β βββ Onboarding.tsx # First-run tutorial & store setup
β βββ LoginScreen.tsx # Multi-user login (username + PIN)
β βββ LockedPage.tsx # Permission-gated route fallback
β βββ NavLink.tsx # Permission-aware nav link
β βββ BackupReminder.tsx # Backup reminder & export utility
β βββ Receipt.tsx # Receipt component (view, download, share, Bluetooth print)
β βββ BarcodeScanner.tsx # Barcode/QR scanner with PWA-aware permission handling
β βββ ThemeColorPicker.tsx # Accent color picker (8 presets)
β βββ LanguageSwitcher.tsx # Language picker (ID, EN, MS)
β βββ ui/ # shadcn/ui components (40+)
βββ i18n/
β βββ index.ts # i18next initialization
β βββ locales/
β βββ id/ # Bahasa Indonesia
β βββ en/ # English
β βββ ms/ # Bahasa Malaysia
βββ pages/
β βββ Dashboard.tsx # Home: stats, quick actions, low stock alerts
β βββ Cashier.tsx # POS / cashier (barcode scan input, camera scanner, side-by-side cart on landscape)
β βββ Products.tsx # Product CRUD (with description, SKU, units, photos)
β βββ Reports.tsx # Sales reports & charts
β βββ Settings.tsx # Settings (store, payments, categories, units, theme, backup, install PWA)
β βββ Users.tsx # Multi-user management (owner only)
β βββ Supplier.tsx # Supplier CRUD
β βββ StockIn.tsx # Stock in + COGS calculation
β βββ StockOut.tsx # Stock out
β βββ StockReport.tsx # Stock movement reports
β βββ TransactionHistory.tsx # Transaction history with open bill filter tabs
β βββ NotFound.tsx # 404 page
βββ hooks/
βββ use-auth.tsx # Multi-user auth context (current user, permissions, login/logout)
βββ use-pwa-install.ts # PWA install prompt + standalone detection (incl. iOS)
βββ use-theme-color.ts # Accent color persistence
βββ use-mobile.tsx # Mobile breakpoint detection
βββ use-toast.ts # Toast helper
All data is stored locally in the browser using IndexedDB (via Dexie.js). No data is ever sent to any server.
| Table | Description |
|---|---|
users |
Multi-user accounts (owner/staff role, hashed PIN, granular permissions) |
categories |
Product categories (name, color, icon) |
products |
Master products (name, SKU, sell price, COGS, stock, unit, description) |
units |
Master units of measurement |
suppliers |
Supplier data |
stockIns |
Stock-in records |
stockOuts |
Stock-out records |
hppHistory |
COGS change audit trail |
paymentMethods |
Payment methods (Cash, Bank Transfer, QRIS, etc.) |
transactions |
Sales transactions (status: open/completed, customer name, table number, remarks) |
transactionItems |
Individual items within each transaction (per-item notes & discount) |
storeSettings |
Store settings & app state (incl. multi-user toggle) |
When stock is received, COGS is automatically recalculated:
New COGS = ((Old Stock Γ Old COGS) + (New Qty Γ Buy Price)) / (Old Stock + New Qty)
Got suggestions, feature ideas, or found a bug? Submit and vote on our board:
Join the Telegram group to discuss the app, ask questions, and share tips with other users:
π t.me/kasirgratisan
FreeKasir is proudly supported by:
Want to sponsor FreeKasir and have your logo featured here? Reach out at sponsorship@freekasir.com.
FreeKasir is built and maintained for free. If you find it useful, you can buy the developer a coffee to support continued development:
π traktir.jipraks.com
Contributions are welcome! Here's how:
- Fork this repository
- Create a feature branch (
git checkout -b feature/new-feature) - Commit your changes (
git commit -m 'Add new feature') - Push to the branch (
git push origin feature/new-feature) - Open a Pull Request
- UI text uses i18next β add new strings to
src/i18n/locales/{id,en,ms}/JSON files inside the appropriate namespace (common,settings,products,reports,dashboard,onboarding) - Use
useTranslation('namespace')hook andt('key')in components - Currency and number formatting should be locale-aware using
i18n.languageandNUMBER_LOCALES/CURRENCY_SYMBOLmaps - Date formatting should use
date-fnswith locale fromLOCALESmap - Use existing
shadcn/uicomponents fromsrc/components/ui/ - All monetary values are stored as numbers representing Indonesian Rupiah (no decimals)
- Format numbers using
toLocaleString('id-ID') - New features must work fully offline (no API calls)
- Use
useLiveQuery()fromdexie-react-hooksfor reactive data binding - Gate sensitive UI/actions with the
can()helper fromuseAuth()when multi-user is enabled
Built with β€οΈ for Indonesian small businesses.