← rooo.pro

同じ日に第6号 — 写真同意システムを一段深くした半日

2026-05-09 / 第6号 / 公開時点では下書き

第5号「『ちゃんと聞ける』仕組みを Claude と作った話」を朝に公開したばかり。
その記事を書いていた瞬間に「これ、まだ穴がある」と気づいた箇所がいくつかあって、その日の午後から夕方にかけて全部潰した。同じ日に 2 本目を書くのは初めての経験。


第5号の最後に書いた「未対応項目」をやり切る

第5号の終盤にこう書いていた:

・撤回テスト(全件・部分)
・メンバー登録 → 一斉送信
・共同管理者の確保
・弁護士チェック

このうち、コード側でやれるものは第6号の作業中にやり切った。残ったのは「人間に頼む」部分(共同管理者・弁護士)だけ。これは長期課題として記録に残し、Claude にも忘れないようメモリファイルに書いてもらった。

撤回テスト → コードを読んだ Claude がバグを先に指摘した

T1〜T5 の 5 シナリオで撤回フローを実機テストする計画を Claude と一緒に組んだ。テストに入る前、Claude にコードレビューさせたところ、こう言ってきた:

部分撤回後の再アクセス時に、撤回したはずの写真のラジオボタンが pre-select されたままになる 可能性があります。getExistingConsents_ が withdrawn 行を読み飛ばすだけで、photo 単位の最新を判定していないためです。意図せず「再同意」してしまう動線になります。

機微情報を扱う団体システムでこれは看過できない。私には選択肢が 2 つあった:

A 案:実機で再現してから直す
B 案:先に直してから実機テストする

「バグの動作を本番ライクな環境で実演する前に潰したい」と思って B 案を選んだ。Claude が getExistingConsents_ を「最新ステータス per photo」ベースに書き直し、それを Apps Script 側に反映してから T1〜T5 を実行 → 全部期待どおり

ここで一番印象に残ったのは、Claude は実機で挙動を見る前にバグを見つけたということ。コードを読んで、データの流れを追って、矛盾を指摘した。AI がやれる「コードの中の論理の不整合」検出は、私のような大枠だけ読める人間には深さが違う。

撤回フローを設計し直した — 集合写真と単独写真を分ける

第5号の段階では「撤回 = 完全削除」だった。だけど集合写真の場合、1 人が「やめてほしい」と言ったから写真全体を削除するのは、他の写っている人への配慮が足りない。第6号で仕様を変えた:

集合写真:完全削除はせず、全身加工版(顔だけでなく体型もシルエット化)に切り替え
単独写真完全削除 もしくは 全身加工で継続 を本人が選べる

Photos シートの default_people 列の人数で、システムが自動的に集合/単独を判定する(2 人以上 = 集合、1 人 = 単独)。

データ構造的には、撤回 =「level=E(全身加工なら OK)への同意切り替え」と捉え直した。これで data model 上、「撤回」と「同意の変更」が地続きになる。哲学的にも合う:撤回はコミュニケーションの拒否ではなく、同意の更新 の一形態だから。

選択肢に E を追加 — 全身加工なら OK

同意ページの選択肢は元々 A/B/C/D/― の 5 段階。ここに E:全身加工なら SNS/サイト両方 OK を追加して 6 段階に。

これは「掲載されたいわけじゃないけど、ぼかし切ったうえで参加の記録にしてもらうのなら OK」という人のための選択肢。

D(公開しないで)と E(全身加工なら OK)の関係性は、集合写真のときに少しだけややこしくなる。集合写真で D を選ばれた場合、運営側が D の意図を尊重しつつ「他の写り込んでいる方の OK との両立」のために 結果として全身加工版で出すことがある — という運用ルールにした。同意ページ上でもこの旨を明示している。

メンバー登録フォームを作った

第5号では People シートに本人を 運営が手動で登録する 運用だった。第6号で、本人が直接フォームから登録できる仕組みを足した(URL は運営から個別にご案内)。

入力項目:

・メールアドレス(必須)
・ニックネーム(必須)
・立場・役割(任意:当事者/ピアサポーター/精神保健福祉士/介護福祉士/家族・友人/地域住民/その他)
・障害者手帳の有無(任意:持っている/持っていない/申請中/答えたくない)
・自由記入(任意)

立場・手帳の有無は要配慮個人情報なので、すべて任意、かつ「書かなくて OK」を全選択肢の冒頭に置いた。書きたい人だけ書く形。

person_id は自動採番。形式は karaha-R{令和年}-{連番3桁}

・2026 年(令和8年)→ karaha-R8-001karaha-R8-002、…
・2027 年(令和9年)→ karaha-R9-001 から始まる(年内リセット)

令和を採用したのは、和暦のほうが「いつ登録したか」が ID から直感的に分かるという 日本的な設計判断。普段はあまり和暦を使わない私だが、この団体・このコンテキストでは合うと思った。

