ワダチを作る #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」に、後から足したテーブル(タイマーの記録・習慣と内容のアイコン)が入っていなかったのです。このままだと、アイコンが消えても気づけません。足しました。

試す手順は、次の形にしました。

  1. 目印の習慣を作る
  2. 戻す先の時刻を控える
  3. 目印を壊す(削除して、別の習慣を作る)
  4. 時刻を指定して戻す
  5. 件数と中身が、戻ったか確かめる

戻す操作は、人が行います(決まりです。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 で作ってもらった、掃除・ウォーキング・禁酒のアイコンを、前と同じ方法で透過にしました。

掃除(ほうきとバケツとスプレー)、ウォーキング(歩く人)、禁酒(ビールのジョッキと瓶に禁止マーク)の3つのアイコン。茶色と橙の砂漠の絵柄で、明るい背景の上に置いている

掃除・ウォーキング・禁酒のアイコン(背景を透過して、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の本題、積み上がりの計算ロジックです。連続日数を主役にしないために、何をどう数えるか。

← トップページに戻る