PERSONAL FINANCE / PRIVATE PRODUCT

Money

Turning years of real bookkeeping habits into a private, local-first, cross-device product that can be recovered.

Role
Product designer and design engineer (service architecture / data migration)
Time
2026 · 24h first release, ongoing
Platforms
Mobile Web / Desktop Web / PWA

One track handles daily recording. The other keeps the data owned and recoverable.

Case at a glance

Problem to solve
  • 封闭工具里的多年私人数据,怎么迁成可信、低摩擦、可长期维护的个人产品。
Role & contribution
  • Owner / Product Engineer:从真实个人工作流出发,覆盖产品、设计、前后端、数据迁移与发布。
Key decisions & tradeoffs
  • 采用 Worker + D1 作为事实源,IndexedDB 作为本地读取层。
  • 停止扩展功能,优先修复真实使用中的加载与历史浏览。
Results & impact
  • 在约 24 小时自然时间内完成从 demo 到生产服务的闭环。
  • 形成可验证、可导出、可恢复且持续使用的私人记账系统。
Validation & support
  • 15 个阶段提交与完整架构、验证、备份文档。
  • 生产站点、移动端截图及自动化发布门禁。
Scope & boundaries
  • 真实财务数据必须保持私密。
  • 移动端体验优先,但只维护一套 Web/PWA 代码。

01 / Context

Not another expense UI

The real problem was moving years of private data out of a closed tool while preserving fast mobile entry, desktop analysis, and long-term recoverability.
Early Money desktop ledger prototype
Early prototype

The early demo established the visual direction, but data, sync, and history were still simulated.

Early Money mobile analytics prototype
Early prototype

The early mobile chart validated the monochrome-yellow language while exposing crowded periods and weak state feedback.

01

02 / Framing

Fix the taxonomy before the entry flow

  • Categories represent spending domains; subcategories represent concrete items.
  • One home per item reduces hesitation and analytical noise.
BEFORE场景 × 物品 × 行为

按摩 / 厨具 / 游泳散落多处

AFTER12 个消费领域

一个事项,一个稳定归属

Product brief and category seed

The taxonomy moved from mixed contexts, objects, and behaviors to twelve spending domains.

02

03 / Decision

One PWA, two densities

  • Mobile handles fast entry, search, and refresh.
  • Desktop handles period analysis, drill-down, and organization.
  • No native app and no premature offline-write conflict system.
Money desktop analytics with period navigation, spending trend, and category ranking
Local synthetic build

Desktop keeps period decisions, trend, and category drill-down in one workbench.

Money mobile expense entry sheet with numeric keypad and category choices
Local synthetic build

Recording is a global action; amount, category, item, and date stay in one bottom-sheet flow.

Money mobile analytics with current month trend and category ranking
Local synthetic build

Mobile keeps the same analytical logic while showing only the period and metrics needed for the current decision.

Money mobile search with progressively loaded historical results
Local synthetic build

Search spans notes, concrete items, and categories, progressively traversing full history with stable cursors.

01Responsive PWA
02IndexedDB
03Same-origin API
04Worker
05D1
Architecture record

D1 preserves truth while IndexedDB makes historical content immediately available on-device.

03

04 / System

Immediate locally, truthful in the cloud

Private structured data stays out of the service-worker HTTP cache. IndexedDB handles local reads; Worker and D1 own authentication and truth.
01OPEN
02LOCAL
03VISIBLE
04VERIFY

先显示本机历史,后台静默校验;退出即清除私人缓存。

Caching decision

Read locally, validate in the background, and clear private caches on logout.

记录输入

幂等写入

确认即时刷新

主库读取

分析下钻

周期查询

导出下载

鉴权生成

恢复重建

备份校验

USER / FRONTSTAGE / BACKSTAGE

Service audit

Entry, sync, analysis, export, and recovery are treated as one service chain.

04

05 / Iteration

Real use exposed the feeling of waiting

Mobile slowness was not just API latency. Fixed periods, repeated network reads, and oversized loading states amplified loss of control, leading to full-history cursors, local-first reads, and in-place feedback.
BEFORE整块等待

大型 spinner

AFTER内容保留

原位进度与低对比骨架

Interaction iteration

Large spinners gave way to in-place progress and quiet skeletons.

05

06 / Delivery

