Files
CompanySite/.agents/frontend-specialist/PWA_IMPLEMENTATION.md
T
Clintchiz d402256547
Deploy to Production / Build & Verify (push) Failing after 5m56s
Ping Search Engines / Notify Search Engines (push) Successful in 2s
Deploy to Production / Pre-Deploy Tests (push) Has been skipped
Deploy to Production / Deploy to Railway (push) Has been skipped
Deploy to Production / Deploy to Render (push) Has been skipped
Deploy to Production / Deploy to VPS (PM2) (push) Has been skipped
Deploy to Production / Deploy to Fly.io (push) Has been skipped
Deploy to Production / Post-Deploy Verification (push) Has been skipped
Deploy to Production / Notify on Failure (push) Successful in 2s
E2E Test Suite / Critical User Journeys (push) Has been skipped
E2E Test Suite / API Integration Tests (push) Has been skipped
E2E Test Suite / Smoke Tests (P0) (push) Failing after 11m26s
E2E Test Suite / Form Interaction Tests (push) Failing after 11m42s
E2E Test Suite / Destructive & Chaos Tests (push) Failing after 12m2s
E2E Test Suite / Cross-Browser Regression (chromium) (push) Failing after 16m14s
E2E Test Suite / Cross-Browser Regression (webkit) (push) Failing after 17m45s
E2E Test Suite / Cross-Browser Regression (firefox) (push) Failing after 25m23s
E2E Test Suite / Security Header Tests (push) Failing after 7m55s
E2E Test Suite / Test Report Summary (push) Failing after 20s
E2E Test Suite / Mobile Device Tests (push) Failing after 2h49m9s
Uptime Monitor / Health & Response Time (push) Failing after 2s
Uptime Monitor / SSL Certificate (push) Successful in 2s
Uptime Monitor / Send Alerts (push) Failing after 3s
Uptime Monitor / Record Uptime Success (push) Has been skipped
First Init
2026-03-21 16:46:46 +05:30

