kasirgratisan
Free, Open Source, Offline Point of Sales Apps
Free, Open Source, Offline Point of Sales Apps
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.
| 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 dev
The app will be running at http://localhost:8080.
npm run build
npm run preview
This project can also run as a native Android app using Capacitor while keeping the PWA/web version working from the same codebase.
Requirements:
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 assembleDebug
Output: android/app/build/outputs/apk/debug/app-debug.apk
npm run build
npx cap sync android
cd android
./gradlew bundleRelease
Output: 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/emulator
src/
├── 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:
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:
Contributions are welcome! Here's how:
git checkout -b feature/new-feature)git commit -m 'Add new feature')git push origin feature/new-feature)src/i18n/locales/{id,en,ms}/ JSON files inside the appropriate namespace (common, settings, products, reports, dashboard, onboarding)useTranslation('namespace') hook and t('key') in componentsi18n.language and NUMBER_LOCALES / CURRENCY_SYMBOL mapsdate-fns with locale from LOCALES mapshadcn/ui components from src/components/ui/toLocaleString('id-ID')useLiveQuery() from dexie-react-hooks for reactive data bindingcan() helper from useAuth() when multi-user is enabledBuilt with ❤️ for Indonesian small businesses.