Done means the data can come back

  • Real auth, CRUD, search, export, and category management.
  • Migrations, backup, restore, and release smoke checks.
  • A private product with no public registration or invented commercial proof.
0114 tests
02D1 migrations
03CSV / JSON
04Backup
05Restore
06Leak scan
Repository verification

Tests, migrations, export, backup, and restore define what done means.

06

Experience in depth

Pain points, user stories, and interaction design

Not a tech stack section. This is about the situation people are in, where they get stuck, and what I did about it.

My pain points

Every project here starts from somewhere I personally got stuck.

  1. P01

    Years of ledger data locked inside a closed app: no real export, no way to change how it works, and switching devices meant starting over.

  2. P02

    Logging one expense took account, category, subcategory, amount, and confirm — impossible to finish standing at a checkout counter.

  3. P03

    Answering "how much did dining cost last month, and which transactions were they" meant jumping between a report page and a list page.

  4. P04

    The old category system mixed situations with objects ("takeout" next to "food"), so every entry required a small decision.

  5. P05

    A cloud ledger means my real financial data lives on someone else's server. I was not willing to accept that.

User stories

Written as "as … I want … so that …", each mapped to a verifiable product action.

  • US01

    As someone at a checkout counter, I want to log an expense in seconds and see it in today's ledger immediately, so I never have to reconstruct it later.

  • US02

    As someone doing a monthly review, I want to drill from year / month / week trends into the actual transactions, so I can see where the money really went.

  • US03

    As someone who only remembers a vague impression, I want keyword search across all historical notes, so "that shop last time" is enough to find the entry.

  • US04

    As the owner of this data, I want to export and restore the full ledger at any time, so a broken system never costs me years of records.

  • US05

    As a multi-device user, I want mobile for capture and desktop for organizing, so each device does what it is good at.

Experience journey

In real usage order: what they are doing, where it hurts, how the product responds.

StageWhat they are doingFrictionProduct response
01Capture
Standing in a shop, one hand on the phone, a few seconds to record the expense.
Most tools need five steps before the entry is stored, and a standing user abandons halfway.
Capture is the top mobile priority: amount first, idempotent writes so a flaky-network retry never doubles the entry.
02Sync
Logged on mobile, continued on desktop in the evening.
Full-screen loading breaks the rhythm of logging several entries in a row.
No full-screen loaders. Progress becomes a quiet inline indicator, and IndexedDB serves stale-while-revalidate so local content appears first.
03Review
End of month, trying to understand where the money went.
Reports and transaction lists usually live on separate pages, so an anomaly is not clickable.
Year / month / week trends stay continuously drillable into categories, dates, and transactions — every number opens into the entries behind it.
04Search
Only "that shop last time" is remembered — no amount, no date.
Category browsing is useless against fuzzy memory.
Global keyword search spans notes, subcategories, and categories, with stable cursor pagination for progressive loading of full history.
05Own
Checking that the system will not hold the data hostage.
Exports from closed tools are usually partial, so switching tools means losing history.
Export, backup, restore, and migration stay part of the release flow; the live app keeps private login with no public signup.

Interaction details

The micro-decisions that make it feel fluid or clumsy.

Amount first
The entry screen opens with the cursor in the amount field and a numeric keypad; the category defaults to the previous choice.
No full-screen loading
Loading is carried by thin inline indicators. Content always arrives before progress.
Idempotent writes
Every submission carries an idempotency key, so retries and double taps never create a second entry.
Local answers first
IndexedDB uses stale-while-revalidate so transactions, charts, search, and category detail render instantly on-device.
Stable cursor pagination
Full history and search results load progressively without shifting a list that is already being scrolled.
Split by device
Mobile only carries capture; category management, export, and bulk edits happen on desktop.

Design details

Tradeoffs in the visual system, state language, and pacing.

Monochrome workbench, one accent
The black-and-white workbench continues, with yellow reserved for capture, selection, and sync states — never decoration.
Integer cents
Amounts are stored and rendered as integer cents to avoid float drift, set in tabular figures for vertical scanning.
Rebuilt taxonomy
The old mixed taxonomy became 12 spending domains with single-parent subcategories, removing same-level ambiguity.
One visual system across depth
Charts and lists share a single scale and typographic rhythm so drilling from trend to transaction never breaks visually.
Two densities
Mobile enlarges touch targets for one-handed reach; desktop raises information density for analysis and bulk work.