The Mini POS System is built as a Progressive Web App (PWA), allowing it to be installed on devices and work offline. This guide covers PWA configuration and customization.
Understanding the PWA Structure
The PWA consists of three key components:
- Manifest file (
manifest.json) - App metadata and appearance
- Service Worker (
sw.js) - Offline functionality and caching
- Installation handler (
js/shared.js) - Install prompt logic
Manifest Configuration
The manifest.json File
Located at the root directory, this file defines your PWA’s identity:
{
"name": "Mini POS System",
"short_name": "Mini POS",
"start_url": "./index.html",
"display": "standalone",
"background_color": "#ffffff",
"theme_color": "#4f46e5",
"description": "Offline Point of Sale System",
"icons": [
{
"src": "icons/icon-192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "icons/icon-512.png",
"sizes": "512x512",
"type": "image/png"
}
]
}
Manifest Properties Explained
Name fields
"name": "Mini POS System",
"short_name": "Mini POS"
- name: Full app name (shown during installation and in app switcher)
- short_name: Abbreviated name (shown on home screen, limited space)
- Keep
short_name under 12 characters for best display
Display mode
Options:
- standalone: App-like, hides browser UI
- fullscreen: Full screen, hides all UI
- minimal-ui: Minimal browser UI (back/forward buttons)
- browser: Normal browser view
Recommended: standalone for POS applications Colors
"background_color": "#ffffff",
"theme_color": "#4f46e5"
- background_color: Splash screen background while app loads
- theme_color: Browser UI color (address bar, task switcher)
Must match <meta name="theme-color"> in HTML filesStart URL
"start_url": "./index.html"
The page that opens when the app launches. Use:
"./index.html" - Dashboard
"./pos.html" - Direct to POS
"./?source=pwa" - Track PWA launches
The manifest is referenced in index.html:8 with <link rel="manifest" href="manifest.json" />
App Icons
Required Icon Sizes
PWAs need multiple icon sizes for different contexts:
| Size | Purpose | File Path |
|---|
| 192×192 | Android home screen, small displays | icons/icon-192.png |
| 512×512 | Splash screens, high-res displays | icons/icon-512.png |
| 32×32 | Favicon | icons/favicon.ico |
Creating PWA Icons
Design your icon
- Use a square canvas (512×512 or higher)
- Include padding (10% margin recommended)
- Avoid text that becomes illegible when scaled
- Use high contrast colors
- Test at multiple sizes
Generate multiple sizes
From your 512×512 master icon, create:# Using ImageMagick
convert icon-512.png -resize 192x192 icon-192.png
convert icon-512.png -resize 32x32 favicon.ico
Or use online tools: Add to manifest.json
"icons": [
{
"src": "icons/icon-192.png",
"sizes": "192x192",
"type": "image/png",
"purpose": "any maskable"
},
{
"src": "icons/icon-512.png",
"sizes": "512x512",
"type": "image/png",
"purpose": "any maskable"
}
]
The purpose: "any maskable" allows adaptive icons on Android.Update HTML references
In all HTML files (lines 7-10):<link rel="shortcut icon" href="icons/favicon.ico" type="image/x-icon">
<link rel="icon" href="icons/icon-192.png" />
<link rel="apple-touch-icon" href="icons/icon-192.png" />
iOS requires apple-touch-icon to be 180×180 or larger. The 192×192 icon works but you may want a dedicated iOS icon.
Service Worker Setup
How the Service Worker Works
The service worker (sw.js) enables offline functionality by caching assets.
// Cache version - increment to force updates
const CACHE = 'mini-pos-v2';
// Files to cache for offline use
const ASSETS = [
'./',
'./index.html',
'./products.html',
'./pos.html',
'./reports.html',
'./manifest.json',
'./css/style.css',
'./js/db.js',
'./js/shared.js',
'./js/dashboard.js',
'./js/products.js',
'./js/pos.js',
'./js/reports.js',
'./icons/icon-192.png',
'./icons/icon-512.png'
];
Service Worker Lifecycle
Install phase (sw.js:23-37)
self.addEventListener('install', (event) => {
event.waitUntil(
caches.open(CACHE).then((cache) =>
Promise.allSettled(
ASSETS.map((asset) => cache.add(asset).catch(() => {}))
)
)
);
self.skipWaiting();
});
Caches all specified assets when the service worker installs.Activate phase (sw.js:39-48)
self.addEventListener('activate', (event) => {
event.waitUntil(
caches.keys().then((keys) =>
Promise.all(
keys.filter((k) => k !== CACHE).map((k) => caches.delete(k))
)
)
);
self.clients.claim();
});
Removes old caches when a new version activates.Fetch phase (sw.js:50-66)
self.addEventListener('fetch', (event) => {
const req = event.request;
if (req.method !== 'GET') return;
event.respondWith(
caches.match(req).then((hit) => {
if (hit) return hit;
return fetch(req)
.then((res) => {
const resClone = res.clone();
caches.open(CACHE).then((cache) => cache.put(req, resClone));
return res;
})
.catch(() => caches.match('./index.html'));
})
);
});
Serves cached content when available, falls back to network, or shows index.html if offline.
Updating the Service Worker
When you make changes to your app:
Increment cache version
const CACHE = 'mini-pos-v3'; // Change v2 to v3
This forces browsers to download new assets.Add new files to ASSETS array
If you added new pages or resources:const ASSETS = [
// ... existing files ...
'./new-page.html',
'./js/new-script.js'
];
Test the update
- Make changes and increment cache version
- Deploy or refresh your local server
- Open DevTools → Application → Service Workers
- Click “Update” or hard refresh (Ctrl+Shift+R)
- Verify new service worker activates
Use Chrome DevTools → Application → Storage → Clear site data to fully reset the PWA during development.
Service Worker Registration
The service worker is registered in js/shared.js:20-26:
if ('serviceWorker' in navigator) {
window.addEventListener('load', () => {
navigator.serviceWorker.register('./sw.js', { scope: './' })
.catch(console.error);
});
}
This runs on every page load and registers the service worker.
Service workers only work over HTTPS (or localhost for development).
Installation Experience
The app includes an install button that appears when the browser supports PWA installation:
let deferredPrompt;
window.addEventListener('beforeinstallprompt', (e) => {
e.preventDefault();
deferredPrompt = e;
const installBtn = document.getElementById('installBtn');
if (installBtn) {
installBtn.classList.remove('hidden');
installBtn.addEventListener('click', async () => {
if (!deferredPrompt) return;
deferredPrompt.prompt();
await deferredPrompt.userChoice;
deferredPrompt = null;
installBtn.classList.add('hidden');
});
}
});
The button is defined in index.html:26:
<button id="installBtn" class="hidden px-4 py-2 bg-indigo-600 text-white rounded-lg text-sm font-medium hover:bg-indigo-700">
Install App
</button>
Customize install button
Modify the button text, style, or position:<button id="installBtn" class="hidden px-4 py-2 bg-green-600 text-white rounded-lg hover:bg-green-700">
📱 Install Mini POS
</button>
Change button placement
The button appears in the header. Move it to a different location:<!-- In a prominent banner -->
<div class="bg-blue-50 border-b border-blue-200 p-4 text-center">
<button id="installBtn" class="hidden">Install for offline access</button>
</div>
The beforeinstallprompt event is browser-specific. It works in Chrome/Edge but not Safari. Safari users must manually “Add to Home Screen”.
Android (Chrome)
- Visit the app URL
- Click “Install App” button (or menu → Install app)
- App appears on home screen
- Opens in standalone mode
iOS (Safari)
Manual installation required
iOS doesn’t support the install prompt. Users must:
- Tap the Share button
- Select “Add to Home Screen”
- Confirm the name and tap “Add”
Add iOS instructions
Consider adding an iOS-specific prompt:<div id="iosPrompt" class="hidden bg-blue-50 p-4">
<p>📱 Install this app: Tap Share → Add to Home Screen</p>
</div>
<script>
if (/iPad|iPhone|iPod/.test(navigator.userAgent) && !window.navigator.standalone) {
document.getElementById('iosPrompt').classList.remove('hidden');
}
</script>
Desktop (Chrome/Edge)
- Visit the app URL
- Look for install icon in address bar
- Or click “Install App” button
- App opens as a standalone window
Desktop PWAs appear in the Start menu/Applications folder and can be launched like native apps.
Testing Your PWA
Run Lighthouse
- Open Chrome DevTools (F12)
- Go to “Lighthouse” tab
- Select “Progressive Web App”
- Click “Analyze page load”
Check PWA requirements
Lighthouse verifies:
- ✅ HTTPS or localhost
- ✅ Valid manifest.json
- ✅ Service worker registered
- ✅ Works offline
- ✅ 192×192 and 512×512 icons
- ✅ Theme color configured
Manual Testing Checklist
Advanced PWA Features
Add App Shortcuts
Define quick actions in manifest.json:
{
"shortcuts": [
{
"name": "New Sale",
"short_name": "POS",
"description": "Open POS for new sale",
"url": "./pos.html",
"icons": [{ "src": "icons/pos-shortcut.png", "sizes": "96x96" }]
},
{
"name": "View Reports",
"short_name": "Reports",
"url": "./reports.html",
"icons": [{ "src": "icons/reports-shortcut.png", "sizes": "96x96" }]
}
]
}
Users can long-press the app icon to see these shortcuts.
Add Categories
Help users discover your app in app stores:
{
"categories": ["business", "finance", "productivity"]
}
Add Screenshots
For enhanced install prompts:
{
"screenshots": [
{
"src": "screenshots/dashboard.png",
"sizes": "1280x720",
"type": "image/png"
},
{
"src": "screenshots/pos.png",
"sizes": "1280x720",
"type": "image/png"
}
]
}
Advanced features like shortcuts and screenshots have limited browser support. Test across target platforms.
Troubleshooting
PWA Not Installing
Check HTTPS
PWAs require HTTPS (except on localhost). Verify your site has a valid SSL certificate.
Validate manifest
- Open DevTools → Application → Manifest
- Check for errors or warnings
- Verify all icon paths are correct
Check service worker
- Open DevTools → Application → Service Workers
- Ensure service worker is registered and activated
- Check for errors in the console
Service Worker Not Updating
- Increment cache version in
sw.js
- Hard refresh (Ctrl+Shift+R)
- DevTools → Application → Service Workers → Unregister
- Clear site data and reload
Icons Not Showing
- Verify icon files exist at specified paths
- Check file sizes match manifest declarations
- Ensure icons are PNG format (not JPG or SVG)
- Use absolute paths if relative paths fail:
/icons/icon-192.png
Use PWA Builder to validate your PWA and generate store packages.
Best Practices
- Cache Strategy: The app uses “Cache First” for static assets and “Network First” for dynamic content
- Update Frequency: Increment cache version with every deployment
- Icon Quality: Use vector-based designs that scale well
- Testing: Test installation on multiple devices and browsers
- Offline UX: Show clear messaging when offline (future enhancement)
The Mini POS System’s IndexedDB storage works seamlessly offline, making it a true offline-first application.