# Where the Data Lives

> Build log · Month 10 of 12

offline-first vs cloud-first, the decision that shapes every syncing app. Echo's cloud-synced voice journal, Calc+'s local vault, conflict resolution, and privacy as architecture.

Day 251–275 · 25 posts · Building in public as @caelum0x4

**Day 251** — This month: where your data lives. The most consequential architecture call in any app that stores something, and I make it per-app. Echo (voice journal) is cloud-synced. Calc+ (vault) is local-only. Same studio, opposite answers. The data model IS the promise.

**Day 252** — Calc+ is a calculator with a hidden vault, and its whole value is that your private stuff never leaves the device. So it's local-only, encrypted at rest, no server, no account. The most secure architecture has nothing to breach. Sometimes the best backend is none.

**Day 253** — Echo is the opposite: a voice journal you want on every device and never want to lose, so it's cloud-first with sync. The tradeoff I accept: encryption, sync conflicts, and holding your recordings. Convenience has an infrastructure cost, and it's mine.

**Day 254** — Offline-first isn't "works offline sometimes." It means the local store is the *source of truth* and the network is an enhancement. Fully usable on a plane; sync reconciles later. Most apps do it backwards and feel broken the second signal drops.

**Day 255** — Conflict resolution is the tax on sync. Edit an entry offline on your phone, edit it on your laptop, both sync. Now what? Last-write-wins is simple and silently destroys data. I merge and flag instead. Never silently delete a user's words.

**Day 256** — Thread: offline-first vs cloud-first, and how I choose per app.
  - Ask: what happens with no signal? If it must "fully work," you're offline-first.
  - Offline-first = local store is truth. Cloud-first = server is truth, cache is convenience.
  - Sync's real cost is conflict resolution. Last-write-wins loses data silently. Merge or flag.
  - Privacy-critical (Calc+ vault)? Local-only. No server = nothing to breach.
  - Multi-device + loss-averse (Echo)? Cloud-first with E2E. You take the responsibility.

**Day 257** — Sync bug of the month: an entry edited offline got overwritten by an older cloud version on reconnect, because I compared timestamps from two skewed device clocks. Never trust device clocks for ordering. I moved to logical version vectors. Wall-clock time is a lie.

**Day 258** — Echo's recordings are E2E encrypted before they ever hit my server, so I *cannot* listen to your journal even if compelled to. A deliberate constraint: make the private thing impossible for me to access, not just against-policy. Architecture beats promises.

**Day 259** — The cost of E2E on Echo: no server-side transcription or search, because the server sees ciphertext. So transcription runs on-device. Slower, but the alternative is decrypting your journal on my servers, which defeats the point. I chose privacy loudly.

**Day 260** — Local-first has a brutal failure mode: device loss. Calc+ is local-only, so lose the phone with no backup and the vault is *gone*, by design. I make backup explicit and optional (encrypted export), not a silent sync to a cloud the user opted out of.

**Day 261** — Optimistic UI in a sync app is a promise you might break. Show the entry saved instantly (great UX), but if sync fails you reconcile honestly, not leave a phantom "saved" thing that vanishes on the next device. Optimism is fine if you reconcile; a lie if you don't.

**Day 262** — Echo syncs metadata eagerly and audio lazily. You see your journal list instantly on a new device; recordings stream on demand. Syncing gigabytes of audio on first launch would feel broken. Sync what they see now; defer what they'll need later.

**Day 263** — Opinion: most apps should be more offline-first than they are. Treating the network as always-present is a bug that only shows up when users need the app most — the subway, the flight, the dead zone. Design for disconnection; connection is the bonus.

**Day 264** — Migrations are terrifying in a synced app: change the local schema and you must migrate every device independently, some offline for weeks. Schema changes are versioned and backward-compatible for several releases. You can't force-update a phone in a drawer.

**Day 265** — Thread: making data portable, so users trust you with it.
  - Echo: one-tap "export everything" — recordings, decrypted, on your device.
  - Calc+: encrypted export of the vault. You hold the key, not me.
  - No lock-in, no proprietary format they can't read elsewhere.
  - Deletion is real: purge server data, revoke tokens, in-app, not via support email.
  - If a user can't take their data and leave, they never fully trusted you with it.

**Day 266** — The sync-status honesty signal: Echo shows "synced," "syncing," or "offline — will sync later" plainly. Hiding sync state creates "did my entry save??" anxiety. Surface where the data is, even when it's "not backed up yet." Honest status beats silent uncertainty.

**Day 267** — CalGym and TracePace (GPS) forced the offline question hardest: you're in the mountains recording a run with no signal. TracePace is offline-first — the GPS track lives locally, synced when back in range. An outdoor app that needs signal is a contradiction.

**Day 268** — Battery is a data-architecture concern for TracePace: continuous GPS drains phones. I batch location writes, lower the sample rate when stationary, and never hunt for signal in a dead zone. Offline-first is also battery-first. Defer the sync until it's cheap.

**Day 269** — Month 10 lesson: "where does the data live" is the product's core promise about privacy, reliability, ownership. Local-only says "we can't see it." Cloud-sync says "we'll keep it safe everywhere." Pick deliberately, per app, and let the promise drive the architecture.

**Day 270** — Next month: procedural and generative content done *legally* — the engine behind Cipher's puzzles and Vertex's levels, and why "compute it or compose it originally, never scrape it" is both an ethical line and a moat. Infinite content without infinite risk.

**Day 271** — A meta-point from data month: every architecture choice is invisible until the moment it isn't — the lost entry, the breach, the dead-zone failure. You engineer for the bad day nobody sees. Good architecture is a promise you keep on the worst day.

**Day 272** — The fleet's data architectures are deliberately inconsistent, and correct. A vault, a journal, and a GPS tracker have opposite needs; one-size-fits-all sync would be the mistake. The studio shares *code*, not blind uniformity. Reuse the engine, tailor the promise.

**Day 273** — [N] users now trust the fleet with some form of data — locally or synced — and that number, however small, changes how I sleep. Holding people's recordings and vaults is a responsibility that scales with trust. Better it weigh on me now than surprise me later.

**Day 274** — Distribution note, because it never stops: "your data never leaves the device" (Calc+) and "encrypted so even I can't read it" (Echo) are *marketing*, not just architecture. Privacy done seriously is a story worth telling. The engineering and the pitch are one sentence.

**Day 275** — Day 275. Ten months in. The fleet's data foundations are deliberate, per-app, and honest about their tradeoffs. Two months of runway left. Next I harvest the content engine that makes the games sustainable, then close the year with the hardest post: the honest retro.

← [Month 9: Distribution Is the Actual Boss](https://ereboslab.com/blog/month-9-distribution-is-the-actual-boss/) · [Month 11: Infinite Content, Zero Theft](https://ereboslab.com/blog/month-11-infinite-content-zero-theft/) →

[← All build-log months](https://ereboslab.com/blog/)
