A full-featured Progressive Web App for field merchandisers to conduct inventory counts and damage reporting โ fully capable without an internet connection.
The AcaciaHBC Inventory System is a mobile-optimised PWA that guides merchandisers through a structured three-step count workflow โ from session setup through to a formatted Excel export.
As a client-side PWA, the application's security model is scoped to the device. The following measures are in place.
| Measure | Status | Detail |
|---|---|---|
| Data Storage | localStorage | All session data (inventory, damages, settings) is stored exclusively in the device's localStorage. Nothing is transmitted to a server. Data stays on-device at all times. |
| No Authentication | By Design | The app has no login. Access is controlled by who has the PWA installed. This is appropriate for single-user field devices. If multi-user access is required, authentication should be added. |
| Input Validation | โ Active | All user inputs are validated client-side. Quantities must be positive whole integers. Damage notes are required fields. Empty or invalid inputs are rejected with toast notifications before any data is written. |
| XSS Surface | โ Low Risk | Product and location data is loaded from controlled JSON files (not user-supplied URLs). Dynamic HTML uses textContent for user-supplied strings, limiting injection vectors. Search/display relies on template literals for catalogue data only. |
| External Dependencies | 2 Libraries | SheetJS (xlsx 0.18.5) and ExcelJS (4.3.0) are loaded from Cloudflare CDN via HTTPS. These are well-maintained, widely-used libraries. Pinning to specific versions reduces supply-chain risk. |
| Data Lifecycle | โ Auto-Cleared | Count data is automatically deleted 20 days after the last export. The timer resets on each successful XLSX export. This limits the window of exposure for stale data persisting on a lost or shared device. |
| No Cloud Sync | By Design | There is no cloud database, API endpoint, or analytics tracker in the current build. All data egress is user-initiated (manual file download or share). No telemetry is collected. |
| Service Worker Scope | Registered | A service worker is registered for offline/PWA functionality (sw.js). The scope and caching strategy are defined in the separate sw.js file, not visible in the HTML alone. This should be audited separately. |
| File Export Safety | โ Local Blob | XLSX files are generated in-memory as a Blob and downloaded via a temporary object URL, which is revoked after 5 seconds. No file is uploaded to any external server. |
Service workers and the Web Share API require a secure HTTPS origin. The app must be served over HTTPS in production for PWA features and sharing to function. Running over HTTP will silently disable these capabilities.
The app produces a structured Excel workbook delivered directly to the device โ no email, no server, no intermediary step required.
Lists every counted SKU with row number, location, category, barcode/SKU, product name, and quantity counted. Rows are sorted by category alphabetically. A bold totals row at the foot summarises total line items and total units counted. Report header rows include merchandiser name, store, count period, and export timestamp.
A separate worksheet listing all damage entries: location, category, SKU, product name, quantity damaged, and the merchandiser's damage description. If no damages were recorded, the sheet notes this explicitly. Totals rows summarise the number of damage lines and total units damaged.
Each export is automatically named using the format IC_[Location]_[DD][Mon][YYYY]_[HHMM].xlsx โ for example, IC_CapeTown_26Mar2026_1430.xlsx. Special characters in location names are stripped to ensure cross-platform file system compatibility.
The file is downloaded directly to the device's default downloads folder. On mobile browsers that support the Web Share API (iOS Safari, Android Chrome), an additional Share button appears, allowing the file to be sent immediately via Messenger, email, Teams, or any installed share target.
The app is built offline-first. Merchandisers working in stores with poor or no signal can complete a full count session and export a report without any network access.
Adding products, logging quantities, recording damage notes โ the entire data-entry workflow functions without a network connection. All data writes to localStorage instantly.
Closing the browser or losing power does not lose data. localStorage persists across sessions on the same device, so a count can be resumed the next day without losing earlier entries.
The Excel file is built entirely in-browser using client-side libraries. No network call is made during export. The file can be generated and downloaded while fully offline.
Once installed as a PWA, the app shell can be cached by the service worker, allowing it to launch without a network connection, even on first open after installation.
On first load, the app fetches products.json, locations.json, and system-count.json. If these are not cached by the service worker, an offline launch may result in an empty product list.
Sharing the exported file via Messenger or email requires the receiving app to have network access. The file itself is available offline; delivering it to a recipient requires connectivity at time of share.
Instruct merchandisers to open the app once while connected to Wi-Fi before heading to a store. This ensures the service worker caches all JSON data and the app shell, making the session fully offline-capable.
The PWA registers an external sw.js service worker. The caching strategy (Network-First, Cache-First, or Stale-While-Revalidate) is defined in that file and should be configured to pre-cache products.json, locations.json, and system-count.json for guaranteed offline access.