Inspiration

I built ThisDay for myself.

I had a voice memo on my phone about something I needed to do on a Tuesday. Tuesday came and went. The memo was still there, perfectly recorded, telling nobody anything. My phone could capture the thought but couldn't hand it back to me at the moment it mattered.

That is the whole problem in one sentence. Every app I tried gave me a backlog; a someday pile that grows faster than I can clear it, when what I actually needed was a day. Tasks in one app, notes in another, voice memos in a third, habits in a fourth, and my calendar sitting off to the side pretending none of it existed.

So the brief I wrote for myself was: Not someday. This day. One day, in the order it happens, holding every kind of thing; and anything in it can remind you.

I wasn't building a product. I was building the thing I wanted on my own phone. The store listing came a long way after the first commit.

What it does

ThisDay is a native SwiftUI planner for iPhone, iPad and Mac where every kind of item lands on a real date.

One list, five kinds of thing. Tasks, events, notes, voice memos and habits share a single agenda, because they share a single day. A habit at 10:00 sits between the 9:00 task and the 11:00 meeting, where it belongs, same row, same swipe, same checkbox, whatever kind it is. Your own calendars appear inline, so a morning with a meeting in it doesn't look free.

Everything can remind you. This is the part nothing else does. Record a voice memo and put a reminder on it. Write a note and have it find you at 6pm. That's the gap I originally hit, and it's the app's subtitle: Even voice notes remind you.

Habits that tick themselves. Point a habit at Apple Health: steps, exercise minutes, active energy, sleep, the Watch's three rings, workouts; set the number you're aiming at, and stop reporting on yourself. The rings are drawn as rings, filling as your day fills them. But a habit is never marked done because a sensor said so and you disagreed: no reading is never "done", and your own tick always wins over the watch that was on the charger.

Nothing gets buried. Unfinished work rolls forward to today instead of quietly aging on a date you already passed. An inbox holds anything captured but not yet sorted, so capture never has to be a decision.

Moments. Keep one photo from a day worth keeping. Months later it's still filed under the day it happened on. This is the half of the product statement people don't expect from a planner: Plan your days — and keep the ones worth remembering.

Plus widgets and Lock Screen complications, Live Activities and the Dynamic Island, App Intents and the Action Button, a share extension, a real Mac app with a ⌘K command palette, iCloud sync, and no account, no sign-up, ever.

How we built it

Solo, native, no shortcuts.

  • SwiftUI, one multiplatform target for iPhone, iPad and Mac, generated with XcodeGen from a single project.yml. The Mac takes its own bundle ID via a [sdk=macosx*] override, same target, same 175-odd Swift files, one xcodegen generate.
  • SwiftData + CloudKit in a private container for sync. No server, no backend, no account. Media (voice notes, moment photos) rides on the record as @Attribute(.externalStorage) so CloudKit carries the actual bytes as a CKAsset, not just a filename.
  • A design system first, features second. Colours, spacing, radii and type live in a tokens layer, and the whole app follows one written shape rule: every control is a rounded rectangle, never a capsule. There's a companion design file with 79 frames — 35 iPhone, 34 Mac, plus reusable components — that the code is checked against.
  • A branded interaction language rather than stock components: a custom swipe row, multi-select, popup menu, segmented control, and the "Day Bar" — a bottom bar that is the app's focus. It grows upward as one connected card to show a "Day Alert" (a short, actionable notice with an Undo), rather than floating a toast over the content.
  • Monetization with RevenueCat. ThisDay is a one-time purchase, not a subscription — I'm not charging rent on someone's own calendar. It's sold the Things way: iOS and macOS as two separate purchases, one RevenueCat project, one default offering with a single $rc_lifetime package holding both products, and two entitlements (ios_lifetime, macos_lifetime) so each platform asks for "the unlock" and receives its own store's product. The paywall reads its offering from RevenueCat, so pricing and packaging change without shipping a build.

Everything after the first build was driven by testing on my own iPhone and fixing what annoyed me, in rounds.

Challenges we ran into

