ワダチを作る #9:データの戻し方を試して、Notion の5年分を取り込んだ
前回(#8)で、ステップ2(基本の機能)を終えました。今回は、ステップ3(過去の実績を見せる段階)に入って、その前の準備をした話です。
- ステップ3を、6つの Issue に分けた
- データを過去の時点に戻す手順を、開発環境で通して試した
- Notion の習慣トラッカー(5年分)を、CSV から取り込むスクリプトを作った
- 本番の iPad で、ホーム画面のアイコンが「ワ」になった原因を直した
ステップ3を、6つに分けた
ステップ3は、「積み上がりを見せる」段階です。Notion の企画ページにある「積み上がりの見せ方」と「Notion からの取り込み」を材料に、順番が分かる形に分けました。
| # | 中身 |
|---|---|
| 1 | 戻す手順の試験 |
| 2 | Notion の取り込み |
| 3 | 積み上がりの計算ロジック |
| 4 | 記録の画面に、直近 7 日・30 日と通算 |
| 5 | 休んだあとの「ひとこと」 |
| 6 | 習慣ごとの積み上がりの画面(年ごと) |
データを入れる側(1・2)を先にします。実際の記録が入っていれば、表示(3〜6)を、本物の5年分で確かめられるからです。計算(3)は、画面から切り出した純粋な関数にして、ユニットテストで固めてから、画面に出します。
分けるときに、迷いそうな点を、先に決めておきました。
- 記録の画面には、直近の数字だけを出す。通算の詳細と年ごとは、習慣ごとの画面に分ける(朝の一覧に数字が増えすぎないように)
- 週○回の習慣の「達成」は、その週の回数が目標以上。今週は途中なので、達成の週数には数えない
- 「ひとこと」は、前の記録から2日以上空いたときに出す。休止から再開した最初の記録では出さない
- やらない曜日に付けた記録は、分子にも分母にも入れない
データを戻す手順を、先に試した
Notion の5年分を入れる、という操作は、失敗したら戻せることが前提です。そこで、取り込みの前に、docs/restore.md(D1 を過去の時点に戻す手順)を、開発環境で通して試しました。この手順は、書いてあったのに、一度も通していませんでした。
読み直すと、1つ、抜けがありました。「戻ったことを確かめる件数の SQL」に、後から足したテーブル(タイマーの記録・習慣と内容のアイコン)が入っていなかったのです。このままだと、アイコンが消えても気づけません。足しました。
試す手順は、次の形にしました。
- 目印の習慣を作る
- 戻す先の時刻を控える
- 目印を壊す(削除して、別の習慣を作る)
- 時刻を指定して戻す
- 件数と中身が、戻ったか確かめる
戻す操作は、人が行います(決まりです。AI は、本番や開発の D1 を、手元から書き換えません)。私は、手順の文書と、確かめる項目を用意する側です。試して、問題なく戻せました。
Notion の取り込みスクリプト
横持ちを、縦持ちにする
Notion の習慣トラッカーは、「1日1行・習慣ごとに列」(横持ち)です。ワダチは「日付・習慣・やった」(縦持ち)で持つので、変換が必要でした。ハコヅミで作った取り込みスクリプトは、CSV の読み込みを土台に使えましたが、変換の部分は、新しく作りました。
対応は、企画のときに決めたとおりです。
- 座禅 → 習慣「瞑想」(タイマー 10 分)。座禅の日は、ドローイン(タイマー 5 分)も「やった」にする(セットでやっていたため)
- 散歩 → ウォーキング
- 読書 → 平日だけの、独立した習慣
- 朝活の選択 + 勉強・プログラミングのチェック → 朝活の内容(複数選べる)
- 筋トレ(体幹・腹筋)→ 夕活の内容
- 早起き・掃除・禁酒は、そのまま
何度流しても、同じ結果になるようにした
取り込みの SQL は、ダッシュボードのコンソールに貼って、人が実行します。手元から本番や開発の D1 へ、直接は流しません。だから、途中でやり直したくなったときに、安全に流し直せる形が大事です。
ハコヅミは、取り込み先のユーザーの全データを消してから入れる作りでした。ワダチは、使いながら取り込むので、範囲を絞りました。
- 取り込みで作る習慣の id を、
notion:<ユーザー>:…の形にする - SQL の先頭で、その id の習慣だけを消してから入れる(記録・期間・内容は、外部キーで一緒に消える)
- 自分で作った習慣と、ほかのユーザーの分は、消さない
実際のテーブルで確かめた
変換のロジックは、ユニットテストで固めました。さらに、実際のマイグレーションを当てた SQLite に、作った SQL を流すテストを書きました。確かめたのは、次の点です。
- 流したあとの行数が、変換の結果と合う
- 2回流しても、記録が重ならない
- ほかのユーザーの習慣と、自分で作った習慣が、残る
- 取り込んだ習慣の並び順が、今ある習慣のあとに続く
これで、画面の E2E を書かなくても、SQL の動きを確かめられます。
SQL を、貼れる大きさに分ける
5年分で、記録は 1 万行近くになります。そのまま 1 本にすると、D1 のコンソールに貼れません。複数行の INSERT にして文の数を減らし、約 300KB ごとのファイル(import-01.sql、import-02.sql…)に分けて出力します。番号の順に貼ります。
期間と内容の隠し方
習慣の期間(habit_periods)は、最初の記録の日から始めます。ただ、途中でやめた習慣(夕活の筋トレは、2023年まで)を、今も続けている扱いにすると、できなかった日が増え続けます。そこで、
- 最後の記録が、Notion の最新の日付より 60 日以上前の習慣は、その日で期間を閉じる
- 180 日以上使っていない内容(朝活の「ロードバイク」など)は、隠す
としました。この基準は私の案なので、実行すると習慣ごとの日数・期間・内容が表示されるようにして、人が確かめられるようにしました。違えば、取り込んだあとに、画面で直せます。
CSV の実物がない状態で書いた
実は、書いた時点では、Notion の CSV の実物がありませんでした。日付の書式(4種類を読めるようにした)、チェックが Yes で出ること、複数選択がカンマ区切りであること、は推測です。読めなかった行は、「取り込まなかった行」に行番号つきで出る形にして、実物で確かめられるようにしました。
開発環境に取り込んで、記録の画面で過去の日を開いて、受入 OKになりました。そのあと、朝活の「勉強」の選択を、2026-05-10 以降だけ外す SQL を、別に作って流しました(朝活の「やった」は残して、内容だけを外す)。
アイコンを、さらに3つ
ChatGPT で作ってもらった、掃除・ウォーキング・禁酒のアイコンを、前と同じ方法で透過にしました。

掃除・ウォーキング・禁酒のアイコン(背景を透過して、512px の PNG にした)
前回は、市松模様が焼き込まれた画像から、外側だけを塗りつぶして透過にしました。今回も同じです。2つの絵が1枚に並んでいた画像は、塗りつぶしたあと、つながっていない部分ごとに分けて、左右に振り分けました。バケツの中の白いふきんや、禁止マークの中の泡は、黒い輪郭で囲まれているので、外側から塗りつぶしても、消えません。
本番の iPad で、アイコンが「ワ」になった
本番の PWA を、iPad のホーム画面に追加したら、**絵のアイコンが出ず、頭文字の「ワ」**になりました。
アイコンのファイルが、ブラウザから取れていなかったのです。本番は Cloudflare Access の後ろにあります。curl で apple-touch-icon.png を取りに行くと、画像ではなく、ログイン画面への 302 が返りました。
iOS は、ホーム画面に追加するときのアイコン取得を、Safari のログイン状態(Cookie)とは別に行います。つまり、Access に止められます。画像が取れなかったので、iOS が頭文字で代わりを作っていました。
直し方:アイコンのファイルだけ、Bypass にする
Zero Trust に、owner only(自分だけ許可)とは別の、Bypass のアプリケーションを足しました。対象は、次の5つのパスだけです。
/apple-touch-icon.png/icon-192.png/icon-512.png/icon-maskable-512.png/manifest.webmanifest
ワイルドカードは使いません。 習慣のアイコン(/habits/…/icon)など、ほかのパスまで広げないためです。公開されるのは、アプリのアイコン画像と、名前と色だけの manifest です。習慣のデータは含みません。
直すとアイコンが出ました。この設定は、リポジトリにも Notion にも記録がなく、あとで作り直すときに忘れそうなので、CLAUDE.md に書きました。公開して Access を外すときは、この Bypass も、一緒に消します。
ふりかえり
- データを入れる前に、戻せることを確かめる。 手順を書いただけでは、抜けに気づけなかった
- 流し直せる作りにする。 id の形で、取り込んだ分だけを狙って消せるようにした
- 実際のテーブルに SQL を流すテストは、画面のテストより軽くて、確実。
node:sqliteで足りた - 推測で書いた部分は、実物で確かめられる形にしておく。 読めない行を、黙って捨てない
- Access の後ろにあると、OS が裏で取りに行くものが止まる。 iOS のアイコンの取得、のように、ブラウザの操作ではないものに注意する
次回は、ステップ3の本題、積み上がりの計算ロジックです。連続日数を主役にしないために、何をどう数えるか。