Repository source: docs/plans/backlog/offline_support_roadmap.md
Offline Support Roadmap
Status: Partially delivered; reconciled against implementation on 2026-10-15. This records product direction and sequencing; each selected slice must still enter the Feature Development Process (FDP) before implementation.
Product intent
After visiting the public site online, a reader should be able to continue using a clearly bounded, trustworthy version of the forum without a network connection. The long-term aspiration is to support offline participation, but read-only continuity and safe recovery come first. Offline writes must never silently lose, duplicate, expose, or misrepresent a user's work.
Completed foundation
The following is merged and considered the baseline for future work:
A public-only SQLite snapshot is built for each static release.
It includes every visible pinned thread plus up to 200 recent non-pinned threads, all visible posts in those threads, and no private or operational tables; the base snapshot defaults to a 100 MiB cap.
A separate compact update (20 recent non-pinned threads, 8 MiB cap) is published before the base by the queued publisher. The reader imports thread, post, and public-key rows into its saved database using repeatable upserts. This is a bounded update bundle, not deletion-aware delta synchronization.
Snapshots include every approved public key and content-associated unapproved public keys; private keys and private account data are excluded. Downloaded public records and keys cannot be remotely revoked.
Independent atomic publication, rebuild-time first-snapshot bootstrap, and missing-snapshot repair on eligible anonymous GET/HEAD requests are delivered. Normal writes and queued rebuilds enqueue publication; one per-minute task worker processes it. Direct database changes require explicit enqueueing.
Load-time refresh compares shell revisions (including the embedded snapshot revision) and skips unchanged downloads; manual refresh forces a recheck. A missing snapshot does not block caching the reader shell and assets.
Cache names, cleanup, registration diagnostics, and PWA runtime delivery are profile-specific; activation cleans only the active profile cache family.
Normal public Board and saved-thread URLs work from that snapshot when the network fails. Online navigation remains network-first.
Board controls supported by the snapshot are available offline: All/Liked and Newest/Oldest/Top.
The snapshot also supports a bounded Tags index and saved tag-result views; the shared offline subnav includes Tags and a disabled New Post control.
Offline Board and thread cards follow normal title, hidden-post, heat, and theme presentation rules. A thin
offline modebar is the persistent offline-state indicator and carries compact archive-time and reader-revision indicators. Saved posts have normal permalinks, and eligible Outbox items link back to their original thread/post targets.Tools → Offline Reading reports saved archive metadata, cached-versus-live reader revision, and a confirmed refresh/recheck action.
Tools → Outbox is available offline as a separate local-work shell. It keeps Likes, reply drafts, and thread drafts in device-local storage, shows their states and outcomes in compact expandable rows, and foreground-delivers queued work automatically when an open page reconnects. Drafts remain local.
Public-only deployments opt in to the cache; approved-members-only deployments do not expose or register it.
See Offline Reading Release 1 and Offline Normal Navigation for the completed FDP records and the operator runbook for recovery instructions (its older 50-thread/25-MiB bounds need reconciliation with the current builder defaults above). See also the completed Bundle Expansion, Snapshot Initialization, Freshness Automation, Reader Asset Refresh, and Browser/Offline Identity records. The companion Extended Offline Parity Roadmap maps the long-term maximum-safe-parity goal to specific capabilities and decision gates.
Non-negotiable guardrails
Every later slice must preserve these unless an FDP explicitly changes them:
Never cache private/member-only pages, account data, private keys, identities, LLM/operational data, or authenticated API responses in the public offline cache.
Never replace an online response with a saved HTML page; normal navigation remains network-first and uses the snapshot only after a network failure.
Never imply that a stale snapshot is current, that an unavailable action succeeded, or that a queued write has reached the server.
Keep full-thread snapshots atomic: a failed refresh retains the last complete snapshot.
Treat data removal, account changes, moderation state, and conflicts as first-class offline-write cases, not edge cases.
Roadmap
1. Snapshot lifecycle and reader confidence
Status: Partially complete; finish confirmation, clearing, and browser QA.
Reader outcome: A reader can tell that a snapshot has been saved, how old it is when needed, and how to refresh or remove it without using browser developer tools.
Progress and remaining pieces:
[ ] A short, non-persistent online confirmation after a complete snapshot is saved; it must distinguish success, retained prior snapshot, and failure.
[x] An optional details surface for saved-at time, reader revision, thread and post counts, and size. The ordinary offline view remains limited to its thin
offline modebar and compact indicators.[x] An explicit refresh/recheck control with confirmed status messages.
[ ] An explicit clear control with confirmation and accessible status.
[ ] A browser QA matrix covering first install, refresh, failed refresh, worker upgrade, clear, offline restart, and reconnection.
Established decisions: Tools → Offline Reading is the details/control surface. Automatic revision-gated refresh and explicit forced refresh are delivered; use that surface for the remaining lifecycle controls.
2. Broader read-only navigation
Status: Partially complete; Tags navigation is delivered.
Reader outcome: More public navigation remains useful while offline, without turning the browser cache into a copy of the site.
Progress and candidate slices, each independently scoped:
[x] Snapshot-backed tag index and tag-thread views, with a bounded tag index derived only from the saved threads.
[ ] Broader links between saved posts, threads, and permitted public metadata (saved-post permalinks and Outbox target links are delivered).
[ ] Carefully selected public profile summaries, only if their data boundary and deletion/revocation behavior are acceptable.
[ ] Explicit unavailable pages for search, feeds, tools, and routes not in the snapshot, instead of ambiguous browser errors.
Do not assume: Tags, profiles, search, or feeds belong in the snapshot by default. Each changes the public-data and staleness boundary.
3. Saved drafts and explicit delivery
Status: Partially complete; capture and foreground automatic queued delivery are available from an already-open compose page.
Reader outcome: A user can safely compose a thread or reply while offline and recover it after restart, but it remains a draft until the user explicitly submits online.
Delivered pieces: Device-local reply/thread draft capture, individual discard, automatic foreground send/retry for queued work from Tools → Outbox, and visible outcomes. Drafts are never submitted automatically.
Remaining pieces: Direct offline compose navigation, edit/restore/export, bulk-clear confirmation, per-thread recovery UI, and stronger shared-device retention controls.
Why separate it: Draft persistence is much safer than a write queue and can establish local-data lifecycle and recovery UX before any server mutation is attempted.
4. Queued low-risk reactions
Status: Initial Like queue delivered; reconciliation hardening remains.
Reader outcome: A user can queue a like or flag offline and later see whether the server accepted, rejected, or no longer needs that intent.
Required design work:
[x] A local queue that excludes private keys and the public cache.
[x] Stable local intent IDs; existing reaction writes de-duplicate a repeated tag from the same identity.
[x] Per-item states and explicit user-visible recovery actions.
[ ] Broader reconciliation against changed/deleted/hidden posts and changed authorization or moderation state.
[x] No-background-sync policy; an open Outbox or offline-reader page automatically attempts queued work on reconnection, while a closed browser does not.
Open policy question: A queued flag may affect moderation expectations. Decide whether it is appropriate to display it as a local intention before the server has received it.
5. Queued replies and new threads
Status: Initial signed, foreground automatic delivery delivered; composition and idempotency hardening remain.
Reader outcome: A user can create content offline and have it reliably submitted after reconnecting, with clear control over every pending item.
Required design work:
[x] Durable compose payloads, parent/thread references, and local draft capture from an open compose page.
[x] Existing browser signing is used for deliberate content delivery, and Likes are signed at the original offline click; no private key is copied into Outbox storage.
[ ] Server-side client-intent idempotency beyond retrying the retained prepared post, and a durable server mapping for all retry windows.
[ ] Detailed resolution UI for locked, hidden, or changed parent threads.
[ ] Edit, reorder, cancel, and export controls (individual discard and retry are delivered).
[x] Queued content remains distinct from published content until accepted.
This should be its own multi-stage release, not an extension of a read-only cycle.
6. Offline-first synchronization maturity
Status: Future strategy, not scheduled work.
A bounded compact-update import is already delivered; it does not establish deletion/revocation reconciliation or a general delta protocol. Remaining potential capabilities include incremental snapshots, content-delta sync, storage budgets, multi-device behavior, attachment policy, conflict history, and observability. Do not start this work until queued-write behavior has proved reliable and the product requires more than bounded reading.
Explicitly out of scope for the current read-only feature
Offline access to approved-members-only or other personalized content.
Offline search across the entire forum.
Automatic caching of all static pages or the full server database.
Offline posting, voting, tagging, moderation, account changes, and invite flows.
Silent background retries that hide pending or failed user actions.
Suggested ordering
Finish snapshot lifecycle confidence on Tools → Offline Reading: first validate install/refresh/retained-copy behavior in a real browser, then plan accurate completion feedback and confirmed clearing of saved reading data. Clearing must explicitly preserve or warn about device-local Outbox work.
Add unavailable-route treatment and saved-content coverage clarity; broader read navigation should follow demonstrated need.
Finish draft restore/edit/export and shared-device retention controls.
Harden the delivered queue's server idempotency and target/authorization reconciliation before broadening action types.
Consider general delta synchronization only if justified; the compact update bundle is already part of the baseline.
Recommended next slice: Snapshot lifecycle confidence. Begin with browser verification of install, unchanged loads, a new publication, forced refresh, failed refresh retaining the prior copy, offline restart, and reconnect. The asset-refresh record still leaves a publish-triggered browser refresh unobserved. Use that evidence to scope lifecycle feedback and a safe clear-reading-data control through Railspike before application implementation. Outbox design, Like queuing, and initial signed post delivery are already delivered and should not be scheduled again as new foundations.