# Advice on ARCHITECTURE.md Review of the mobile / offline plan in `ARCHITECTURE.md`. The two-stage extract/render pipeline, edit flow, and federation sections are accurate and clear — this document focuses on where the architectural risk lives: the mobile app and the path to fully-offline operation. ## What's strong - **Workflow framing (1–4) is the right way to think about it.** Each workflow is a concrete user story, not an abstract capability list. Workflow 1 (record → convert → cloud) is achievable with what's already there; that's a good wedge to ship first. - **Honest status table** at the bottom of "Fully offline — missing pieces". An architecture doc that admits what isn't done is more useful than one that hand-waves. - **Incremental validation plan (§5).** Testing the service worker approach in the browser before touching native builds is the right call — cheap to run, and the failure mode is informative rather than expensive. ## Decision: drop `capacitor-nodejs` The doc previously listed `capacitor-nodejs` as a fallback if service workers fail on iOS. We are dropping this option entirely. Reasons: - It embeds a full Node runtime, meaningfully increasing app size. - iOS support relies on a fork of Node-mobile and has historically been spotty. - It introduces a long-term maintenance burden (tracking upstream Node, plugin updates, two runtimes to debug). - The "Hard" effort label in the original status table understated both the integration risk and the ongoing cost. If service workers turn out to be blocked on iOS, the fallback should be one of: 1. **A data access abstraction** (see next section) that lets the app read from IndexedDB directly via a JS loader, with no `fetch('/data/*')` in the hot path at all. This sidesteps the WKWebView question entirely. 2. **A native Swift/Kotlin micro-server** if a local HTTP origin is genuinely required. 3. **Bundling data as static assets** and re-running `cap sync` on import — crude but boring and reliable. `capacitor-nodejs` should not appear in the doc, the test plan, or the status table. ## Things to fix or add ### 1. Add a data access abstraction step *before* the service worker work The doc frames the offline problem as "serve local data to the WebView at `/data/*`". That skips a prior question: does the Astro site actually need to fetch `/data/*` at runtime, or can the data layer be abstracted behind a thin loader (`loadIndex()`, `loadActivity(id)`) with two implementations? - **Cloud build:** loader uses `fetch('/data/...')` as today. - **App build:** loader reads from IndexedDB directly. This is a much smaller change than service worker interception, avoids the iOS WKWebView question entirely, and is useful even if you stay cloud-only (testability, mocking, future federation transports). It should land *before* any service worker work — at which point the SW work may turn out to be unnecessary. ### 2. Commit to JS for sidecar merge — do not use Pyodide The "missing pieces" section lists two options for re-running `merge_all` on save: reimplement in JS (~150 lines) or call into Pyodide. Pick JS. Reasons: - Pyodide is lazy-loaded by `/convert/`. It is **not** warm just because the app is open. - A user tapping Edit → change title → Save would trigger a multi-second Pyodide cold start (~10MB) for a one-line edit. Terrible UX, and it repeats on every cold app launch. - Porting `merge_all` to JS keeps the edit drawer decoupled from the convert page's machinery. The two subsystems stay independent. Pyodide should remain convert-page-only. ### 3. The Workflow 4 diagram contradicts the test plan The "Fully offline on phone" workflow shows a "Local Node server" arrow as if it were the chosen path. The §5 test plan picks service workers first. The diagram should reflect that — show the SW path as primary, and drop the Node server box entirely (per the decision above). ### 4. Missing: data lifecycle on device Nothing in the doc covers: - How much storage the app is allowed to use on iOS before the OS evicts it. - What happens on uninstall / reinstall. - Sync / conflict resolution if the same activity exists locally and on a cloud instance. These don't need solutions today, but they should be acknowledged as open questions. Otherwise Workflow 4 will hit all of them at once during implementation. ### 5. Reconcile Pyodide payload size Line 162 says "~8MB", line 335 says "~10MB". Pick one and use it consistently. ## Small stuff - The federation diagram uses a `Note1` node that won't render as a Mermaid note — it'll appear as a regular box. Use `%%` comments or restructure. - The "iOS: App Store / TestFlight" cell in the PWA-vs-Capacitor table sits in the Capacitor column but reads like a downside. Clarify it's the distribution path, not a limitation relative to PWA. ## Bottom line The plan is sound and the incremental validation approach is right. The two highest-leverage changes: 1. **Add a data access abstraction layer** before the service worker work. It's small, useful regardless, and may make the SW work moot. 2. **Port `merge_all` to JS** so the edit drawer doesn't depend on Pyodide warm-up. With `capacitor-nodejs` removed, the offline path is: data access abstraction → IndexedDB-backed loader → JS merge → (optionally) service worker for any remaining `fetch('/data/*')` callsites that can't be migrated to the loader.