ニックネームを本人が変更できる

これも第5号では「運営に依頼」が必要だった。第6号では同意ページの上部に「ニックネーム変更」パネルを置いて、本人が直接変更できるように。

どうしてもニックネームというのは、最初に決めた名前としばらく使ってから「やっぱりこっちがいい」になりやすい。それを「運営に頼んでください」にしておくのは摩擦が大きすぎる。1 クリックで編集モードに入れる UI が正しい。

4 つの法務寄り改善(弁護士チェック前にやれること)

弁護士チェックは将来やる前提で、それまでにエンジニア判断でやれることをやった:

1. 同意ページから photo-policy / privacy への直接リンク:footer に追加。本人が背景情報をたどれるように。
2. policy_version の記録:同意送信時に [policy:v2026-05-09] を Consents.comment + Audit log に刻印。あとで「いつ・どのバージョンの方針に同意してくれたか」が再構成できる。
3. 年次再確認トリガー:1 年経過した同意について自動でメール送信。月 1 回(毎月 15 日 9 時)に Apps Script のトリガーが回る設定。
4. 個人情報漏えい時の通知ポリシー:privacy policy に追加。個人情報保護法 26 条への準拠と、本人通知を最優先にする旨を明記。

これらはどれも、弁護士に見せる前の 整地。法人化のタイミングで弁護士に依頼する際、こういう「明らかに整えられる小さな穴」が潰れていれば、レビューの本質的な部分(リスク評価・契約・体制)に集中してもらえる。

Claude が私のブラウザを操作した日

第5号までは「Claude が提案 → 私が実装」の構造だった。第6号で初めて、Claude が私の Chrome を直接操作して、Apps Script のコードを書き換え、デプロイし、テスト関数を実行した

具体的には:

・Apps Script Editor を開く
・Monaco エディタの内容を JS API(monaco.editor.getModels()[0].setValue(...))で書き換える
Ctrl+S で保存
・「デプロイ → 新バージョン作成 → デプロイ」をクリックする
・実行する関数を選び ▶️ ボタンを押す
・実行ログを読み取って結果を私に報告する

私は基本「画面を見ているだけ」になる時間帯があった。これは少し奇妙な体験だった。目の前で誰かが、私のアカウントで、私のシステムを更新している 状態。それも、本人確認・承認は私のクリックでしかできない(OAuth はそこで止まった)。

ひとつ印象に残った瞬間:年次再確認トリガーを配線するときに OAuth 承認が必要 という Google の画面が出て、Claude がそこで止まったこと。Claude は明確に「アカウント認証は私が踏み込まない領域」と言って、私に承認を求めた。

OAuth 承認が必要な状態で止まりました。新しく作る関数はトリガー作成の権限が必要で、初回は Google の承認が要ります。私はここで止めて、ユーザーに承認していただく必要があります(アカウント認証は私が踏み込まない領域)。

これは「AI が何でもできる」ではなく、AI が踏み込んではいけない境界を AI 自身が明示する モデル。本人確認・認証・権限の付与は、エンドユーザーの責任として残す。これが正しい設計だと思う。「全自動」を売りにする AI 製品が増える中、この境界の引き方は karaha.org のような繊細な領域でこそ重要。

何を書かないか(同じ)

第5号と同じ判断軸:機微情報を扱う団体運営の文脈なので、書く側で線を引く。

・テストに使ったメールアドレス・トークン(自分のもの)
・個別メンバーの登録情報
・Sheet の中身、内部 ID
・法務リスク評価そのものの中身(弁護士の領域)

書けるのは 「設計の選択をどう判断したか」「コードの構造がどう変わったか」「Claude との分担」 までで、運営内部の詳細は別の場所に記録する。

残った 1 つ — Cloudinary の自動削除

5-4-5(撤回時の Cloudinary 画像削除の自動化)は今日は手をつけなかった。これは Cloudinary の API key を Apps Script の Script Properties に入れる必要があり、運営者の判断が要る。当面は撤回受付メールに記載される手動手順で運用 OK。

同じ日に 2 回書くという密度

第7号はおそらく 「メンバー名簿への実際の登録 → 一斉送信」の運用回 になる。動いている人間の同意を実際に取り始める段階なので、build-in-public 的にはここが本番。

そしてここまでの全工程は、半日 +α で終わった。第5号が朝のリリース、第6号が夕方の改善ログ。同じ日に 2 回書くのは初めて。AI と一緒に走ると、こういう密度で書ける日が来る。

正直に言うと、書きながら少し怖いところもある。動きが速すぎないか、機微情報の扱いが粗くないか、見落とした穴が残っていないか。だから build-in-public で公開する。外から見られる方が、最終的には堅牢になる はずだから。