196 lines
6.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# PWA Implementation — WorkRoot IT Solutions
## Overview
Progressive Web App (PWA) features have been added to the WorkRoot website. The implementation follows a **progressive enhancement** approach — the site works fully without JavaScript; PWA features layer on top.
---
## Files Added / Modified
| File | Type | Purpose |
|------|------|---------|
| `public/manifest.json` | New | Web App Manifest (installability) |
| `public/sw.js` | New | Service Worker (offline + background sync) |
| `src/pages/offline.astro` | New | Offline fallback page |
| `src/components/PWAInstallPrompt.astro` | New | Install prompt banner + background sync helper |
| `src/layouts/BaseLayout.astro` | Modified | Links manifest, registers SW, includes install prompt |
| `src/middleware.ts` | Modified | CSP updated: `worker-src 'self'`, `manifest-src 'self'` |
---
## Features Implemented
### 1. Web App Manifest (`public/manifest.json`)
- **Display mode:** `standalone` (hides browser chrome when installed)
- **Theme color:** `#0891b2` (matches brand primary)
- **Background color:** `#0f172a` (dark splash screen)
- **Shortcuts:** Quick links to `/contact` and `/services` from the home screen
- **Icons:** Uses existing `apple-touch-icon.png` and `favicon.svg`
### 2. Service Worker (`public/sw.js`)
**Caching Strategies:**
| Request Type | Strategy | Details |
|---|---|---|
| Static assets (JS, CSS, images, fonts) | Cache-first | Served from cache; fetched and cached on miss |
| HTML pages | Stale-while-revalidate | Serve cache instantly, update in background |
| API routes (`/api/*`) | Network-only | Never cached — always fresh |
**Pre-cached on install:**
- `/` (home)
- `/offline` (fallback page)
- `/manifest.json`
- `/favicon.svg`
- `/apple-touch-icon.png`
**Cache names (versioned for easy invalidation):**
- `workroot-static-v1`
- `workroot-pages-v1`
To invalidate caches on next deploy, increment `CACHE_VERSION` in `public/sw.js`.
### 3. Offline Fallback (`src/pages/offline.astro`)
- Served at `/offline`
- Clean branded page with "Try Again" and "Go to Home" actions
- Pre-cached by the service worker on install
- Shown automatically when a navigation request fails offline
### 4. Background Sync (`public/sw.js` + `src/components/PWAInstallPrompt.astro`)
When a form submission fails due to no network:
1. Form handler calls `window.queueFormSync(url, method, body, formType)`
2. The payload is stored in **IndexedDB** (`workroot-pwa` DB, `workroot-sync-queue` store)
3. A background sync tag `form-sync` is registered with the browser
4. When connectivity is restored, the service worker automatically retries all queued submissions
5. On success, clients receive a `pwa:sync-success` custom event they can listen to
**Usage in form pages:**
```js
// In contact or newsletter form submit handler:
try {
const res = await fetch('/api/contact', { method: 'POST', body: JSON.stringify(data) });
if (!res.ok) throw new Error('Server error');
// handle success
} catch {
if (!navigator.onLine) {
await window.queueFormSync('/api/contact', 'POST', data, 'contact');
showMessage('You are offline. Your message will be sent when you reconnect.');
}
}
// Listen for sync success:
window.addEventListener('pwa:sync-success', (e) => {
if (e.detail.formType === 'contact') {
showMessage('Your message was sent successfully!');
}
});
```
### 5. Install Prompt (`src/components/PWAInstallPrompt.astro`)
- Listens for `beforeinstallprompt` event (Chrome/Edge/Android)
- Shows a non-intrusive banner after 4 seconds on first visit
- Banner is suppressed for 7 days after dismissal (stored in `localStorage`)
- Hides immediately after successful installation (`appinstalled` event)
- Accessible: uses `role="banner"`, `aria-label`, button labels
---
## Security Considerations
The CSP in `src/middleware.ts` was updated to include:
```
worker-src 'self' → allows service worker from same origin only
manifest-src 'self' → allows manifest.json from same origin only
```
These are deliberately restrictive — no external workers or manifests are permitted.
---
## Offline Functionality Testing
### Manual Testing in Chrome DevTools
1. Open DevTools → **Application** tab
2. **Service Workers** panel:
- Confirm `sw.js` is registered and active
- Use "Offline" checkbox to simulate offline
3. **Manifest** panel:
- Verify all manifest fields are correct
- Check "Add to home screen" works
4. **Cache Storage** panel:
- Verify `workroot-static-v1` and `workroot-pages-v1` exist with expected entries
5. Navigate to `/contact` while offline → should serve cached page
6. Navigate to a page not in cache while offline → should show `/offline`
### Automated Testing
The offline behavior can be tested with Playwright:
```typescript
// In a Playwright test:
await context.setOffline(true);
await page.goto('/contact');
// Should either show cached page or /offline fallback
```
---
## Updating the Service Worker
To force all users to get the new service worker immediately:
1. Increment `CACHE_VERSION` in `public/sw.js` (e.g. `'v1'``'v2'`)
2. Old caches will be deleted during the `activate` event
3. `skipWaiting()` + `clients.claim()` ensure immediate takeover
---
## Lighthouse PWA Checklist
| Criterion | Status |
|-----------|--------|
| Registers a service worker | ✅ |
| Responds with 200 when offline | ✅ (cached pages + `/offline` fallback) |
| `<meta name="viewport">` set | ✅ (BaseLayout) |
| `<meta name="theme-color">` set | ✅ `#0891b2` |
| Web App Manifest with `name`, `short_name`, `icons` | ✅ |
| Icons at 192×192 and 512×512 | ⚠️ Only `apple-touch-icon.png` (180×180) — add larger icons for perfect score |
| Manifest `display: standalone` | ✅ |
| HTTPS in production | ✅ (HSTS enforced) |
| Install prompt supported | ✅ |
### Recommended Improvement
Add 192×192 and 512×512 PNG icons to `public/` and reference them in `manifest.json` to achieve a perfect Lighthouse PWA score:
```json
{
"src": "/icon-192.png",
"sizes": "192x192",
"type": "image/png",
"purpose": "any"
},
{
"src": "/icon-512.png",
"sizes": "512x512",
"type": "image/png",
"purpose": "any maskable"
}
```
---
## Known Limitations
- **iOS Safari:** Background sync is not supported. Queued forms will be retried when the user next opens the app with network access (via the SW `sync` event on supported platforms). On iOS, consider showing a manual retry prompt.
- **SSR + Service Worker:** Since Astro runs SSR, HTML responses are dynamic. The stale-while-revalidate strategy serves potentially stale HTML while fetching fresh content in the background. This is acceptable for a marketing site.
- **API routes are always network-only.** This is intentional — form submissions and the health API must never serve stale responses.