175 lines
7.5 KiB
Markdown
175 lines
7.5 KiB
Markdown
# 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.
|