docs: specify AgendaMax PWA installability
This commit is contained in:
@@ -0,0 +1,174 @@
|
||||
# AgendaMax PWA Installability
|
||||
|
||||
## Goal
|
||||
|
||||
Make AgendaMax installable as a web app on mobile and desktop browsers, with a
|
||||
native installation prompt where the browser supports it and an explicit iOS
|
||||
installation guide where Apple does not expose that prompt API.
|
||||
|
||||
## Decisions
|
||||
|
||||
- Use a manually maintained manifest and service worker instead of adding
|
||||
`vite-plugin-pwa`. This keeps the caching policy visible and avoids a new
|
||||
build-time dependency for a small, already stable Vite app.
|
||||
- Use an online-first data model. The service worker may recover the application
|
||||
shell after a previous visit, but it must never cache `/api` responses or
|
||||
attempt offline writes for appointments, clients, cash, or settings.
|
||||
- Keep the existing AgendaMax visual language and Spanish copy. Installation is
|
||||
an optional secondary action, not a permanent mobile banner.
|
||||
- Require HTTPS in deployed environments. `localhost` remains valid for local
|
||||
testing because browsers treat it as a secure context.
|
||||
|
||||
## Current Context
|
||||
|
||||
- Frontend: React 18, TypeScript, Vite, Tailwind CSS, React Router.
|
||||
- Production serving: Express serves `dist/` and falls back to `index.html` for
|
||||
non-API routes.
|
||||
- Existing brand assets: `public/favicon.svg`, `#3b66ff` theme color, AgendaMax
|
||||
name and current Spanish UI.
|
||||
- Existing entry points: `src/main.tsx`, `src/App.tsx`, `LoginPage`,
|
||||
`AppShell`, and `AdminShell`.
|
||||
- There is no manifest, service worker, install prompt handling, or iOS-specific
|
||||
home-screen metadata today.
|
||||
|
||||
## Architecture
|
||||
|
||||
### Static PWA assets
|
||||
|
||||
Add the following public assets, copied by Vite into `dist/`:
|
||||
|
||||
- `manifest.webmanifest` with `name` and `short_name` set to AgendaMax,
|
||||
`start_url` `/`, `scope` `/`, `display` `standalone`, portrait orientation,
|
||||
brand colors, and PNG icons at 192x192 and 512x512.
|
||||
- `sw.js` with a versioned cache name.
|
||||
- PNG icons derived from the existing AgendaMax favicon mark. Keep the SVG
|
||||
favicon unchanged for browser tabs.
|
||||
|
||||
Update `index.html` with the manifest link, iOS home-screen metadata, an
|
||||
explicit mobile web app title, `viewport-fit=cover`, and the existing theme and
|
||||
description metadata.
|
||||
|
||||
### Service worker
|
||||
|
||||
Register the worker from `src/main.tsx` only for production builds, using
|
||||
`updateViaCache: "none"` so a deployed worker is checked promptly.
|
||||
|
||||
The worker has these rules:
|
||||
|
||||
- On install, cache only the stable shell/bootstrap assets and call
|
||||
`skipWaiting`.
|
||||
- On navigation requests, use network-first and fall back to the cached root
|
||||
document. This allows deployments to deliver fresh HTML while preserving a
|
||||
previously visited shell during a temporary outage.
|
||||
- On same-origin static GET requests, use cache-first for immutable or hashed
|
||||
assets and add successful responses to the runtime cache.
|
||||
- Bypass `/api/`, non-GET requests, cross-origin requests, and requests with
|
||||
credentials or other conditions that could expose tenant data.
|
||||
- On activation, remove caches from older versions and call `clients.claim`.
|
||||
|
||||
The worker is deliberately not a data-sync layer. If an API request fails, the
|
||||
existing application error/loading behavior remains authoritative.
|
||||
|
||||
### Install state and UI
|
||||
|
||||
Create a small reusable install hook/component with these states:
|
||||
|
||||
1. `unsupported`: no UI.
|
||||
2. `available`: show an install action backed by `beforeinstallprompt`.
|
||||
3. `ios-instructions`: show a short dialog explaining Safari's Share then Add
|
||||
to Home Screen flow.
|
||||
4. `installed`: no UI, detected from `display-mode: standalone` and
|
||||
`navigator.standalone`.
|
||||
|
||||
The hook must retain the deferred Android prompt only until it is used, handle
|
||||
`appinstalled`, and avoid showing the CTA repeatedly after a user dismisses it
|
||||
within the current browser session.
|
||||
|
||||
Render the reusable action in:
|
||||
|
||||
- `LoginPage`, so a user can install before authentication;
|
||||
- the authenticated business mobile header/sidebar in `AppShell`;
|
||||
- the authenticated platform-admin mobile header/sidebar in `AdminShell`.
|
||||
|
||||
The action should remain a compact secondary button with a download icon. The
|
||||
iOS dialog is instructional and must not claim that a native prompt is
|
||||
available. It must not reserve a persistent bottom band or interfere with
|
||||
existing mobile navigation.
|
||||
|
||||
Use safe-area-aware spacing where the install dialog or mobile controls touch a
|
||||
screen edge.
|
||||
|
||||
## Data Flow
|
||||
|
||||
1. Browser loads the Vite entry document.
|
||||
2. Production client registers `/sw.js`; the worker installs and claims future
|
||||
navigations.
|
||||
3. The install hook evaluates browser capability and standalone state.
|
||||
4. Android/Chromium emits `beforeinstallprompt`; the hook stores the event and
|
||||
exposes the CTA.
|
||||
5. User selects the CTA; the hook calls the native prompt and handles the
|
||||
resulting `appinstalled` or dismissal event.
|
||||
6. iOS Safari is identified when not standalone; the CTA opens the instruction
|
||||
dialog and does not attempt an unsupported API.
|
||||
7. All authenticated API requests continue to use the existing `fetch`/auth
|
||||
path and always go to the network.
|
||||
|
||||
## Error Handling and Compatibility
|
||||
|
||||
- Failure to register the service worker is non-fatal and must not prevent the
|
||||
React application from rendering; log a concise warning in development only.
|
||||
- Missing or invalid install events result in hidden UI, not an exception.
|
||||
- Existing browsers that cannot install PWAs continue to work as normal web
|
||||
pages.
|
||||
- iOS installation is supported through Safari's system flow. Other iOS
|
||||
browsers may render the app but are not promised a direct install action.
|
||||
- The service worker must not intercept API errors, mutate auth tokens, or
|
||||
serve one user's tenant data to another user.
|
||||
|
||||
## Testing and Verification
|
||||
|
||||
### Automated
|
||||
|
||||
- `npm run typecheck` passes.
|
||||
- `npm run build` passes and emits the manifest, worker, icons, and metadata in
|
||||
`dist/`.
|
||||
- Add a Playwright check for Chromium's deferred install event and `prompt()`.
|
||||
- Add a Playwright check for iOS-style user-agent/standalone detection and the
|
||||
instructional dialog.
|
||||
- Add checks that unsupported and already-installed states do not render the
|
||||
CTA.
|
||||
- Verify the production Express server returns status 200 for the manifest,
|
||||
worker, and icon paths, while SPA fallback still serves client routes.
|
||||
- Run `npm run audit:visual` and confirm no horizontal overflow at 375, 768,
|
||||
1280, or 1536 pixels.
|
||||
|
||||
### Manual device acceptance
|
||||
|
||||
- Android Chrome on HTTPS displays the native install action and opens
|
||||
AgendaMax in standalone mode with the correct icon/name.
|
||||
- iPhone Safari on HTTPS shows the two-step installation guide and the added
|
||||
home-screen app opens without browser chrome.
|
||||
- After a prior visit, temporarily disabling the network still allows the
|
||||
shell to load; API-backed data correctly remains unavailable rather than
|
||||
showing stale cached data.
|
||||
- A new deployment replaces the old worker/cache without requiring the user to
|
||||
clear browser storage manually.
|
||||
|
||||
## Scope Exclusions
|
||||
|
||||
- No offline appointment creation, edits, queued writes, conflict resolution,
|
||||
or background synchronization.
|
||||
- No native App Store/Play Store packaging.
|
||||
- No change to authentication, tenant isolation, API routes, or database schema.
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
- AgendaMax has a valid install manifest and 192x192/512x512 icons.
|
||||
- Android/Chromium exposes an in-app install action when the native event is
|
||||
available.
|
||||
- iOS Safari exposes clear Share -> Add to Home Screen instructions.
|
||||
- Installed standalone mode hides the install action.
|
||||
- The service worker is registered in production, preserves the shell after a
|
||||
prior visit, and never caches `/api` or non-GET requests.
|
||||
- Production HTTPS serving works through the existing Express/Docker path.
|
||||
- Typecheck, build, PWA behavior checks, and visual audit pass.
|
||||
Reference in New Issue
Block a user