Moo Jun Jie UI/UX Designer
Note 02 · 28 October 2026 All notes

An iPhone app with one user, built by sessions that forget.

值得 (Worth) tracks what I own and what each thing costs me per day. Claude wrote every line of the code, and I don’t read Dart. So my work was deciding what to build, writing it down so each new session could carry on, and having the final say on every screen.

My part
The idea, feature order, handoff rules, design review, testing on my iPhone
Built with
Claude, in Claude Code
Timeline
June–October 2026, three versions
Stack
Flutter and SQLite on the phone, built in the cloud by GitHub Actions
Status
Personal, in Chinese and English, installed on my own iPhone
Home screen: Hi, J / Worth it today, a black card with a total value of RM 13,349, RM 2.00 per day, 13 items and RM 741 of add-ons, then tag filters and a grid of item cards with emoji icons. Item page for a Moza R5 racing wheel: a cobalt card whose largest number is a cost per day of 6.61 RM, owned 277 days, total RM 1,830, with Slide to archive, then small cards for price, add-ons, purchase date and shop. Want list: a cobalt card for a DJI Pocket 4 listed at RM 1,599 with Slide: I bought it, two more cards peeking out behind it in purple and teal, and a want list total card below.

Fig. 01Home, an item, and the want list, screenshotted on my iPhone in the English version of the app.

What I did
  • Picked the question the app answers: what does each thing cost me per day?
  • Agreed the order of work: ten stages, each finished and saved before the next
  • Signed off the rules every new session follows, written into one roadmap file
  • Reviewed the redesign and changed it in four places
  • Chose the name and the icon, and tested on my own phone
What Claude did
  • Wrote the Flutter app, five database versions and 13 test files
  • Kept the roadmap up to date at the end of every stage
  • Set up the cloud build, because I don’t have a Mac
  • Drew the design system, the screen mock-ups and six icon options
(01) The questionWhy build it at all

Price tells you what you paid. Cost per day tells you if it was worth it.

I buy most things on Shopee and Lazada, and then I forget about them. My RM 4,600 laptop, used almost every day for nearly three years, now costs less per day than the RM 1,500 racing wheel I bought this January.

So the whole app is built around one number: the price, plus any upgrades, divided by the days I’ve owned it. On an item’s page, that number is bigger than the price. It falls every day I keep using the thing, and stops when I let it go.

A paid iOS app already does this. I wanted my own version, for me alone, without borrowing its name, icons or artwork.

(02) Three versionsJune–October 2026

A web page at home, then a copy on the phone, then an app of its own.

  • June: a web app on my home server.Next.js and SQLite in Docker on my NAS. It worked, but only on my home network, and it never felt like an app.
  • September: the same app, on my iPhone.A Flutter copy of the web version that works offline. I don’t have a Mac, so GitHub Actions builds it in the cloud and I install it myself. The nine items from the server came across in a JSON backup, with tags that had been escaped twice cleaned up on the way.
  • October: ten stages, a new name, a new design.Over two days: a wishlist, collections, a history of upgrades, warranty dates and reminders, receipt scanning, a year in review, then a full redesign and seven new analysis cards.

In the middle of that, Things Pro became 值得, “worth it”. Claude drew six icons and I picked the fifth: a box with five ticks on its side, like days on a calendar, with the last one blue.

Six app icon options numbered 1 to 6: a receipt with RM on it, a receipt with a blue tick, the Chinese character 值 with a blue dot, a W with a blue stroke, a white line-drawn box with five ticks on its side and the last one blue, and an archive box with a calendar of dots.

Fig. 02The six icon options. Number 5 is on my home screen now: it says “things” and “days” without words.

(03) HandoffOne file, read first

I can’t read the code, so I made sure the next session could.

Each Claude session starts with no memory of the last one. On a project this size that matters more than any single feature: a new session that guesses where things stand will happily redo or undo work.

So the project has one roadmap file, in Chinese, that every session reads before touching anything. It says what’s done, what’s next and what was decided, with the reason next to each decision. At the end of every stage, the session updates it.

On 27 October I signed off four rules, now at the top of that file:

  • Look before you start.Check the saved state first. Unsaved changes might be another session’s half-finished work, so never throw them away.
  • One stage, one save point.When a stage passes its tests, save it locally without asking me. Each stage can be rolled back on its own.
  • Never publish without asking.Nothing leaves my computer until I say so, and no save point gets rewritten.
  • Explain it to me as a user.Tell me what a change means for the app, not how the code works.

The rules also kept two sessions apart. The redesign ran in its own session, and the new features waited until it was finished, so the two never edited the same files at once.

Lesson

Every session forgets, but the file doesn’t. Writing down the reason, not just the decision, is what stopped the next session from undoing it.

(04) Data firstThe worst bug is an empty screen

The app holds real records, so every change has to keep them.

The scariest thing this app could do isn’t look bad. It’s to open after an update with nothing in it. So the roadmap has a section on changing the database, and it’s the one part that never gets skipped.

The database changed shape four times, and each change came with a test that builds the old version, fills it, upgrades it and checks nothing went missing. Old backups still import. Photos are saved by name instead of full path, after we found that a reinstall moves the folder and breaks every image.

