# Prepared offline chart acceptance This drill verifies one bounded workflow: prepare an existing in-exam visit while connected, reopen its encrypted chart without networking, write SOAP sections, reconnect, and explicitly save one draft to the correct visit. Review and signing happen online. Both offline features remain default-off pilots; passing this drill does not activate them or approve a production clinic. ## Run the automated drill Use a clean checkout without root or web `.env`/development environment files, an available local PostgreSQL administrator connection, and the password of the local `openpims_app` role. The harness refuses remote database hosts and never migrates, seeds, or resets the database supplied in the administrator URL. It creates a randomly named `openvpm_offline_e2e_…` database, applies committed migrations and RLS, and runs the server as the restricted application role. No shared seed is used. Existing application data is untouched. ```sh pnpm install --frozen-lockfile pnpm exec playwright install chromium webkit # Set these through your local secret/environment mechanism: # OFFLINE_E2E_ADMIN_DATABASE_URL: local database administrator connection # OPENPIMS_APP_DB_PASSWORD: existing local restricted-role password pnpm exec playwright test --config=playwright.offline.config.ts # To build and test the actual standalone production server: OFFLINE_E2E_SERVER_MODE=production pnpm exec playwright test --config=playwright.offline.config.ts ``` Production mode also requires `openssl`. It generates a temporary self-signed loopback certificate accepted by the test browsers and serves the proxy over HTTPS, exercising the application's production HTTPS-upgrade policy. The temporary certificate/key and private fixture manifest are removed on shutdown. The Node reachability probe explicitly trusts that generated certificate while retaining certificate and hostname validation. A negative check verifies the ordinary trust store rejects it without that explicit trust. The dedicated config always runs the tests; there is no opt-in skip. It owns ports 3456–3458 and refuses to reuse an existing server. Do not build or run another Next.js process from the same checkout during the drill. It supplies fresh auth configuration, enables offline preparation only for its server, and excludes inherited provider credentials. Hosted billing and messaging remain disabled. The database and private fixture manifest are removed on ordinary shutdown or test failure. A forced process termination may require an operator to remove the uniquely named disposable database after confirming its identity. Screenshots and failure traces are written to an invocation-specific temporary directory, outside the checkout. `OFFLINE_E2E_ARTIFACT_DIRECTORY` can select a different artifact destination. Artifacts contain synthetic fixtures only. The `Offline browser recovery` CI job uses Ubuntu 24.04, supported by the pinned Playwright version. It builds and serves the standalone production artifact, with generated public/static assets copied into that artifact, and runs the same cases in desktop Chromium and WebKit with an iPad viewport against an ephemeral PostgreSQL service: - cold offline page reopening, unlock, exact recovery of all four SOAP sections, explicit save, one persisted note, and online editor readback; - a server-committed save whose response is dropped, followed by reopening and retrying the identical request without a second note or revision; - newer online drafts and signed notes, preserving both versions for review; - stale tabs that cannot overwrite or submit another tab's encrypted draft; - expired offline authorization and successful recovery after reconnection; - account changes that lock the workspace without discarding the owner's work; - failed IndexedDB writes retaining in-memory text and the prior durable copy; and unavailable storage refusing workspace creation. Additional adversarial cases check wrong-passphrase ciphertext preservation, absence of chart text in public caches, separate drafts for multiple visits, live lease expiry, audit rejection/rollback and retry, correction of oversized pastes, storage failure combined with automatic locking, and service-worker update waiting/activation with an existing draft. The worker update changes only the public cache version in the test proxy; clinical routes stay real. A persistent-profile test closes and restarts the browser process. Chromium must reopen offline directly. The pinned WebKit automation has also been observed losing its cached shell across a process restart. That branch records an explicit limitation annotation and proves the encrypted draft still recovers after reconnection; it must not be reported as successful offline Safari cold startup. Physical-device acceptance is still required. The drill uses real browser storage, service workers, login, protected HTTP routes, and PostgreSQL. Fault injection drops a response only after the server commits, aborts a browser storage transaction, or disconnects the browser context. It does not replace clinical save responses with mock successes. Existing database contracts continue to cover tenant/role isolation, revocation, recovery holds, audit atomicity, and concurrent server saves. For Chromium, cold reopening and lease expiry use `context.setOffline(true)`. For those WebKit cases, a token-protected loopback control cuts off the real application origin instead: Playwright's WebKit offline emulation currently [rejects even cached service-worker responses](https://github.com/microsoft/playwright/issues/42775). The drill verifies origin requests fail and reopened pages come from the real service worker. Browser networking can still report connected during an origin outage; an attempted save must then fail without losing text. This workaround does not establish physical airplane-mode behavior. ## Physical Safari/iPad acceptance Automated WebKit is browser-engine coverage, not proof of Safari behavior on a physical iPad. Before naming a device/browser as supported for a clinic pilot, record the exact iPad model, iPadOS/Safari version, browsing mode, candidate commit/deployment, operator, date, and result of each check below. Use only synthetic records in isolated staging with the approved offline flags enabled. Never infer a pass from a responsive desktop screenshot. 1. Prepare a synthetic existing visit and verify the chart snapshot time, allergy display, offline authorization expiry, and saved-device indicator. 2. Enable airplane mode and explicitly disable Wi-Fi and cellular connectivity. Close the workspace tab, reopen its saved URL, unlock, and check all SOAP sections. Background and reopen Safari, then repeat after locking the iPad. 3. Edit each SOAP section. Wait for **Encrypted device copy saved**, close and reopen, and confirm the exact text. Check keyboard/scrolling, portrait and landscape, and readable recovery/error controls. 4. Reconnect. Confirm there is no automatic submission. Explicitly save, open the online editor, and verify the correct patient/visit, exact text, and one draft. Review and sign online only after that check. 5. Repeat with a competing online edit and a signed note. Both local and server text must remain available; resolving a conflict must require review. 6. Check wrong passphrases, a second tab, account switching, expired access, and storage refusal using synthetic fixtures. A wrong passphrase or expired authorization must retain the encrypted draft. Document storage eviction limits; browser-cleared data and lost passphrases cannot be recovered. 7. Confirm that disabling new preparation preserves access to compatible recovery endpoints for already-prepared drafts. Recover all synthetic device drafts before retiring the candidate or clearing browser data. Record failed and untested cases explicitly. Physical acceptance is pending until an operator performs and records these checks; this document supplies the procedure rather than claiming an observed result. ## Pilot decision Agree on a trusted device, passphrase retention, reliable daily reconnection, and a downtime/support owner before a small clinic pilot. The current workspace holds up to 20 prepared charts and authorizes offline access for at most 24 hours. Chart snapshots may be stale; medication lists, attachments, lab results, new visits, billing, and signing are outside this scope. Device copies are not server backups or signed clinical records. Pause the pilot for lost text, wrong-patient association, duplicate notes, silent replacement of newer/signed work, unauthorized access, or false save confirmation. Retain the prior clinical system and the agreed downtime procedure. Follow the normal staging and production release controls; keep compatible recovery available until every outstanding device draft is resolved. For a storage failure followed by automatic locking, the new recovery buffer contains ciphertext only in that tab's memory. Wrong passphrases and a different signed-in person must remain blocked. The owner can recover after storage returns; concurrent newer durable data must not be overwritten. Keep the tab open until this recovery is durably saved. The drill does not promise recovery of oversized/invalid text, cleared browser data, or a memory-only buffer after the tab/browser process is terminated.