heading1
heading1
heading2
heading3
heading4
heading5
heading6
normal text
決めたスタックはNext.js + Vercel、CMSはPayload CMS、DBはNeon。せっかくなら管理画面もフルスクラッチではなく「WordPress的なもの」を自分のリポジトリに同居させたくて、Payloadを選んだ。
作り始めてすぐ、想定外のところでハマった。
## ハマりポイント1: 本番でテーブルができない
```
aaaa
```
ローカルでは動くのに、本番にデプロイすると relation "users" does not exist というエラーが出る。Payloadは管理画面やAPIを自動生成してくれる代わりに、裏側でdrizzle-kitを使ってDBスキーマを管理しているのだが、本番ビルドからdrizzle-kitを意図的に除外するという設計になっていた。
push: true にしてみたり、drizzle-kitを直接呼ぶAPIエンドポイントを自作してみたり、いくつかワークアラウンドを試したが、どれもこの設計思想と衝突して失敗した。最終的には公式のマイグレーション方式に素直に乗ることで解決した。payload migrate:create でマイグレーションファイルを生成してリポジトリにコミットし、ビルドスクリプトを payload migrate && next build に変更する。これでVercelのビルド時に自動でマイグレーションが適用されるようになった。
遠回りをしたが、「フレームワークの設計と喧嘩しない」という当たり前の教訓を改めて得た回だった。
ハマりポイント2: 下書きが公開サイトに漏れる
管理画面から記事を書けるようになり、公開サイト側にトップページの記事一覧と詳細ページを実装した。デプロイして動作確認していたところ、下書き(draft)状態の投稿が公開サイトに表示されてしまうことに気づいた。
原因は、公開ページからPayloadのLocal APIを呼ぶ際に overrideAccess を指定していなかったこと。これはデフォルトで true になっており、アクセス制御ルールを素通りしてしまう。つまり「下書きは公開しない」というルールごとバイパスしていた。overrideAccess: false を明示することで、シークレットモードでも下書きが見えないことを確認できた。
セキュリティやアクセス制御まわりは、フレームワークの「賢い」デフォルト挙動を疑ってかからないと、こういう見落としが起きるんだなと実感した。
## 今のところの状態
管理画面から書いた下書きを、チャットでの要約からコピペなしでそのままAPI経由でPOSTする——という投稿フローまで実際に動くようになった。この記事も、そのフローの最初の1本として投稿している。
小さいサイトだけど、作りながら学んだことの方が多い。