Security

Your data mostly never leaves your phone.

Peak Fettle is built local-first. What does travel is encrypted in transit, backups are encrypted with a key only you hold, and payments never touch our servers at all. Here is exactly where everything lives.

Your iPhone

Every workout, set, weight, and health metric is written to a private database inside the app’s sandbox. On the free tier, this is the only copy that exists.

sqlite (on-device)
keys → ios keychain
free tier: 0 personal-data network calls

The wire

Anything that does travel — sign-in, Pro sync, backups — moves only over an encrypted connection. Nothing is ever sent in the clear.

https only
auth endpoints rate-limited

Our servers

Hold your account, Pro-tier sync data, and backups. Backups arrive already encrypted — the server stores them without the ability to read them.

postgres, encrypted at rest
backups: ciphertext only
no card numbers, ever

The key fact: for free users the second and third boxes are almost empty — the app is engineered, and machine-checked on every code change, to make no personal-data requests at all.

The layers

In plain English, and in full.

Local-first by design

Your logs live in a database on your phone, not in a cloud account. There is no server copy to breach unless you choose Pro sync — and our build pipeline automatically fails any code change that would quietly send personal data off-device.

store: on-device sqlite, app-sandboxed
enforcement: ci sweep bans off-device personal-data calls — every commit
free tier: zero personal rest calls

Backups only you can read

Cloud backups are sealed on your phone before upload. The key stays in your device’s Keychain, protected by a recovery code that is shown to you once and never stored anywhere — so not even we can open your backup.

cipher: aes-256-gcm, fresh iv per backup
key: 32-byte data key in ios keychain
recovery: key wrapped by recovery code; code never persisted — server sees ciphertext only

Sign-in done properly

Passwords are stored only as a slow one-way hash — we couldn’t read yours if we tried. Sessions use short-lived tokens kept in the Keychain, and Apple or Google sign-ins are cryptographically verified on the server, not taken on trust.

passwords: bcrypt cost 12, never plaintext
session: jwt access 15 min · refresh 30 d, rotated
oauth: rs256 signature + issuer + audience checked against apple/google jwks

Payments we never see

Subscriptions run through Apple’s App Store. Your card number never reaches Peak Fettle — we only receive a signed “this person is subscribed” signal, and the server refuses to let the app itself claim Pro status.

billing: apple storekit → revenuecat
webhook: shared-secret authorization; unauthenticated traffic rejected
tier: server-authoritative

No tracking baked in

There is no advertising SDK and no analytics harvesting. Even crash reporting ships switched off, and only ever activates if we explicitly configure it — with crash traces, not your training data.

ads / analytics sdks: none
crash reports: opt-in build flag, off by default

The honest fine print

  • Pro sync data is readable by the service. If you subscribe and turn on sync, that copy of your training data is processed server-side — that is what makes multi-device sync work. It is encrypted in transit and at rest, but unlike backups it is not end-to-end encrypted. Free-tier users are unaffected: nothing syncs.
  • Your account email exists on the server. Signing in requires it. Apple's Hide My Email is supported if you'd rather we never see your real address.
  • Your device is part of the model. On-device data is protected by iOS sandboxing and your passcode or Face ID — a strong default, but device security is the one layer only you control.

statements audited against the shipping build · questions: admin@peakfettle.app