ハコヅミを作る #30:アカウントの画面と、データのエクスポート、退会を作る
前回(#29)は、運営の側の機能でした。今回は、利用者の側です。公開するなら、利用者が自分のアカウントを見て、データを持ち出して、やめられることが要ります。
- アカウントの画面と、表示名(#140)
- 自分のデータのエクスポート(#142)
- 退会(#144)
アカウントの画面

アカウントの画面(データは架空)。エクスポートと退会の入り口も、ここに置く
出すのは、自分の情報だけです。メールアドレス、会員区分、登録した日、表示名、そして前回作った上限に対して、今いくつ使っているか、です。
表示名は、Google の名前と分ける
Google アカウントでログインすると、Google に登録した名前が手に入ります。多くの人は、本名です。
将来、キャンプの記録やおすすめのギアを、ほかの人に見せる機能(共有)を作るつもりです。そのとき、本名がそのまま出てしまうと困ります。そこで、表示名を、Google の名前とは別の列で持つことにしました。
決まりは、1つだけ強く書いています。表示名が未設定のとき、Google の名前を代わりに使わない、です。何もしなかった人の本名が、勝手に出ないようにするためです。
共有はまだ先なので、今は、アカウントの画面にしか出していません。それでも先に作ったのは、あとから「表示名を決めてください」と全員に頼むより、最初からあるほうが楽だからです。
テストが見つけた、使っていないデータ
「未設定のとき、Google の名前が使われない」ことを、E2E で確かめました。画面に名前が出ていないことに加えて、画面に渡しているデータの中にも入っていないことを見ます。
これが落ちました。Google の名前が、全部の画面に渡すデータの中に入っていたのです。
ログインを作ったとき(#27)に、ヘッダーの表示用として渡していたものでした。ヘッダーには出しておらず、データにだけ残っていました。画面に出さないものは、画面のデータにも入れない。外して、テストを通しました。
ヘッダーの右上を、入れ替える

右上は、ログアウトのボタンから、アカウントの画面へのリンクになった(「管理」は管理者にだけ出る)
ヘッダーの右上には、ログアウトのボタンがありました。これを、アカウントの画面へのリンクに置き換えています。ログアウトは、アカウントの画面の中に移しました。
ログアウトが1回遠くなりますが、セッションは30日あります。押す場面は、多くありません。スマホの狭いヘッダーに、ボタンを増やさずに済みました。
データのエクスポート
開発を始めたときから、「利用者のデータは、いつでも持ち出せるようにする」と決めていました。サービスをやめるときの約束にするためです。退会の前に、手元に残せるようにもしたい。そこで、退会より先に作りました。
「データを書き出す」を押すと、ZIP ファイルが1つダウンロードされます。
| ファイル | 中身 |
|---|---|
data.json |
自分のデータの全部。機械で読める、欠けのない形 |
gears.csv など5つ |
ギア・消耗品・コンテナ・プラン・キャンプの一覧。人が読む用 |
images/ |
ギアとキャンプの画像 |
JSON だけでは、「持ち出せる」と言いにくい
最初は、JSON だけを考えていました。ただ、JSON は、ふつうの人には読めません。「持ち出せます」と言って渡すなら、Excel で開ける形も要ります。
CSV は、人が読むことだけを考えて作りました。
- 見出しは日本語。「所有」「毎回用意する」など、状態や種類は、画面と同じ言葉にする
- コンテナやプランは、id ではなく名前で出す
- Excel で文字化けしないよう、先頭に BOM を付ける
- プランの中身や、キャンプのチェックの状態は入れない(表が増えて、かえって分かりにくい。
data.jsonには入っている)
ZIP は、ブラウザの中で作る
画像も入れるので、ZIP は数十 MB になることがあります。Cloudflare Workers は、使えるメモリが 128MB までです。サーバーで画像を全部集めて ZIP にすると、収まらないかもしれません。
そこで、ZIP は、ブラウザの中で作ることにしました。
- サーバーは、自分のデータを JSON で返すだけ
- 画像は、今ある画像の配信から、ブラウザが1枚ずつ取る
- ブラウザの中で、ZIP にまとめて、ダウンロードする
サーバーの側は、新しい処理が1つ増えただけです。画像を取っている間は、「画像を集めています 12 / 56」と、進み具合を出します。途中で読めない画像があっても、止めません。終わったあとに、読めなかった数を出します。
ZIP を作るために、fflate というパッケージを1つ足しました。依存を増やさない方針ですが、ZIP を自分で組み立てるコードを書いて保守するより、安全だと考えました。理由は PR に書いています。
入れないものを、決めておく
書き出したファイルは、人に渡すこともあります。入れないものを、先に決めました。
user_id、メールアドレス、Google の名前- セッション、Google のトークン
- R2 のキー(画像の置き場所の名前)
画像のファイル名も、R2 のキーをそのまま使わず、ギアやキャンプの id から付け直しています。E2E では、書き出した ZIP を開いて、これらの文字がどこにも入っていないことを確かめました。
テーブルを足したときの、入れ忘れ
エクスポートで怖いのは、あとでテーブルを足したときに、書き出しに入れ忘れることです。気づかないまま、「全部のデータ」ではなくなります。
そこで、「利用者のデータのテーブルの一覧」を、1つのファイルに持つことにしました。そして、入れ忘れを2つの方法で見つけます。
- テスト:DB の定義にあるテーブルが、すべて「利用者のデータ」か「そうでないもの」の一覧に入っているかを確かめる。新しいテーブルを足して、どちらにも入れないと、落ちる
- 型:一覧にあるテーブルが、書き出すデータの型に入っていないと、型チェックでエラーになる
人が覚えておく決まりにせず、忘れたら落ちるようにしておけば、何年かあとの自分も困りません。
退会

退会の確認の画面。消えるものの件数を出し、「退会する」と入力するまで、ボタンは押せない
すぐに消す。取り消しの期間は作らない
退会してから、しばらくデータを残しておき、取り消せるようにする作りもあります。ただ、そうすると、「消える予定」という状態と、定期的に消す仕組みが要ります。1人で保守するものが増えます。
ハコヅミでは、すぐに全部消すことにしました。そのぶん、間違えて消さないための手当てを厚くしています。
- 消えるものの件数を、先に見せる
- 「先にデータを書き出せます」と、エクスポートへのリンクを置く
- 「退会する」と入力するまで、ボタンを押せない(サーバーでも確かめる)
消す順番は、R2 が先
消すものは、R2 の画像と、D1 の行です。この2つを、まとめて「全部成功するか、全部失敗するか」にはできません。
順番は、R2 を先、D1 をあとにしました。R2 の途中で失敗したら、D1 は消しません。D1 が残っていれば、ログインして、もう一度退会を押せます。
逆の順番だと、困ります。D1 を先に消して、R2 で失敗すると、ログインできないのに画像だけが残ります。誰の画像かをたどる手がかりも、消えています。
D1 のほうは、1回のバッチ(まとめて成功するか、まとめて失敗する)で消します。対象は、エクスポートで作った「利用者のデータのテーブルの一覧」の全部と、ログインの情報です。ここでも、一覧にテーブルを足して、消す処理に足し忘れると、型チェックでエラーになるようにしました。
退会できない人
2通りの人は、退会できないようにしています。
- 管理者:自分を消すと、管理者がいなくなる。やめるときは、先に権限を外す
- 凍結された人:前回決めたとおり、どの画面にも届かない。消してほしいときは、連絡をもらって、人が対応する
退会した人の記録は、残しません。同じ Google アカウントでもう一度ログインすると、データのない、新しいユーザーとして始まります。迷惑な使い方をした人が、退会して登録し直すことは、防げません。防ぐには、退会した人の記録を残すことになり、「データを残さない」約束とぶつかるためです。
受入確認は、もう1つのアカウントで
退会を、自分のアカウントで試すわけにはいきません。ここでも、もう1つの Google アカウントを使いました。データと画像を少し入れてから退会し、同じアカウントでログインし直して、空で始まることを確かめています。
本番では、退会は試していません。管理者の自分が退会の画面を開くと、「管理者は退会できません」と出ることだけを見ました。
本番に出す
ここまでの5つ(管理者、上限、アカウントの画面、エクスポート、退会)を、まとめて本番に出しました。
マイグレーションは3つで、どれも列やテーブルを足すだけです。今のデータは変わりません。リリースの直後は、自分も「一般・フリー」の扱いになります。本番の D1 のコンソールで、自分を管理者にする SQL を流すと、一覧の上限の表示が消えて、ヘッダーに「管理」が出ます。
公開までに残っているのは、次の4つです。
- 公開の前の、セキュリティの見直し
- ログインしていない人向けのトップページと、データが空のときの案内
- 利用規約・プライバシーポリシー・お問い合わせ
- Cloudflare Access を外す(ここで、一般に公開)
おわりに
- 表示名は、ログインに使う名前と分ける。未設定のときに、本名を代わりに出さない
- 画面に出さないものは、画面のデータにも入れない。テストで、データの中まで見る
- 「持ち出せる」と言うなら、人が読める形(CSV)も用意する
- 重い処理は、サーバーでやらずに、ブラウザに任せる手もある
- 「テーブルを足したら、ここにも足す」は、決まりではなく、テストと型で守る
- 消す順番は、「途中で失敗しても、やり直せるか」で決める