Paid features, sync tiers and store release (design plan)
Status: future plan, not a decision. This explores how Jotry could be sold on the App Store and Google Play, and how that shapes sync. Agreed so far (see
05-decisions-and-open-questions.md): D-33 (hosted sync runs on Jotry’s own end-to-end encrypted server), D-34 (export and folder sync are never paid features), D-35 (hosted sync carries the full revision history; folder sync carries current notes only). Pricing, the business model and everything else below are open. Update 2026-10-08: D-45 makes hosted sync personal for now, on the owner’s backend infrastructure; whether that runs an own Ktor server or a self-hosted Supabase is still open. Update 2026-10-09: the billing model is now agreed: D-52 (entitlement belongs to the sync group; several stores can contribute; latest expiry wins), D-53 (a free app with a sync subscription bought in the stores; the purchase creates the group), D-54 (purchase bound to the group by the store’s account token), D-56 (lapsed groups are read-only and kept for a year) and D-58 (pluggable store verifier; promo entitlements possible). Prices, trial length and the rest remain open. Related plans:cloud-sync-and-e2ee.md(server, crypto, keys) andfolder-sync.md(folder sync and the file format).
Starting points
- Folder sync is effectively free multi-device sync. Point Jotry at an iCloud Drive or Syncthing folder on two devices and they sync. A paywall on folder sync would not protect much revenue, and would break the “your data stays yours” promise in the README. Obsidian is in the same position (free app, paid Sync competing with free iCloud and git) and still sells Sync, because people pay for “it just works”, history and encryption, not for the bare ability to move files.
- What people pay for is convenience and safety: one switch, no folder setup, full history on every device, end-to-end encryption, and it works between an iPhone and an Android phone.
- Using the app should stay simple. Power features exist but don’t get in the way of people who never need them.
Proposed tiers
| Tier | Contents |
|---|---|
| Free | The whole app on any number of devices without syncing them: notes, notebooks, history, search, links, export, import. Folder sync where the platform supports it (Android, desktop). |
| Paid (subscription) | Hosted sync: end-to-end encrypted, across devices and across platforms, with the full revision history on every device (D-35). Device pairing by QR code. Recovery key. |
Why a subscription for sync: it has an ongoing cost (server, storage, support), and stores and users both understand “service = subscription”. A one-time “Pro” purchase only makes sense for local-only extras, and there are none planned.
Why not a paid app: an upfront price hurts discovery, and the free app is the marketing. People who try it and want sync convert; people who don’t still recommend it.
Principles to record (proposed)
- Export is never paywalled. (Recorded as D-34, together with folder sync.)
- Local features never need an account or a network connection.
- The paid check lives in one place: the hosted-sync transport. The rest of the app never asks “is this user paying?”
- Cancelling never locks anyone out of their notes. If a subscription ends, sync stops; every device keeps its notes and history, and export still works.
Sync architecture across tiers
One sync core, several transports (see doc 03’s destination capability contract):
shared sync core
(identity map, reconcile, revisions, conflicts, link translation)
| | |
folder transport hosted transport (later: WebDAV, git…)
free, current notes paid, full history
Android + desktop all platforms
- Hosted sync moves the revision graph (records, as in
cloud-sync-and-e2ee.mdsection 2), not files. That is the honest difference between the tiers (D-35). - The entitlement check is one gate in front of the hosted transport.
Hosted sync: own end-to-end server (D-33)
The backend is Jotry’s own server (the Ktor server/ module), not a managed backend such as Supabase or Firebase and not the platform stores (CloudKit, Google Drive app data). Platform stores can’t sync an iPhone with an Android phone; a managed backend adds a third party that sees metadata. The cost: we run, secure and pay for a server.
The server is a dumb store for encrypted records and only sees ciphertext; the design is in cloud-sync-and-e2ee.md sections 3–5.
Accounts or no accounts
The README promises “no account”. Hosted sync needs some identity, so two options:
| Option | How it works | Trade-off |
|---|---|---|
| A. Sync group, no account (proposed) | The first device creates a sync group and its root key. Other devices join by scanning a QR code on a device that is already in the group (the device-to-device enrollment in cloud-sync-and-e2ee.md section 4, option C). A recovery key is the fallback if every device is lost. No email, no password. | The README promise survives (“no account; we can’t read your notes”). Support can’t “reset your password”. Losing every device and the recovery key loses the hosted copy, which must be said plainly. |
| B. Account (email, passkey) | Normal sign-in for authentication only; encryption keys stay separate. | Familiar, and makes subscription restore and support easier. Breaks the “no account” promise, and the server now holds an email address. |
Chosen: A (D-45), with the store purchase tied to the group (D-52 to D-54).
Store rules and licensing
(Store policies change; check the current App Store Review Guidelines and Google Play policies before building.)
- In-app purchase: unlocking features inside the app generally has to use Apple’s and Google’s billing. Some regions now allow outside payment links or other billing under conditions; treat that as optional, not as the plan.
- No downloaded code: Apple does not allow apps to download and run new code. Extensions (folder sync, hosted sync, future ones) are built into the app, as doc 03 already assumes.
- Cross-platform licensing (D-52 to D-54): a store purchase is tied to an Apple ID or a Google account, so buying on iPhone does not unlock Android by itself. The client sends the store’s signed transaction to the server together with the group it belongs to; the account token inside the transaction names that group, so a leaked receipt cannot be claimed by another group. The server verifies it and attaches it to the group as an entitlement, and every device in the group syncs. A group can hold entitlements from several stores, and the latest expiry wins.
- Switching platforms: a new iPhone joins the group by QR from the old Android phone and needs no purchase; billing stays with Google until the user cancels there. To move billing, they buy the Apple subscription for the same group; the group then has two entitlements and the later expiry applies. The app shows which store bills the group and links to that store’s subscription page. The server cannot cancel across stores.
- Apple’s multiplatform rule: Apple lets an app grant access to a service bought elsewhere only if the same purchase is also offered in the iOS app (guideline 3.1.3(b) as we read it; re-check the current wording before submission).
- Lost phone, same store account: the recovery key restores the group (D-55). Restoring the purchase on the new phone reattaches a lapsed group within the year it is kept (D-56). There is no cross-store proof of ownership: Apple cannot verify a Google purchase or the reverse.
- Before the store accounts exist: the server’s entitlement check is a pluggable verifier (D-58). Sync, enrollment and recovery are built against a development verifier; Apple’s local StoreKit testing and recorded signed transactions cover the Apple verifier. Sandbox purchases, TestFlight and Play Billing need paid developer accounts; Google may also require a closed test with a minimum number of testers before production, so open that account early.
- Family sharing, refunds, grace periods, billing retry: the server must handle the store notifications for each platform.
- Privacy disclosures: hosted sync changes the App Store privacy label and the Google Play data safety form (encrypted content, device identifiers, purchase records). Decide what we collect before writing them.
- README promises to update when sync ships: “no Jotry cloud service” becomes “an optional, end-to-end encrypted sync service; no account; we can’t read your notes”.
Simple by default, power when wanted
| Who | What they see |
|---|---|
| Everyone | The app works offline on one device with nothing to set up. Export is one tap in Settings. |
| Someone who wants their notes on two devices | One switch, “Sync across devices”, and a QR code to add a device. No folders, formats or links. |
| Power users | Settings → Advanced: folder sync, link format, “write Jotry properties to files”. Not shown unless opened. |
Folder sync is strongest on desktop (file watchers, background running, Obsidian/VS Code/git on the same machine), works acceptably on Android, and is fragile on iOS. Proposal: Android and desktop get folder sync; iOS gets hosted sync, and folder sync only as a manual “Sync now” if at all (see folder-sync.md Q8).
A desktop app is a separate product to build and support (D-07 keeps it a later phase). The repo’s webApp is not a substitute: a browser can’t keep a folder in sync.
Formats become a contract at release
Once people have folders and exports in the wild, the file format is something other apps and users depend on. Decide these before the first public release:
- relative links in exported files (D-36, decided)
- file names and the front-matter default (
folder-sync.mdQ1) - a format version in the managed-folder marker and in
EXPORT-INFO.txt
The hosted-sync record format is versioned from the first implementation, as doc 03 already requires.
Suggested order
- Export: relative links (D-36) and human file names. Small; builds the shared file-format code.
- Release 1 ships with the export format settled.
- Sync core (identity map, reconcile, conflicts), then Android folder sync (free; D-06).
- Server, crypto, QR pairing, recovery key, then hosted sync on Android and iOS (paid).
- Store billing and server-side receipt checks, tied to the sync group.
- Desktop app with folder sync and hosted sync.
Open questions
| # | Question | Proposed direction |
|---|---|---|
| Resolved by D-53: free app with a hosted-sync subscription. | ||
| M2 | Price, trial length, and whether there is a yearly plan. | Decide closer to release, after the beta. |
| Resolved by D-45: account-free sync groups with QR pairing and a recovery key (option A). | ||
| Resolved by D-52 and D-54: the server verifies store transactions and attaches each to the sync group. | ||
| Resolved by D-56: the group becomes read-only and the server keeps it for a year, then deletes it. Devices keep everything locally. | ||
| M6 | Storage limits on hosted sync (history can grow)? | Generous fixed limit per group; show usage; revisit with the revision-retention question in doc 05. |
| M7 | Is the server self-hostable for users who don’t want ours? | Desirable for the privacy brand; decide after the protocol is stable. Self-hosting would bypass billing, so it would be a deliberate choice. |
| M8 | Is folder sync on iOS worth building? | Probably not at first; see folder-sync.md Q8. |
| M9 | When does a desktop app happen, and on which technology? | After hosted sync; Kotlin Multiplatform with Compose Desktop is the natural first candidate (D-07). |
| M10 | Which metadata is collected for billing and abuse prevention, and how is it disclosed? | The minimum the stores require; document it with the threat model in cloud-sync-and-e2ee.md. |