Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.encoreos.io/llms.txt

Use this file to discover all available pages before exploring further.

Version: 2.1.0
Last Updated: 2026-03-30
Status: ✅ Fully Configured
Complete guide to Progressive Web App (PWA) setup, configuration, and optimization for the Encore Health OS Platform.

Table of Contents

  1. Overview
  2. Current Configuration
  3. Icon Setup
  4. Service Worker Configuration
  5. Performance Optimization
  6. Mobile Safe Area Support
  7. Testing Checklist
  8. Troubleshooting
  9. References

Overview

Encore Health OS is built as a Progressive Web App (PWA) with mobile-first responsive design, advanced caching strategies, and optimized build configuration for maximum performance. Key Features:
  • ✅ Auto-updating service worker
  • ✅ Comprehensive Workbox caching strategies
  • ✅ Raster icons generated from public/favicon.svg (Sharp + png-to-ico)
  • ✅ Update notifications and offline support
  • ✅ Mobile-first PWA features
  • ✅ Unified icon system (Encore hex mark — aligned with public/brand/encore-primary-dark.svg)
Related Documentation:

Current Configuration

Setup Status ✅

PWA setup is fully configured with icons generated from public/favicon.svg via Sharp and committed to public/.
  • ✅ Auto-updating service worker
  • ✅ Comprehensive Workbox caching strategies
  • ✅ PNG + ICO outputs for favicon and install surfaces
  • ✅ Update notifications and offline support
  • ✅ Mobile-first PWA features
  • ✅ Unified icon system (Encore hex mark — aligned with public/brand/encore-primary-dark.svg)

Configuration Files

  • vite.config.ts - VitePWA plugin configuration
  • index.html - Viewport meta tag, apple-touch-icon links
  • src/index.css - Safe area CSS custom properties
  • src/platform/pwa/PwaUpdatePrompt.tsx - Update notification component

Icon Setup

Current icon set

FileSizePurpose
favicon.svg512×512 (vector)Master artwork; matches encore-primary-dark geometry
favicon.png32×32PNG favicon (index.html)
favicon.ico16, 32, 48Multi-size ICO for browsers
pwa-64x64.pngpwa-512x512.pngvariousManifest + index.html
pwa-128x128.png, pwa-256x256.png128, 256Manifest (vite.config.ts)
maskable-icon-512x512.png512×512Android adaptive (purpose: maskable); logo drawn at ~410×410 centered (~20% edge safe zone)
apple-touch-icon-180x180.png180×180iOS home screen

Source asset

  • public/favicon.svg — Master Encore hex mark (512×512 viewBox, rounded square). Design source: public/brand/encore-primary-dark.svg (scale and rounding applied for app-icon use).

Icon generation

From the repository root:
# PWA PNGs, maskable 512, favicon.png (32), favicon.ico (16/32/48)
node scripts/generate-pwa-icons.mjs

# iOS apple-touch icon (180×180) from the same SVG
npx tsx scripts/utils/generate-apple-touch-icon.ts
Dependencies: sharp (rasterization), png-to-ico (ICO file). Regenerate and commit outputs under public/ after changing favicon.svg. Bump the ?v= query on favicon links in index.html if browsers cache aggressively. Maskable icon: maskable-icon-512x512.png uses a 512×512 canvas with the SVG rasterized at 410×410 and composited centered, reserving roughly a 20% edge safe zone for Android adaptive icon masks (see Adaptive icons).

Manifest Configuration

