Own product
Tidemark
Expo SDK 57 · React Native 0.86 · React 19 · TypeScript 6 · react-native-svg · @noble scrypt and XChaCha20-Poly1305 · StoreKit 2 via expo-iap · GitHub Actions → Pages on its own domain
Problem
A bathroom scale gives one number a day, and that number swings by a kilo or more on salt, water, sleep and a late meal. Someone doing everything right sees it go up on a Tuesday and concludes it is not working. That is the day most people stop.
Plenty of apps log weight. The ones that read the numbers properly tend to want an account, and weight, medication and body photos are health data — a special category under UK GDPR. So the interesting problem was not the maths. It was whether you can ship something useful without ever holding any of it.
Plenty of apps log weight. The ones that read the numbers properly tend to want an account, and weight, medication and body photos are health data — a special category under UK GDPR. So the interesting problem was not the maths. It was whether you can ship something useful without ever holding any of it.
Approach
You can, and the answer was to have no server and no account at all. Everything runs on the phone: the data lives in AsyncStorage and files, encrypted by iOS while the device is locked (
That decision is written down with its costs beside it, which is the part I would want to be judged on. No sync between devices. Lose the phone without a backup and the data is gone. No remote switch — a risky feature can only be turned off in a build, because there is nothing to turn it off from. The repository carries a standing rule that no SDK which sends anything off the phone may be added, analytics and crash reporting included: one of them breaks the privacy label, the policy and the paywall promise in a single commit.
The trend uses Holt’s linear smoothing (
Two details carry more weight than they look. Reminders never contain a number, and the medication reminder does not name the medication: a lock screen is visible to anyone stood near it. And backups can be password-locked with audited primitives — scrypt and XChaCha20-Poly1305 from @noble, with the system’s own randomness — rather than anything hand-rolled.
NSFileProtectionComplete), and the App Store privacy label reads Data Not Collected because it is true rather than because it was argued for.That decision is written down with its costs beside it, which is the part I would want to be judged on. No sync between devices. Lose the phone without a backup and the data is gone. No remote switch — a risky feature can only be turned off in a build, because there is nothing to turn it off from. The repository carries a standing rule that no SDK which sends anything off the phone may be added, analytics and crash reporting included: one of them breaks the privacy label, the policy and the paywall promise in a single commit.
The trend uses Holt’s linear smoothing (
src/core/trend.ts) rather than a moving average, so it follows the direction you are heading instead of trailing a week behind it. All of that maths sits in src/core as plain TypeScript with no React in it, close to fully unit-tested, which is why it can be trusted without a device in the loop. The charts are drawn by hand with react-native-svg — no chart library, so nothing to fight over dark mode or large text.Two details carry more weight than they look. Reminders never contain a number, and the medication reminder does not name the medication: a lock screen is visible to anyone stood near it. And backups can be password-locked with audited primitives — scrypt and XChaCha20-Poly1305 from @noble, with the system’s own randomness — rather than anything hand-rolled.
Outcome
One TypeScript codebase produces the iPhone app and a web build, developed without a Mac. CI runs typecheck, lint at zero warnings and the full test suite on every push, and fails if coverage drops below the floor recorded in
The deploy is least-privilege on purpose. The job that runs
Tidemark now has its own site, at tidemark.ysbdesigns.uk, and the old GitHub Pages addresses redirect to it. One workflow publishes the site, the privacy policy, the original single-file tracker it grew out of, and — at
It is on neither store, and the status of every feature is published rather than implied. There has still been no signed iPhone build: the company’s Apple Developer enrolment is in review. Its own site sorts features into three tiers and I am using its words, not mine — nine are in the app; Home Screen and Lock Screen widgets are built and in testing; and the Apple Watch app and complications are designs, not code, which that site says outright beside the pictures. Apple Health sync and automatic backups moved the other way since I last checked: both are built and the whole native app compiles in CI, but like the widgets they have never run on a phone, so its own copy rules keep them tagged in development until they do. iCloud sync and the Apple Watch app are not built at all. Three things are written and unit-tested but not proven on a device — buying and restoring Plus, iOS file encryption while the phone is locked, and the production hardening plugin. That a portfolio can be this specific about what is unfinished is the point of keeping the status in the repository rather than in someone’s head.
package.json — a test suite that is allowed to quietly shrink is one that stops meaning anything. A second workflow publishes the web app on every push to main, and a third loads the live app, its privacy policy and the older tracker every six hours and fails if any of them is down, so a broken deploy arrives as an email rather than as a discovery.The deploy is least-privilege on purpose. The job that runs
npm ci — and so every dependency’s install scripts — is granted contents: read and nothing else; only the separate deploy job holds pages: write. A compromised postinstall script on that build runner cannot publish anything.Tidemark now has its own site, at tidemark.ysbdesigns.uk, and the old GitHub Pages addresses redirect to it. One workflow publishes the site, the privacy policy, the original single-file tracker it grew out of, and — at
/app/, noindex — a web build of the app. That build is a test harness, not a product, and the repository labels it as one.It is on neither store, and the status of every feature is published rather than implied. There has still been no signed iPhone build: the company’s Apple Developer enrolment is in review. Its own site sorts features into three tiers and I am using its words, not mine — nine are in the app; Home Screen and Lock Screen widgets are built and in testing; and the Apple Watch app and complications are designs, not code, which that site says outright beside the pictures. Apple Health sync and automatic backups moved the other way since I last checked: both are built and the whole native app compiles in CI, but like the widgets they have never run on a phone, so its own copy rules keep them tagged in development until they do. iCloud sync and the Apple Watch app are not built at all. Three things are written and unit-tested but not proven on a device — buying and restoring Plus, iOS file encryption while the phone is locked, and the production hardening plugin. That a portfolio can be this specific about what is unfinished is the point of keeping the status in the repository rather than in someone’s head.
The screens



If this looks like your problem
Tell me about it and I'll tell you what it takes.