A Point of Sale system built with SvelteKit, Svelte 5, and LocalStorage. Suitable for small businesses accepting both Fiat and Bitcoin payments via Lightning Network with OpenPleb integration. Enables merchants to receive fiat payments for Bitcoin transactions via peer-to-peer matching offers.
- Bitcoin Payments for Fiat - Customers can pay with Bitcoin, and the merchant receives fiat when a taker who want to earn Bitcoin accepts the offer
- Fiat on-chain Transfer - Merchant receives fiat directly when taker accepts the offer
- Cashu Bond Time-Lock Protection - Merchant protected with NUT-11 time-locked bonds
- Automatic Bitcoin Conversion - Convert bonds back to BTC if no taker arrives
- Secure client-side authentication with LocalStorage
- Cookie-based token storage (24-hour expiry)
- SSR-compatible route protection
- Session management and auto-expiry
- Default credentials:
user/password
- Today's sales overview with totals
- Transaction statistics and charts
- Recent transaction history feed
- Bitcoin exchange rate display (configurable)
- Pending transaction tracking
- Sales by payment method breakdown
- Add products to cart with one click
- Multiple payment methods (Cash, PromptPay, Lightning, LNURL, Cashu)
- Real-time cart total calculation
- Quick checkout with invoice generation
- Multi-line items support for complex orders
- Create, edit, and delete products
- Stock management (on/off toggle)
- Sequential product IDs (00001, 00002, ...)
- Product categories with emoji icons
- Custom product images
- Category-based product organization
- View all transactions with full details
- Filter by payment method (Cash, PromptPay, Lightning, LNURL, Cashu)
- Filter by status (Success, Pending, Failed)
- Transaction details with timestamps
- Invoice and memo details for Lightning payments
- Search and filter functionality
- Fully responsive design (mobile + desktop)
- Dark/Light theme toggle
- English localization
- Modern, clean UI with Tailwind CSS
- Smooth animations and transitions
- Intuitive navigation
| Technology | Version |
|---|---|
| SvelteKit | 2.x |
| Svelte | 5.x |
| TypeScript | 5.x |
| Tailwind CSS | 3.x |
| Vite | 7.x |
| LocalStorage API | Native |
All data is persisted in the browser's LocalStorage, making the application:
- Offline-capable - Works without internet once loaded
- Privacy-focused - No backend database required
- Fast - Instant load and data access
- No server maintenance - No database to manage
{
id: string // Sequential: 00001, 00002, ...
name: string
price: number
category: string
image?: string
stock: number // 1 = in stock, 0 = out of stock
createdAt: string
}{
id: string
items: TransactionItem[]
total: number
paymentMethod: 'cash' | 'promptpay' | 'lnurl' | 'cashu' | 'lightning'
status: 'paid' | 'pending' | 'failed'
invoice?: string // Lightning invoice
memo?: string // Payment memo
paidAt?: string
createdAt: string
}{
lightningAddress?: string // Your lightning@address
openPlebApiKey?: string // For Bitcoin price updates
cashuMint?: string // Cashu mint URL
currency?: 'sat' | 'btc' // Price display currency
taxRate?: number // Tax percentage (optional)
}// Cookie: lnwpos_user
{
id: string
email: string
passwordHash: string
createdAt: string
}
// Cookie: lnwpos_token
value: "username.timestamp" // 24-hour expiry-
Clone the repository
git clone https://github.com/pruks-dev/lnwPOS.git cd lnwPOS -
Install dependencies
npm install
-
Run development server
npm run dev
-
Open in browser
http://localhost:5173
-
Login with default credentials
- Email:
user - Password:
password
- Email:
-
(Optional) Add products via Products page
- Click "Add Product" to create new products
- Configure categories and pricing
- Set stock availability
- Navigate to POS page
- Click products to add to cart (supports multiple quantities)
- Select payment method (Cash/PromptPay/Lightning/LNURL/Cashu)
- Click "Checkout" button
- Confirm payment
- Transaction is saved to LocalStorage immediately
- Navigate to Products page
- Click "Add Product" to create new product
- Click product to toggle stock status (on/off)
- Click edit icon to modify product details
- Click delete icon to remove product
- Product ID auto-generates sequentially
- Navigate to Transactions page
- Filter by payment method (Cash, PromptPay, Lightning, LNURL, Cashu)
- Filter by status (Paid, Pending, Failed)
- View transaction details with items, totals, and timestamps
- Navigate to Settings page
- Configure Lightning address for price updates
- Set Cashu mint URL for Cashu payments
- Choose currency (satoshi or BTC)
- Optionally configure tax rate
The application uses a secure client-side authentication system with SSR protection:
- Login: POST to
/api/auth/login - Logout: POST to
/api/auth/logout - Token Storage: Cookies (not LocalStorage) - SSR-safe
- Token Format:
username.timestamp - Expiration: 24 hours (configurable)
- Password Hashing: Simple hash function (TODO: upgrade to bcrypt/argon2)
- Token automatically expires after 24 hours
- User is logged out after token expiration
- Session persists across page refreshes within token validity
- SSR-safe route protection prevents unauthorized access
- LNURL Support - Lightning Network URL for payments
- Cashu Integration - Decentralized micro-credentials (unspent tokens)
- Accept Bitcoin for Fiat - Customer pays with Bitcoin, merchant receives fiat when taker accepts the offer
- Cashu Bond Protection - NUT-11 time-locked bonds protect merchants
- Real-Time Pricing - Automatic Bitcoin price updates via OpenPleb API
- Status Tracking - Support for
paid,pending,failedstates
- Accept cash payments directly
- No verification needed
- Status:
paid - Simple and instant
- QR code for customer payment
- Shop PromptPay ID configured in Settings
- Status:
paid
lnwpos_products- All products datalnwpos_transactions- All transactions datalnwpos_settings- Application settingslnwpos_user- Current user sessionlnwpos_token- Authentication tokenlnwpos_next_id- Next sequential product ID
- β Chrome/Edge (latest)
- β Firefox (latest)
- β Safari (latest)
- β Mobile browsers (iOS Safari, Chrome Mobile)
- β Desktop browsers (Chrome, Firefox, Safari, Edge)
Note: LocalStorage-based storage requires JavaScript to be enabled.
npm run build
npm run previewnpm run build # Validates TypeScript types- Use
npm run devfor hot reload development npm run checkvalidates Svelte components- Data persists in browser during development
- Client-side only - No server-side validation
- LocalStorage - Susceptible to browser extensions attacks
- Password hashing - Simple hash
- No CSRF protection - CSRF tokens not implemented
- No rate limiting - No API rate limiting
- β Small businesses and sole proprietorships
- β Testing and prototyping
- β Teaching and learning
- LocalStorage layer (products, transactions, users, settings)
- Client-side authentication with cookie tokens
- POS with cart and multi-item support
- Product management (CRUD operations)
- Transaction history with filters
- Dashboard with analytics
- Dark/Light theme toggle
- Responsive design (mobile + desktop)
- Lightning integration (LNURL + OpenPleb API)
- Receipt generation (print/export)
- Inventory alerts (low stock notifications)
- Data backup and export features
- Multiple currency support
- Advanced cart management (quantities, modifiers, discounts)
- Receipt generation (print/export PDF/QR)
- Inventory alerts (low stock notifications)
- Data backup and export (JSON/CSV)
- Multi-device sync
- User management system
- POS hardware support (thermal printer)
LnwPoS integrates with OpenPleb to facilitate instant fiat-on-ramp transactions via Lightning Network. This allows customers to pay with Bitcoin while the merchant receives fiat directly.
The integration follows a peer-to-peer matching offer flow:
1. Order & Request Offer
βββββββββββββββββββ
β POS requests β β OpenPleb: Create offer (bitcoin + fiat price)
β offer with β
β bitcoin amount β β Return LN invoice for payment
β + fiat price β
ββββββββββ¬βββββββββ
β
βΌ
2. Display QR Code
βββββββββββββββββββ
β Show LN invoice β β Customer scans & pays with Lightning
β QR code β
ββββββββββ¬βββββββββ
β
βΌ
3. Payment Confirmed + Bond Assigned
βββββββββββββββββββ
β OpenPleb β β Offer confirmed, bond assigned
β creates offer β
β + sends bond β
ββββββββββ¬βββββββββ
β
βΌ
4. Two Possible Outcomes
β
ββββββββββββββββββ
βΌ βΌ
ββββββββββββββββββ βββββββββββββββ
β Case A: No β β Case B: β
β Taker β β Taker β
β β β Arrives β
β Timeout β β β
β 7 days β β Taker β
β β β pays fiat β
ββββββββ¬ββββββββββ ββββββββ¬βββββββ
β β
βΌ βΌ
ββββββββββββββββββ βββββββββββββββ
β POS redeems β β Bond β
β bond token β β rejected β
β to get BTC β β in list β
β (time locked β β (cannot β
β NUT-11) β β redeem) β
ββββββββββββββββββ βββββββββββββββ
Step 1: Request Offer
- POS generates order with
bitcoin_amountandfiat_price - OpenPleb creates a sell order (maker) and returns:
- Lightning Network invoice for the bitcoin amount
- Cashu bond token (p2pk time-locked, NUT-11)
Step 2: Payment
- Customer scans QR code and pays via Lightning Network
- Payment is confirmed on the Lightning Network
Step 3: Offer Confirmed
- OpenPleb confirms the offer and declares it as "completed"
- POS status updates to
pending(waiting for taker) - OpenPleb assigns a Cashu bond token to the POS
Step 4a: No Taker (Timeout)
- If no taker arrives within the time lock period:
- User (merchant) can redeem the bond token themselves
- Bond has a default time lock of 7 days (configurable)
- Token can be redeemed with the configured cashu mint
- Redeeming converts the bond back to Bitcoin
Step 4b: Taker Arrives
- If a taker accepts the offer:
- The bond is immediately rejected/removed from the list
- Taker transfers fiat directly to the merchant
- Merchant receives fiat without needing the bond
- Default Time Lock: 7 days (configurable in settings)
- Bond Type: Cashu token with p2pk time lock (NUT-11 specification)
- Redemption: User/POS redeems token with configured cashu mint
- Fiat Transfer: Happens directly between merchant and taker (off-chain)
- Instant Fiat: Customer pays with Bitcoin, merchant gets fiat via peer payment
- Peer-to-peer: No need for centralized fiat on-ramp services
- Time-Lock Protection: Merchant is protected if taker doesn't arrive
- Auto-Convert: If no taker, bond automatically converts to BTC
Required settings in Settings page:
- Lightning Address: Your lightning@address (for OpenPleb)
- OpenPleb API Key: For connecting to OpenPleb API
- Cashu Mint URL: Your configured cashu mint for redemption
- Time Lock: Bond expiration time (default: 7 days)
Contributions are welcome! Please feel free to submit a Pull Request.
MIT License - Feel free to use this project for personal or commercial purposes.
Built with β€οΈ using:
Made with Bitcoin β‘