The PWA manifest is configured in vite.config.ts using VitePWA plugin: See vite.config.ts for the live VitePWA block. It includes favicon.ico, favicon.png, apple-touch-icon-180x180.png, and manifest icons (pwa-64x64 through pwa-512x512, plus maskable-icon-512x512.png). theme_color / background_color use Encore navy (#0D2140). Key Points:
  • registerType: "autoUpdate" - Service worker updates automatically
  • Separate any and maskable icons for best platform compatibility
  • iOS home screen icon specified in index.html with <link rel="apple-touch-icon">
  • background_color matches theme_color for consistent branding

HTML References

Update index.html: index.html links favicon.svg, favicon.ico, favicon.png, PWA PNG sizes, and apple-touch-icon-180x180.png with a cache-bust query (e.g. ?v=5). Keep those in sync when regenerating assets.

Icon regeneration

node scripts/generate-pwa-icons.mjs
npx tsx scripts/utils/generate-apple-touch-icon.ts
Commit updated binaries under public/ (and bump ?v= in index.html when needed).

Service Worker Configuration

Auto-Registration (VitePWA)

Encore Health OS uses VitePWA for automatic service worker registration. No manual registration code needed. Current approach:
  • VitePWA handles registration automatically
  • Service worker updates via useRegisterSW() hook from virtual:pwa-register/react

Update Notifications

Component: src/platform/pwa/PwaUpdatePrompt.tsx Uses useRegisterSW() hook to detect when a new service worker is available and shows a toast notification:
import { useRegisterSW } from 'virtual:pwa-register/react';
import { toast } from 'sonner';

export function PwaUpdatePrompt() {
  const {
    needRefresh: [needRefresh, setNeedRefresh],
    updateServiceWorker,
  } = useRegisterSW();

  useEffect(() => {
    if (needRefresh) {
      toast('New version available!', {
        description: 'Click update to get the latest features.',
        action: {
          label: 'Update',
          onClick: () => updateServiceWorker(true),
        },
        duration: Infinity,
      });
    }
  }, [needRefresh, updateServiceWorker]);

  return null;
}
Integration: Component added to src/App.tsx for app-wide update detection.

Performance Optimization

Vite Build Configuration

The project uses manual chunk splitting for optimal caching and load performance: Vendor Chunks:
  • vendor-react: React, ReactDOM, React Router (~150KB)
  • vendor-radix: Radix UI components (~100KB)
  • vendor-query: TanStack Query (~40KB)
  • vendor-supabase: Supabase client (~80KB)
  • vendor-charts: Recharts, D3 (~200KB)
  • vendor-forms: React Hook Form, Zod (~50KB)
  • vendor-pdf: PDF.js libraries (~400KB)
  • vendor-dnd: DnD Kit (~50KB)
  • vendor-flow: XY Flow (~150KB)
Core Module Chunks:
  • core-hr: HR module
  • core-fa: Finance module
  • core-fw: Forms/Workflow module
  • core-rh: Recovery Housing module
  • core-gr: Governance module
  • core-fm: Facilities module
  • core-cl: Clinical module
Platform Module Chunks:
  • platform-documents: Document management
  • platform-reports: Reporting engine
  • platform-forms: Form builder
  • platform-notifications: Notification system
Benefits:
  • Users only download chunks they need
  • Vendor chunks cached long-term (rarely change)
  • Core modules cached per-domain
  • Better cache invalidation (only changed chunks re-downloaded)
  • Initial bundle size reduced by 60-70%

Workbox Caching Strategies

CacheFirst (Long-lived assets):
  • Google Fonts API cache (1 year, 10 entries)
  • Google Fonts webfonts (1 year, 20 entries)
  • Images (30 days, 100 entries) - .png, .jpg, .jpeg, .svg, .gif, .webp
NetworkFirst (Dynamic data):
  • Supabase API calls (5 minute cache, 10s timeout, 50 entries)
Navigation Preload:
  • Enabled for faster page loads
  • Preloads navigation requests while service worker starts

Bundle Analysis

To analyze bundle size and chunk distribution:
npm run build
npx vite-bundle-visualizer
This helps identify large dependencies and optimization opportunities.

Mobile Safe Area Support

CSS Custom Properties

Safe area insets are defined in src/index.css using env() function:
:root {
  /* Safe Area Insets for Modern Mobile Devices */
  --safe-area-inset-top: env(safe-area-inset-top, 0px);
  --safe-area-inset-bottom: env(safe-area-inset-bottom, 0px);
  --safe-area-inset-left: env(safe-area-inset-left, 0px);
  --safe-area-inset-right: env(safe-area-inset-right, 0px);

  /* Mobile Navigation Heights (see src/index.css for live tokens) */
  --mobile-header-height: 48px;
  --mobile-header-context-height: 32px; /* second row when visible */
  --mobile-header-switcher-height: 0px; /* legacy; main offset uses conditional context row */
  --mobile-nav-height: 64px;
}

Utility Classes

Convenience classes for applying safe area padding:
@layer utilities {
  .safe-area-top { padding-top: var(--safe-area-inset-top); }
  .safe-area-bottom { padding-bottom: var(--safe-area-inset-bottom); }
  .safe-area-left { padding-left: var(--safe-area-inset-left); }
  .safe-area-right { padding-right: var(--safe-area-inset-right); }
}

Component Implementation

MobileHeader.tsx:
<header className="... safe-area-top">
  <div className="h-16 flex items-center justify-between px-4">
    {/* Content pushed below notch */}
  </div>
</header>
MobileNav.tsx:
<nav className="... safe-area-bottom">
  <div className="flex items-center justify-around h-16 px-2">
    {/* Content pushed above home indicator */}
  </div>
</nav>
ResponsiveNav.tsx (pattern): padding-top on mobile main must match whether the second header row is rendered. The app uses shouldShowMobileHeaderContextRow so main adds var(--mobile-header-context-height) only when that row is visible (see source for the exact calc(...) classes).

Viewport Meta Tag

Required for safe area insets to work:
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover" />
Key: viewport-fit=cover tells the browser to extend content into safe areas.

PWA Shortcuts and Categories

The PWA manifest includes shortcuts for quick access to key features:
shortcuts: [
  {
    name: "Dashboard",
    short_name: "Dashboard",
    url: "/",
    icons: [{ src: "/pwa-192x192.png", sizes: "192x192" }]
  },
  {
    name: "Forms",
    short_name: "Forms",
    url: "/fw/forms",
    icons: [{ src: "/pwa-192x192.png", sizes: "192x192" }]
  },
  {
    name: "Census",
    short_name: "Census",
    url: "/rh/census",
    icons: [{ src: "/pwa-192x192.png", sizes: "192x192" }]
  }
]
These shortcuts appear in the PWA install prompt and app launcher on supported devices.

App Categories

The manifest specifies categories for better app store classification:
  • business
  • productivity
  • medical

Key Features

Offline Capability

  • Service worker caches forms and submissions for offline access
  • Background sync queues form submissions when offline
  • Graceful degradation for features requiring connectivity

Mobile Optimization

  • Touch-friendly UI (44×44px minimum touch targets)
  • Safe area support for devices with notches, Dynamic Island, home indicators
  • Responsive breakpoints: Mobile (320px) → Tablet (768px, 1024px) → Desktop (1280px+)
  • Native-like interactions (swipe gestures, bottom navigation)
  • Optimized for portrait orientation with landscape support

Installation

  • Installable as standalone app on iOS, Android, and desktop
  • Real PWA icons (not placeholders)
  • Custom install prompt for better UX (planned)
  • App update notifications with auto-refresh option

Technical Stack

  • Vite Plugin PWA: Build-time service worker generation
  • Workbox: Runtime caching strategies
  • Service Worker: Background sync, push notifications (future)
  • React Hook: virtual:pwa-register/react for update detection

Testing Checklist

PWA Functionality

  • Service worker registers correctly
  • Offline mode works
  • Update prompt appears when new version available
  • Icons display correctly on home screen
  • Manifest validates (use Lighthouse)

Icon Testing

  • Icons appear in browser tab
  • Icons appear in PWA install prompt
  • Icons appear on iOS home screen
  • Maskable icons work on Android
  • Icons scale correctly at all sizes

Mobile Testing

Device Emulation:
  1. Use browser DevTools device emulation
  2. Select devices with notches (iPhone 14 Pro, Pixel 7) to test safe areas
  3. Test both portrait and landscape orientations
Physical Devices:
  1. Test on actual mobile devices via network URL
  2. Verify safe area rendering on notched devices
  3. Test install-to-home-screen flow
Offline Testing:
  1. DevTools → Network → Offline
  2. Verify forms still render and submissions queue
  3. Go back online and verify sync

Performance Testing

  • Lighthouse PWA score: 90+
  • First Contentful Paint: <2s
  • Time to Interactive: <3.5s on 3G
  • Offline forms fully functional
  • Safe area CSS uses hardware-optimized env() (no JS overhead)

Performance Targets

  • Lighthouse PWA score: 90+
  • First Contentful Paint: <2s
  • Time to Interactive: <3.5s on 3G
  • Offline forms fully functional
  • Safe area CSS uses hardware-optimized env() (no JS overhead)

Troubleshooting

Icons Not Displaying

Problem: Icons don’t appear in browser tab or PWA install prompt Solutions:
  1. Verify icon files exist in public/ directory
  2. Check vite.config.ts icon paths are correct
  3. Clear browser cache and service worker
  4. Regenerate icons using the process above
  5. Check browser console for 404 errors

Service Worker Not Registering

Problem: Service worker doesn’t register or update Solutions:
  1. Check browser console for errors
  2. Verify VitePWA plugin is configured in vite.config.ts
  3. Clear service worker cache in DevTools → Application → Service Workers
  4. Check registerType is set to "autoUpdate"

Safe Area Insets Not Working

Problem: Content hidden behind notch or home indicator Solutions:
  1. Verify viewport meta tag includes viewport-fit=cover
  2. Check CSS uses env(safe-area-inset-*) correctly
  3. Test on actual device (emulation may not show correctly)
  4. Verify safe area classes are applied to correct elements

Offline Mode Not Working

Problem: App doesn’t work offline Solutions:
  1. Verify service worker is registered
  2. Check Workbox caching strategies are configured
  3. Test in DevTools → Network → Offline
  4. Check service worker cache in DevTools → Application → Cache Storage

Update Notification Not Showing

Problem: Users don’t see update notifications Solutions:
  1. Verify PwaUpdatePrompt component is in App.tsx
  2. Check useRegisterSW() hook is working
  3. Test by making a code change and rebuilding
  4. Check browser console for errors

References


Maintained By: Platform Team
Status: ✅ Ready for Production | ✅ Unified Icon System Active (Gold Compass on Dark Blue)