転職用のポートフォリオとして、個人でWebアプリ「Hubpin」を作っています。
制作の経緯は「Hubpin 開発記録」に時系列でまとめています。
設計と判断は自分で行い、実装も原則自分で書いています。AIには手順書・レビュー・調査を任せています。
制作中の自作アプリで、掲載用の証拠スクリーンショットを撮っていたときの判断です。
完璧に見える1枚が撮れた
「未ログインだと管理画面に入れない」ことを示す画像がほしくて、
シークレットウィンドウで /dashboard を直打ちしました。
撮れたのは、アドレスバーが /dashboard のまま、画面はログインフォームという1枚。
「打った URL」と「出た画面」が1枚に両方写っている。これ以上ない証拠に見えました。
採用しかけて、実装を読み直した
return NextResponse.redirect(url) // URL は必ず /login に変わる
redirect を返しているので、アドレスバーが /dashboard のままになることはありません。
あの1枚は、ブラウザが遷移し切る前の一瞬でした。
何が問題か
公開素材として出すと、こう読まれます。
URL を保ったまま画面だけ差し替えている(=
rewrite)
実装と違う説明を、自分で用意したことになります。
しかもタイミング次第なので再現性がありません。
採用したのは「対」の2枚
同じシークレットウィンドウで連続して撮りました。
| 写っているもの | |
|---|---|
| 1枚目 | 未ログインで /dashboard → /login に飛ばされている |
| 2枚目 | デモログイン後 → /dashboard が見えている |
1枚目だけでは「そもそも /dashboard が壊れているだけ」の可能性が消えません。
「入れない」と「入れる」が同じ条件で並んで、初めて保護が効いている証明になります。
同じ形を前にも見ていた
データベースの権限(RLS)を確認したときも同じでした。
- 他人のデータを更新しようとして 0行
- 本人なら 7行
0行だけでは「UPDATE 文が壊れているだけ」と区別がつきません。
あのときも、片方だけでは何も言えなかった。
落としどころ
証拠の強さは、写っている情報量ではなく「反証をいくつ潰せるか」で決まる、
というのが今回の学びです。
1枚に全部写っているほうが強く見えるのは、見た目の話でしかありませんでした。
そして「採用しかけた」のは自分で、実装を読み直さなければそのまま出していました。