The failures that report success. iCloud sync was the worst of them, because it lied. CloudKit is only offered to sandboxed Mac apps — without the app-sandbox entitlement the container silently fails to attach, the app falls back to a local-only store, and Settings cheerfully says "iCloud Sync: on" while the Mac syncs nothing, forever. Separately, only the records were syncing, so a voice note captured on the phone arrived on the Mac permanently stuck at "Recorded on another device." Both looked like success. The fix was a status object that records which store path was actually taken and reports it honestly, plus a reconciler that keeps file and record in step in both directions.

The bug that deleted every recording one frame later. Cancelling a recording deletes its file. The recording view called cancel on disappear — so stop() had to explicitly clear the store key to transfer ownership, or every saved recording was destroyed a frame after you saved it. It presented as "voice notes won't play."

Two stores, two vocabularies. The Mac App Store rejects the non_consumable product type and wants one_time; iOS wants non_consumable. Same product, different word. RevenueCat support had to enable the Mac App Store app type on request before I could even create the record.

A predicate that silently matched nothing. Force-unwrapping an optional inside a SwiftData #Predicate doesn't crash — it just quietly returns an empty result. Nothing is louder than a query that fails by finding nothing.

Desktop is not "iOS on a big screen." CommandGroup(after: .textEditing) produces no Edit menu item at all. SwiftData records no undo history until you hand its context an UndoManager. And claiming plain ⌘C/⌘V at app level beats the responder chain and breaks copy/paste inside every text field in the app — so task copy/paste is ⇧⌘C/⇧⌘V, deliberately.

Changing my own mind in public. The design doc said "No dark mode" — twice. Then I used the app at night. Dark mode became a formal amendment to the design system, and it forced a real constraint: the accent colour inverts to near-white in dark, so anything drawn on top of it has to use a semantic on-accent token and never a literal white.

Accomplishments that we're proud of

  • It's the app I actually use every day. That was the only success criterion at the start, and it's still the one I trust most.
  • Voice memos that remind you. A small feature that fills a real hole in what a phone can do out of the box, and it's the app's one-line pitch.
  • Health-backed habits that still respect you. Rings that fill themselves, but a tick you can always override. Getting the ethics of automatic tracking right mattered more to me than the integration itself.
  • A design language, not a component dump. The Day Bar, the connected Day Alert with Undo, the shape rule written down and enforced — the app looks like one thing made by one person on purpose.
  • A genuinely native Mac app, not a catalyst afterthought: command palette, menu commands, proper undo, hidden title bar, keyboard shortcuts.
  • A monetisation model I can defend. Buy it once. No account, no sign-up, no subscription, no analytics on your day.

What we learned

Build for one real user first — even if that user is you. Every feature that survived came from an actual moment of friction on my own phone. Nothing invented in the abstract made it through.

Distrust anything that reports success. The two worst bugs in this project both had green checkmarks on them. I now write status objects that record which path the code actually took, rather than which path it was supposed to take.

Design decisions belong in writing. The shape rule, the dark-mode reversal, the icon licensing gap — all of it lives in a design doc that gets amended. Otherwise you relitigate the same choice every three weeks and lose.

Billing is a product surface, not a plumbing task. Putting products, entitlements and packaging in RevenueCat meant the interesting question stopped being "how do I code this" and became "what should I actually charge, and for what?" One-time versus subscription, two platforms versus universal purchase — those are product decisions, and I got to make them instead of implementing StoreKit twice.

The store is a design problem too. A 30-character app name, a 30-character subtitle and 100 characters of keywords are the tightest constraints in the whole project. ThisDay alone was already taken — the suffix in ThisDay: Planner & Reminders is load-bearing, not decoration.

What's next for ThisDay

  • Ship it. iOS and macOS to the App Store, with the launch promotion and the THISDAY1 easter egg live behind the site.
  • Deepen Moments into a real photo journal — the "keep the days worth remembering" half of the promise still has the most room in it.
  • Smarter rollover and planning: suggest where unfinished work should actually land tomorrow, instead of just moving it.
  • Apple Watch, so a habit can be ticked from the wrist that measured it.
  • Sharper Health habits — more metrics, better goal shapes than a single number.
  • iPad as a first-class surface, with the Mac's keyboard and multi-select affordances brought across.
  • And the quiet one: keep it a one-time purchase with no account. Whatever else grows, that doesn't change.

Built With

Share this project:

Updates

Submission history