Futari 開發日誌 3:離開也保留陪伴,守護成為自己的模組

2026-05-11 — 2026-05-14 · v0.15.0 → v0.16.1


v0.14.2 merge 進來那天,我停下來看了一眼 backlog。

#79,離開群組。這個 issue 我掛了很久,因為設計上很難。技術上不難——寫個 server action,把 member_b 設 null,資料清乾淨就好。難的是:當一段關係結束的時候,這個工具裡記下的那些共同的事情,要怎麼處理?

我的答案是:不刪除,但把它封進一個章節裡。


章節(epoch)這個概念是這個版本的核心設計。每個 group 在任何時間點只有一個 open 的 GroupEpochended_at IS NULL),代表「現在進行中的這段關係」。當有人離開,或者有人重新加入,舊的 epoch 關閉、新的 epoch 開啟。transactions 跟 settlements 透過 transacted_at 落在哪個 epoch 來做歸屬,不是靠 FK 硬連。

/past-times 頁是翻歷史用的:你可以看到過去每個章節裡的帳目,但那些是唯讀的。當前章節的 records 跟 stats 預設只看 current_epoch_started_at 之後的資料。

這個設計解決了一個讓我糾結很久的問題:如果有一天兩個人分開了,再各自記帳,舊的帳不能消失,但也不能混進新的數字裡。章節的邊界讓兩件事都成立。

leave group 的 UI 流程是四張卡片:警告 → 確認 → 愛物處置(哪些愛物帶走、哪些留著)→ 完成。member swap 的流程也重新整理過了。partner-left 跟 welcome-solo 的卡片在對方離開後顯示,不是冷冰冰地消失,是一個溫柔的交接。

v0.15.0 在 5/12 落地。


v0.15.1 是細節的累積,但細節的密度很高。

愛物 detail page 的 header navigation 統一了(#161),所有類型的返回按鈕、名稱、編輯入口都對齊到同一個 30px 高度的 row。分類色點的邏輯重新整理:每個 Category 只宣告一個 primary colortintlightenHex() deterministic 推得,不再分別維護兩個色值。這個改動讓「在 feed icon 跟 donut slice 之間用同一個 hue family」這件事變得自然,以後新增分類只要給 colorink,不用再選 tint。

balance 的 pending toggle 也在這個版本加上——pending 狀態的紀錄不計入 balance,這讓「你記了一筆但還沒確定要不要算」的場景有了正式的支援。

保險的被保人從自由文字欄位改成可以關聯 group member(自己或對方)。這是一個看起來很小的改動,但它的語意很重要——被保險保障的是這個家裡的某個人,那個人應該是一個有 profile 的存在,不是一串文字。


v0.15.2 是三個方向的擴展同時進來。

PartnerQuiz(#187):兩個人互相出題,測試你對對方的了解。這個功能的定位是「陪伴的細節」,不是記帳功能,但它是這個工具的第二條腿——Futari 不只是記帳,也是積累兩個人彼此了解的地方。

保險子頁面正式合併到守護(Guardian)模組。守護的概念是:保險、重要文件、緊急聯絡人這類「需要保護的東西」有自己的模組,不是塞在愛物清單裡。

/past-times 的跨 epoch 歷史也完整了:以前只能看當前 epoch 的帳,現在可以翻任意一個歷史章節,filter 也正確地以章節邊界為範圍。


v0.15.3 是邊界的結構化。

過去章節的資料變成正式的唯讀——不是只是 UI 不顯示編輯按鈕,而是在 query predicate 層就過濾掉:所有讀取的地方都強制加上 epoch 範圍,確保當前頁面不會顯示到前一個章節的資料。

投資型保單帳戶價值在這個版本加進來:儲蓄險跟投資型保單的運作方式不一樣,投資型保單有一個「帳戶價值」隨時間浮動,可以跟 RecurringIncome 關聯——每次系統提醒你更新帳戶價值的時候,你確認之後就是一筆收入紀錄。這個設計讓保險的資料不是靜態的,而是跟你的真實狀況同步的。


v0.16.0,守護成為自己的模組。

我在 Settings 加了一個 guardian_beta_enabled 的閘門,單一控制點在 lib/guardian.ts#canAccessGuardian。現在是 beta flag,將來付費層 cut-over 的時候只要動這一個函式。nav 上的守護入口、所有守護相關的頁面,都繞過這個閘門控制可見性。GatedView 元件負責在 beta-off 的狀態下顯示「這個功能即將推出」的佔位。

愛物模板系統(#222)也在這個版本出了。之前每種愛物類型都要開一個子表,但有很多「類型」其實不需要那麼複雜——比如一台咖啡機、一個單車,它們是「物品」,不是「車輛」或「孩子」。item 類型走 template path:template_key + template_fields jsonb,不開子表,但可以透過 template 定義顯示哪些欄位、怎麼顯示。這個設計讓愛物系統可以擴展到任意物品,不需要每次都動 schema。

Records 的愛物篩選也在這個版本細分:支援按愛物類型分 sub-section,讓「這個月所有跟車有關的花費」這樣的查詢變得直覺。


v0.16.1,守護後的細節收尾。

角色色:member_amember_b 的 avatar 背景色正式分化——深咖啡跟橘,呼應 Futari 愛心 icon 的配色。這是一個很小的視覺改動,但它讓「誰付的」在 feed 裡的識別變得更直覺,不用看名字就知道是哪個人。

收入篩選修正:solo 模式下,進帳的 mode toggle 之前在某些路徑下沒有正確接通,這次修好了。

被保人自己/對方:上個版本加了被保人可以關聯 group member,這個版本完整了邊界條件——edit 時如果 policy_holder 是 NULL,預設填入 viewer,不讓空值流進表單。保險從愛物 TypePicker 隱藏起來(因為它現在屬於守護模組)。

兩條清理:一條是移除不再使用的 import 跟 dead code,另一條是補了一條 corrective migration,修正 v0.15.0 引入的 epoch DEFAULT 值設定問題。


5/14 的今天,Futari 是這個樣子:

一個記帳工具,只給兩個人用。支出、進帳、定期支出、定期收入、加權分攤,基本的記帳功能都有。愛物系統讓你把生活裡有意義的東西放進來——車、房子、孩子、寵物、植物、保險、任意物品。守護模組剛剛從愛物裡分離出來,之後會放更多跟保護這個家有關的東西。月度回顧讓你跟對方在每個月初回頭看一次,當月發生了什麼。

還有很多東西在 backlog 裡等著。Landing page、CSV 匯入讓從 Honeydue 出走的用戶可以搬家、AI 洞察、圖表深化、支出分析。v1.0.0 的目標是公開——真正讓外人用得到,而不只是我跟太太的私人工具。

這兩個星期我幾乎每天都在動這個 codebase。不是因為有 deadline,而是因為每次開啟它,都覺得還有更貼近真實生活的方式可以做。

這大概就是自己做工具的感覺。