The rename followed the same rule. The name on the home screen, the icon and the backup files changed. The app’s internal ID and data folder did not, because changing them would make the iPhone treat it as a brand-new app, with an empty database.

So did the English version, added last as a setting. Anything already stored stays in Chinese, like the four ways an item can leave, and is only translated on screen. Switching language changes nothing in the database or in a backup.

The lower half of an item page: an Add-ons card with two entries, Earlier add-ons RM 100 and a simulator stand RM 230, then a timeline running from Bought to each add-on to Now, owned for 277 days, then tags and collections.

Fig. 03Add-ons used to be one number. Now each has its own date, and the timeline is built from them. Older items got a single “Earlier add-ons” entry, so their totals didn’t change.

(05) Redesign28 October

The design system was a starting point. The screens had the final say.

For the redesign, Claude drew a design system first: a light grey canvas, white cards, one cobalt brand colour, black kept for cards about money and a lime used only for highlights. Then seven screens built from it, which I reviewed on a shared canvas before any code changed.

Most of it I kept. Four things I changed, and the file records each one as overriding the design system:

  • Items keep their emoji.The system used line icons throughout. But I spot my things by their emoji at a glance, so items keep them, and only the interface uses line icons.
  • One colour per wish.Wishlist cards take turns in cobalt, purple and teal, so the cards stacked behind the first one read as different things.
  • Filters sit next to what they filter.Tag filters moved from above the total card to just above the item grid.
  • No Liquid Glass.The canvas had a toggle for glass on the floating controls. I left it off, so the app ships with solid surfaces.
One item card, from the Chinese version of the app: a box emoji on a grey tile, a lime Best value badge, a grey Warranty 39 days left pill, the name ACASIS Disk Array, RM 117.30, and 0.36 RM per day over 326 days.

Fig. 04One item card, in Chinese: 最划算 means “best value” and 保修剩 39 天 “39 days of warranty left”. The item keeps its own emoji, and on the home screen lime marks just one item: whichever costs the least per day.

(06) ConfirmingMatched to what can be undone

Archiving is a slide. Deleting still asks.

Archiving something and marking a wish as bought happen often, and neither destroys anything: an archived item can be restored, and a bought item keeps its photo, tags and history. Both used to open a yes-or-no dialog. Now they’re a slide: deliberate enough not to happen by accident, quick enough not to feel like a form.

Deleting can’t be undone, so it stays a red button with a dialog. The archive sheet shows how long I kept the thing and what it cost per day before I commit, and the four ways to let go — sold, gifted, scrapped, lost — stayed, even though the mock-up left them out, because older records already use them.

The archive sheet for the Moza R5: owned for 277 days at 6.61 RM per day, How it left chips for Sold, Gifted, Scrapped and Lost, an archive date of today, Money back if sold, an optional note, and a Slide to archive bar.

Fig. 05Archiving my old iPhone 15 after 856 days, recorded in dark mode: slide on the card, pick Scrapped, slide again. Right, the same sheet in light mode.

(07) ReceiptsAI inside the app

The AI fills in the form. I still press Save.

Typing in every purchase is how apps like this get abandoned. So the add form starts with “Scan an order screenshot”: pick a Shopee or Lazada order, and a vision model reads the name, price, date and shop.

It fills in only what it recognised, says so in a blue note, and never saves by itself. A date in the future or a negative price counts as not recognised, and an order in another currency or with several items gets a warning. The API key stays on the phone and never goes into a backup.

Fig. 06A real Shopee order for a range extender: name, price, date and shop filled in from the screenshot, a tag added by hand, then saved.

Lesson

AI inside the app follows the same rule as AI in the process: it drafts, and a person confirms.

(08) Worth itThe analysis tab

The last question the app answers is the first one: has this paid for itself yet?

The analysis tab is grouped into money, worth it or not, and reminders. In the middle group, you set a line, RM 1 a day by default, and every item shows how many more days of use it needs before its cost per day drops below it.

It turns an old purchase into a small goal. The Edifier speakers need another 23 days. The chair and a pair of Nike Air Force 1s are already there.

Paying off card with a line of RM 1 a day: 7 items paid off, 1 within 30 days. Full green bars mark a KUCADI chair and Nike Air Force 1 shoes as paid off; black bars show Edifier MR4 with 23 days to go, a microphone with 144 and an Acer Predator monitor with 346.

Fig. 07Paying off, with the line at RM 1 a day. Green has crossed it; black shows how far each item still has to go.

(09) ScopeFor one person, on purpose

Built for one person, so some things were easy to say no to.

Left out
  • Login, accounts and cloud sync — one user, and a backup file is enough
  • Home screen widgets and Live Activities — not available to an app I install myself
Not yet
  • Warranty reminders, which may not fire for an app installed this way
  • Backups that include photos, so a new phone keeps them — later
(10) TakeawaysWhat I’d tell myself in June
  • Write down the reason, not just the decision.The next session only knows what the file says. A rule without its reason is the first thing to get “tidied up”.
  • Protect the data before the pixels.Migrations, backups and an unchanged app ID are invisible, and they decide whether I can trust the app at all.
  • A design system is a draft too.The mock-ups were clean and consistent. The four changes I made are what make it feel like mine.
Note 01

A keyboard driver, rebuilt for the browser.