clone

a deno framework for local-first web apps that open instantly, work offline and sync when users choose

feat/141-effect-library
lofi / docs / application-origin-migration.md
application-origin-migration.md 6.6K rendered
1# Application-origin migration23Changing a production app from one origin to another creates a new browser security boundary. An4HTTPS redirect moves navigation; it does not move the old origin's service workers, Cache Storage,5IndexedDB, OPFS, permissions, installed-app identity, or WebAuthn credentials.67This playbook keeps the old origin available while each user deliberately restores account access or8imports a product-owned export, verifies the new origin, and only then removes the old installation.9It never copies account secrets, passkeys, opaque IndexedDB/OPFS files, or browser permission state.1011## Choose the migration contract1213Record these decisions before deploying the new origin:1415| Decision | Required choice |16| ----------------------- | -------------------------------------------------------------------------------- |17| Old-origin availability | A dated compatibility window long enough for offline users to return |18| Data path | Managed account sync/recovery, or a versioned product-owned export/import format |19| Manifest identity | A deliberate new same-origin `id`, `start_url`, and `scope` |20| Credentials | New stable hostname/RP ID and a new-origin enrollment/recovery ceremony |21| Install UX | Whether old and new installations coexist and how each is labeled |22| Retirement | Warning dates, final read-only date, rollback owner, and support path |2324Do not silently add the new hostname to `credentialOrigins`. A WebAuthn credential is scoped by its25RP ID and origin checks; changing the permanent hostname is an identity decision, not a redirect26configuration detail. Keep lofi's checks intact and require an explicit new-origin recovery or27enrollment flow.2829## Pick one data path3031### Managed account sync and recovery32331. On the old origin, reconnect and wait until the UI reports global durability for the latest34 write.352. Make sure the user has a portable recovery phrase. An old-origin passkey alone cannot establish36 the same RP ID on a different hostname.373. Open the new origin directly, create its fresh local browser storage, and restore the account38 with the supported recovery ceremony.394. Wait for synced data to appear, then compare representative counts and named records.405. Make a harmless test edit on the new origin and verify global durability and another-client41 convergence before treating the migration as complete.4243Never put an account secret, recovery phrase, or serialized Jazz/browser database in a URL,44redirect, query parameter, cross-origin message, analytics event, or support log.4546### Product-owned export and import47481. Export only a documented product schema from the old origin. Version it, bound its size, and omit49 credentials, opaque storage records, cache entries, handles, and permission grants.502. On the new origin, validate the file as external input and show an import preview.513. Require explicit confirmation before writing it to the new local database.524. Compare representative counts and records, reload, go offline, and verify the imported data53 again.545. Preserve the export until the compatibility window closes.5556The [file handling recipe](recipes/file-handler.md) provides a preview-only validation boundary, but57an ordinary file picker remains the portable migration path.5859## Deployment sequence60611. Deploy the new origin with its own manifest identity, icons, worker scope, database name, and62 stable credential-origin configuration.632. Keep the old origin's application shell, worker assets, recovery/export UI, and support page64 available. Do not blanket-redirect these paths during the compatibility window.653. Add old-origin messaging that links to the exact new HTTPS origin and explains that local data66 and permissions do not move automatically.674. Let both installations coexist. Give the new installation distinct temporary labeling if the OS68 would otherwise make them ambiguous.695. Ask for notifications, storage persistence, file/protocol associations, and other permissions70 again only when the user reaches the relevant new-origin feature.716. After user verification, offer instructions to uninstall the old app. Never uninstall it or clear72 its storage programmatically as part of migration.7374## Repeatable verification checklist7576Run this with a clean browser profile and with a profile containing representative production-like77data. Retain dates and non-secret results with the release evidence.7879- [ ] `ORIGIN-01` Old origin opens online and offline with its retained worker/app shell.80- [ ] `ORIGIN-02` New origin installs with the intended new manifest ID, scope, and display name.81- [ ] `ORIGIN-03` New origin starts with separate IndexedDB, OPFS, Cache Storage, and permissions.82- [ ] `ORIGIN-04` Chosen sync/recovery or export/import path transfers only product-owned data.83- [ ] `ORIGIN-05` Representative counts and named records match before the old app is removed.84- [ ] `ORIGIN-06` Reload and offline restart preserve verified data on the new origin.85- [ ] `ORIGIN-07` A new-origin edit reaches its required durability and convergence state.86- [ ] `ORIGIN-08` Old passkey behavior is rejected honestly; new recovery/enrollment succeeds.87- [ ] `ORIGIN-09` Permissions and OS associations are requested or registered afresh as documented.88- [ ] `ORIGIN-10` Old and new installations are distinguishable while they coexist.89- [ ] `ORIGIN-11` Offline users returning during the window still receive migration instructions.90- [ ] `ORIGIN-12` No secret or opaque browser-storage value appears in URLs, logs, or artifacts.9192## Partial migration and rollback9394Migration is per user and per device. Track `not started`, `restored/imported`, `verified`, and95`old installation removed` separately; never infer completion from a redirect or a visit.9697If verification fails, stop new-origin writes when practical, keep the old origin authoritative, and98preserve the user's export/recovery material. Fix the new deployment or importer, then repeat from a99fresh new-origin profile. Do not merge divergent local datasets automatically unless the product has100a tested domain-level reconciliation strategy.101102Delay retirement when offline users have not had a reasonable return window, recovery/export remains103broken, or support cannot distinguish partial states. At retirement, keep a minimal non-sensitive104status/support page for the announced period, revoke old deploy credentials, and retain rollback105artifacts. Removing DNS or the old worker too early strands users whose only current copy is local.