A comprehensive offline-first Progressive Web App (PWA) for small businesses to manage products, create GST invoices, track customers, generate reports, and share invoices via WhatsApp.
- Architecture Overview
- Technology Stack
- Application Flow
- Security Implementation
- PDF Sharing & WhatsApp Integration
- Authentication & Session Management
- Database Architecture
- File Structure
- Key Features
- Security Features
- Development Setup
- Environment Variables
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Client (Browser) β
β ββββββββββββββββ ββββββββββββββββ ββββββββββββββββ β
β β React UI β β IndexedDB β β Service β β
β β Components β β (Dexie) β β Worker β β
β ββββββββββββββββ ββββββββββββββββ ββββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
β HTTPS
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Next.js Server β
β ββββββββββββββββ ββββββββββββββββ ββββββββββββββββ β
β β API Routes β β Middleware β β Supabase β β
β β β β (Auth) β β Client β β
β ββββββββββββββββ ββββββββββββββββ ββββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
β
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β External Services β
β ββββββββββββββββ ββββββββββββββββ ββββββββββββββββ β
β β Supabase β β Firebase β β WhatsApp β β
β β (Backend) β β (Admin) β β Web API β β
β ββββββββββββββββ ββββββββββββββββ ββββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
- Offline-First: All data is stored locally in IndexedDB, enabling full functionality without internet
- Progressive Web App: Installable, works offline, uses service workers
- Dual Database Mode: Supports both IndexedDB (offline) and Supabase (online sync)
- Secure Session Management: Cryptographic signatures prevent session tampering
- License-Based Access: Device-bound licensing system
- Framework: Next.js 16 (App Router)
- UI Library: React 19
- Styling: Tailwind CSS 4
- Components: Radix UI, shadcn/ui
- State Management: React Query (TanStack Query)
- Forms: React Hook Form + Zod validation
- Primary Database: IndexedDB (Dexie.js) - Client-side
- Cloud Database: Supabase (PostgreSQL)
- Authentication: Supabase Auth + Custom offline auth
- File Storage: Supabase Storage
- Library: jsPDF + jsPDF-AutoTable
- Format: Invoice slip PDFs for WhatsApp sharing
- Excel: xlsx (for Excel mode)
- Cryptography: crypto-js (HMAC signatures)
- Charts: Recharts
- Date: date-fns
User Opens App
β
βΌ
βββββββββββββββββββ
β LicenseGuard β β Check License Validity
βββββββββββββββββββ
β
βΌ
βββββββββββββββββββ
β AuthGuard β β Check Session Validity
βββββββββββββββββββ
β
βΌ
βββββββββββββββββββ
β Service Worker β β Register for Offline Support
βββββββββββββββββββ
β
βΌ
βββββββββββββββββββ
β Main App UI β β Render Dashboard/Login
βββββββββββββββββββ
User Enters Credentials
β
βΌ
βββββββββββββββββββββββββββ
β Supabase Auth (Online) β
β OR β
β Offline Auth (IndexedDB)β
βββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββ
β Create Secure Session β
β - Generate HMAC β
β - Set Expiry Time β
β - Store in IndexedDB β
βββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββ
β Redirect to Dashboard β
βββββββββββββββββββββββββββ
Employee Enters Credentials
β
βΌ
βββββββββββββββββββββββββββ
β Validate Employee ID β
β & Password (IndexedDB) β
βββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββ
β Create Employee Sessionβ
β - Store in localStorageβ
β - Link to Store β
βββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββ
β Redirect to Dashboard β
βββββββββββββββββββββββββββ
User Creates Invoice
β
βΌ
βββββββββββββββββββββββββββ
β Fill Invoice Form β
β - Select Customer β
β - Add Products/Items β
β - Calculate Totals β
βββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββ
β Save to IndexedDB β
β - Invoice Header β
β - Invoice Items β
β - Update Stock β
βββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββ
β Queue for Sync β
β (If Supabase Mode) β
βββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββ
β Generate PDF (Optional)β
β Share on WhatsApp β
βββββββββββββββββββββββββββ
User Clicks "Share PDF"
β
βΌ
βββββββββββββββββββββββββββ
β Fetch Invoice Data β
β from IndexedDB β
βββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββ
β Generate PDF Blob β
β (jsPDF + AutoTable) β
βββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββ
β Web Share API β
β - Create File Object β
β - Open Share Dialog β
βββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββ
β User Selects App β
β (Email, WhatsApp, etc.)β
βββββββββββββββββββββββββββ
User Clicks "Share on WhatsApp"
β
βΌ
βββββββββββββββββββββββββββ
β Check Internet β
β Connection β
βββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββ
β Generate WhatsApp β
β Message (Formatted) β
βββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββ
β Generate Slip PDF β
β (Compact Format) β
βββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββ
β Download PDF β
β Open WhatsApp Web β
β (wa.me/?text=...) β
βββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββ
β User Attaches PDF β
β Manually in WhatsApp β
βββββββββββββββββββββββββββ
User Clicks Logout
β
βΌ
βββββββββββββββββββββββββββ
β Clear IndexedDB Sessionβ
β - Delete auth_session β
β - Verify Signature β
βββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββ
β Clear localStorage β
β - employeeSession β
β - offlineAdminSession β
β - authType β
βββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββ
β Supabase SignOut β
β (If Online) β
βββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββ
β Redirect to Login β
βββββββββββββββββββββββββββ
The application implements multiple layers of security to prevent session tampering:
Implementation: lib/utils/auth-session.ts
- Every session is signed with HMAC-SHA256 using a secret key
- Signature includes: userId, email, role, storeId, issuedAt, expiresAt
- Any modification to session data invalidates the signature
- Signature is verified on every session read
// Session Structure
{
id: "current_session",
userId: "user-123",
email: "user@example.com",
role: "admin",
storeId: "store-456",
issuedAt: 1234567890,
expiresAt: 1234654290,
signature: "hmac-sha256-hash", // Prevents tampering
lastValidated: 1234567890,
validationCount: 1
}Implementation: app/api/time/route.ts
- Server provides authoritative timestamp
- Client compares server time vs client time
- Detects time manipulation (>5 minute difference)
- Falls back to client time if server unavailable (offline mode)
- Signature Validation: Detects data tampering
- Time Validation: Detects clock manipulation
- Expiry Check: Uses server time when available
- Anomaly Detection: Tracks validation count for suspicious patterns
β Prevents:
- Modifying
expiresAttimestamp in IndexedDB - Changing system time to extend sessions
- Tampering with session data (userId, email, role)
- Replay attacks (signature changes on each validation)
β Detects:
- Invalid signatures β Auto-logout
- Time manipulation β Warning logged
- Suspicious validation patterns β Alert
| Vulnerability | Previous State | Fixed State |
|---|---|---|
| IndexedDB Tampering | β No protection | β HMAC signatures |
| Time Manipulation | β Client time only | β Server time validation |
| Session Replay | β No detection | β Signature validation |
| Data Integrity | β No checks | β Cryptographic verification |
lib/utils/invoice-slip-pdf.ts- Invoice slip PDF (compact format for WhatsApp)lib/utils/invoice-pdf.ts- Full invoice PDF (A4 format)lib/utils/pdf-generator.ts- Shared InvoiceData interface
-
Data Collection:
- Invoice header (number, date, customer)
- Invoice items (description, quantity, price, GST)
- Totals (subtotal, CGST, SGST, IGST, total)
- Business information (name, GSTIN, address)
-
PDF Creation:
- Uses jsPDF library
- AutoTable plugin for item tables
- Custom styling (colors, fonts, layout)
- Slip format: 80mm x 210mm (receipt-like, for WhatsApp)
- Invoice format: A4 size (full invoice)
-
Output:
- Returns Blob object
- Can be downloaded or shared
Location: app/(dashboard)/invoices/[id]/page-client.tsx
Flow:
- Fetches invoice data from IndexedDB (no Supabase dependency)
- Generates PDF using
generateInvoiceSlipPDF() - Creates File object from PDF Blob
- Uses Web Share API (
navigator.share()) - User selects sharing app (Email, WhatsApp, etc.)
Features:
- β Works offline (uses IndexedDB only)
- β No Supabase dependency
- β Generic share (works with any app)
- β Fallback to download if share not supported
Location: components/features/invoices/whatsapp-share-button.tsx
Flow:
- Checks internet connection (required)
- Generates formatted WhatsApp message
- Generates invoice slip PDF
- Downloads PDF automatically
- Opens WhatsApp Web (
https://wa.me/?text=...) - User manually attaches downloaded PDF
Message Format:
π *Invoice Receipt*
πͺ *Store Name*
ββββββββββββββββββββ
π Invoice #INV-001
π
Date: 01/01/2024
ββββββββββββββββββββ
*Items:*
1. Product Name
Qty: 2 Γ βΉ100.00 = βΉ200.00
ββββββββββββββββββββ
π° *Total: βΉ200.00*
ββββββββββββββββββββ
π± View full invoice:
https://app.com/i/invoice-id
Thank you for your business! π
Features:
- β Formatted message with emojis
- β Auto-downloads PDF
- β Opens WhatsApp Web directly
- β Includes invoice link
Location: components/features/invoices/invoice-form.tsx
Flow:
- User fills invoice form
- Clicks "Save & Share on WhatsApp"
- Saves invoice to IndexedDB
- Generates PDF
- Opens WhatsApp with message
- Downloads PDF for attachment
- Table:
auth_session - Structure: See
lib/db/dexie.ts-AuthSessioninterface - Security: HMAC signatures prevent tampering
employeeSession- Employee login dataofflineAdminSession- Offline admin sessionauthType- "employee" or "admin"currentStoreId- Selected store ID
Component: components/auth-guard.tsx
Checks:
- IndexedDB session exists and valid
- Signature verification
- Expiry check (server time)
- Employee session (if applicable)
- Offline admin session (if applicable)
Frequency: Every 5 seconds (periodic check)
- Default Duration: 24 hours (86400000 ms)
- Configurable:
NEXT_PUBLIC_SESSION_DURATION_MSenv variable - Validation: Server time when available, client time as fallback
- Auto-logout: On expiry, redirects to
/auth/session-expired
Files:
app/auth/login/page.tsx- Login page logoutcomponents/layout/sidebar.tsx- Sidebar logout buttoncomponents/layout/header.tsx- Header logout menu
Process:
- Clear IndexedDB session (
clearAuthSession()) - Clear localStorage (employeeSession, offlineAdminSession, etc.)
- Supabase signOut (if online)
- Redirect to login
Database Name: BillingDatabase
Tables:
products- Product catalogcustomers- Customer informationinvoices- Invoice headersinvoice_items- Invoice line itemsemployees- Employee datastores- Store informationsettings- Application settingsauth_session- Authentication sessionssync_queue- Sync queue for Supabaselicense- License informationinventory- Inventory trackingattendance- Employee attendancesales_header- Sales transactionssales_items- Sales line items
Schema Version: 4 (with auth_session support)
Tables: See types/database.types.ts
Sync Strategy:
- Offline-first: All writes go to IndexedDB first
- Background sync: Sync queue processes changes
- Conflict resolution: Last-write-wins
- Sync frequency: Every 30 seconds (when online)
billing-solutions/
βββ app/ # Next.js App Router
β βββ (dashboard)/ # Dashboard routes (protected)
β β βββ invoices/ # Invoice management
β β β βββ [id]/ # Invoice detail page
β β β β βββ page-client.tsx # Share PDF button
β β β βββ new/ # Create invoice
β β βββ products/ # Product management
β β βββ customers/ # Customer management
β β βββ ...
β βββ auth/ # Authentication routes
β β βββ login/ # Login page
β β βββ employee-login/ # Employee login
β β βββ session-expired/ # Session expired page
β βββ api/ # API routes
β β βββ time/ # Server time endpoint
β β βββ invoices/ # Invoice API
β βββ layout.tsx # Root layout
βββ components/
β βββ auth-guard.tsx # Authentication guard
β βββ license-guard.tsx # License validation
β βββ features/
β β βββ invoices/
β β βββ invoice-form.tsx # Invoice creation form
β β βββ invoice-actions.tsx # Invoice actions menu
β β βββ whatsapp-share-button.tsx # WhatsApp share
β βββ layout/
β βββ header.tsx # App header
β βββ sidebar.tsx # Sidebar navigation
βββ lib/
β βββ db/
β β βββ dexie.ts # IndexedDB schema
β βββ utils/
β β βββ auth-session.ts # Secure session management
β β βββ invoice-slip-pdf.ts # PDF slip generation
β β βββ invoice-pdf.ts # PDF invoice generation
β β βββ whatsapp-bill.ts # WhatsApp integration
β β βββ invoice-pdf-sync.ts # PDF sync utilities
β βββ supabase/ # Supabase clients
β βββ hooks/ # Custom React hooks
βββ public/ # Static assets
βββ manifest.json # PWA manifest
βββ sw.js # Service worker
- Create GST/non-GST invoices
- Multiple tax calculations (CGST, SGST, IGST)
- Discount support
- Print/Download PDF
- Share via WhatsApp
- Product catalog with categories
- Stock tracking
- HSN code support
- GST rates per product
- Customer database
- GSTIN tracking
- Contact information
- Purchase history
- Employee login system
- Store-based access
- Attendance tracking
- Role-based permissions
- Sales reports
- Inventory reports
- Tax reports
- Dashboard analytics
- Full offline functionality
- Background sync
- Service worker caching
- IndexedDB storage
-
Session Security
- β HMAC-SHA256 signatures
- β Server time validation
- β Signature verification on every read
- β Auto-logout on tampering detection
-
License Protection
- β Device-bound licensing
- β MAC address binding
- β Expiry validation
- β Revocation support
-
Data Integrity
- β Cryptographic signatures
- β Validation on read/write
- β Anomaly detection
-
Authentication
- β Secure password hashing
- β Session expiry enforcement
- β Multi-factor validation
- β Never trust client-side data alone
- β Always verify signatures
- β Use server time when available
- β Log security events
- β Auto-logout on suspicious activity
- Node.js 18+
- npm or yarn
- Supabase account (optional, for cloud sync)
# Clone repository
git clone <repository-url>
cd billing-solutions
# Install dependencies
npm install
# Set up environment variables
cp .env.example .env.local
# Edit .env.local with your configuration
# Run development server
npm run dev# Supabase (Optional)
NEXT_PUBLIC_SUPABASE_URL=your-supabase-url
NEXT_PUBLIC_SUPABASE_ANON_KEY=your-anon-key
# Session Configuration
NEXT_PUBLIC_SESSION_DURATION_MS=86400000 # 24 hours
NEXT_PUBLIC_SESSION_SECRET=your-secret-key # Change in production!
# Other
NEXT_PUBLIC_APP_URL=http://localhost:3000# Production build
npm run build
# Start production server
npm startNEXT_PUBLIC_SESSION_SECRET- Secret key for HMAC signatures (MUST be changed in production)
NEXT_PUBLIC_SUPABASE_URL- Supabase project URLNEXT_PUBLIC_SUPABASE_ANON_KEY- Supabase anonymous keyNEXT_PUBLIC_SESSION_DURATION_MS- Session duration in milliseconds (default: 86400000)NEXT_PUBLIC_APP_URL- Application URL
Edit NEXT_PUBLIC_SESSION_DURATION_MS in .env.local:
# 1 hour
NEXT_PUBLIC_SESSION_DURATION_MS=3600000
# 12 hours
NEXT_PUBLIC_SESSION_DURATION_MS=43200000
# 24 hours (default)
NEXT_PUBLIC_SESSION_DURATION_MS=86400000The app supports two modes:
- IndexedDB Mode: Fully offline, no Supabase
- Supabase Mode: Online sync with Supabase
Mode is determined automatically based on Supabase configuration.
- Fork the repository
- Create a feature branch
- Make your changes
- Test thoroughly
- Submit a pull request
Proprietary - All rights reserved
For issues or questions:
- Create an issue in the repository
- Contact the development team
Last Updated: 2024 Version: 0.1.0