diff --git a/README.md b/README.md index bd3d808..a4c9d27 100644 --- a/README.md +++ b/README.md @@ -218,8 +218,7 @@ Cloudflare 側で以下を設定してください。 Cloudflare Pages の Functions binding は `wrangler.jsonc` で管理します。 -- production: `COMMENTS_DB` -> `acecore-comments-production` -- preview/local: `COMMENTS_DB` -> `acecore-comments-preview` +- `COMMENTS_DB` -> `acecore-comments` Cloudflare Pages secret は以下を設定します。 @@ -231,8 +230,7 @@ Cloudflare Pages secret は以下を設定します。 D1 schema は `migrations/0001_create_blog_comments.sql` です。初回は D1 database を作成後、以下で適用します。 ```bash -npx wrangler d1 execute acecore-comments-production --remote --file=./migrations/0001_create_blog_comments.sql -npx wrangler d1 execute acecore-comments-preview --remote --file=./migrations/0001_create_blog_comments.sql +npx wrangler d1 execute acecore-comments --remote --file=./migrations/0001_create_blog_comments.sql ``` スパムなどを非表示にする場合は、対象レコードの `deleted_at` に ISO 8601 の日時を入れます。`deleted_at IS NULL` のコメントのみ表示されます。 diff --git a/src/content/blog/astro-cloudflare-site-architecture.md b/src/content/blog/astro-cloudflare-site-architecture.md index b271186..6c195d4 100644 --- a/src/content/blog/astro-cloudflare-site-architecture.md +++ b/src/content/blog/astro-cloudflare-site-architecture.md @@ -67,7 +67,7 @@ checklist: checked: true - text: 'フォーム導線はURLパラメータで文脈を渡し、受信値は安定した分類にする' checked: true - - text: 'コメントなど投稿データはpreviewとproductionでDBを分ける' + - text: 'コメントなど投稿データはD1の実体名とbindingを設定で明示する' checked: true - text: 'AI出力やユーザー投稿は、HTMLとして信頼せず許可リストで扱う' checked: true @@ -276,7 +276,7 @@ AI機能をサイトに入れるときは、モデルの精度だけでなく、 - Turnstileをserver-side validationする - Originとhostname allowlistを見る - URL、メール、HTML、Markdownリンク、宣伝語句を拒否する -- previewとproductionでD1を分ける +- D1の実体名とbindingをWranglerで明示する 詳しくは [CloudflareだけでAstroブログにコメント機能を作る方法](/blog/cloudflare-only-blog-comments/) にまとめています。 diff --git a/src/content/blog/cloudflare-only-blog-comments.md b/src/content/blog/cloudflare-only-blog-comments.md index 09c2053..1f5a205 100644 --- a/src/content/blog/cloudflare-only-blog-comments.md +++ b/src/content/blog/cloudflare-only-blog-comments.md @@ -1,6 +1,6 @@ --- title: 'CloudflareだけでAstroブログにコメント機能を作る方法' -description: '外部コメントサービスに頼らず、Cloudflare Pages Functions、D1、Turnstile、Wrangler設定だけでAstroブログにコメント機能を追加した実装記録です。API設計、保存先、スパム対策、origin制御、preview/production分離、運用時の注意点まで整理します。' +description: '外部コメントサービスに頼らず、Cloudflare Pages Functions、D1、Turnstile、Wrangler設定だけでAstroブログにコメント機能を追加した実装記録です。API設計、保存先、スパム対策、origin制御、Wranglerでのbinding管理、運用時の注意点まで整理します。' date: 2026-06-07T18:00 lastUpdated: 2026-06-07T00:00 author: gui @@ -46,7 +46,7 @@ compareTable: items: - 'Pages Functions、D1、TurnstileだけでAPIと保存先を持てる' - 'Astro側のHTML/CSSとしてサイトデザインへ自然に合わせられる' - - 'Wrangler設定でpreviewとproductionのD1を分けられる' + - 'Wrangler設定でD1 bindingとCloudflare側のDB名を揃えられる' - 'スパム対策、削除、保存する個人情報の範囲を自分たちで決められる' checklist: title: 実装前に決めること @@ -59,7 +59,7 @@ checklist: checked: true - text: 'URL、メール、HTML、Markdownリンク、宣伝語句を投稿前に拒否する' checked: true - - text: 'preview/localとproductionのD1 bindingを分ける' + - text: 'D1 database名とCOMMENTS_DB bindingをCloudflare側と揃える' checked: true linkCards: - href: /blog/cloudflare-pages-security/ @@ -200,7 +200,7 @@ D1 bindingと環境変数は `wrangler.jsonc` に寄せました。 "d1_databases": [ { "binding": "COMMENTS_DB", - "database_name": "acecore-comments-preview", + "database_name": "acecore-comments", "database_id": "...", "migrations_dir": "./migrations", }, @@ -210,7 +210,7 @@ D1 bindingと環境変数は `wrangler.jsonc` に寄せました。 "d1_databases": [ { "binding": "COMMENTS_DB", - "database_name": "acecore-comments-preview", + "database_name": "acecore-comments", }, ], }, @@ -218,7 +218,7 @@ D1 bindingと環境変数は `wrangler.jsonc` に寄せました。 "d1_databases": [ { "binding": "COMMENTS_DB", - "database_name": "acecore-comments-production", + "database_name": "acecore-comments", }, ], }, @@ -228,9 +228,9 @@ D1 bindingと環境変数は `wrangler.jsonc` に寄せました。 Cloudflare PagesのWrangler設定は、Pages project configurationのsource of truthとして扱われます。つまり、bindingや環境変数をダッシュボードの手作業だけに散らさず、リポジトリ側でレビューできる形にできます。 -ここで大事なのは、**preview/localとproductionのD1を分けること** です。 +ここで大事なのは、**binding名を固定し、D1の実体名をCloudflare側とリポジトリ側で揃えること** です。 -コメント機能は投稿データを持つので、preview環境で本番D1へ書き込むと事故になります。今回も `acecore-comments-preview` と `acecore-comments-production` を分け、同じ `COMMENTS_DB` binding名で環境ごとに向き先を変えています。 +今回はコメント用D1を1つに寄せているため、環境ごとの `COMMENTS_DB` はすべて `acecore-comments` を指します。 ## Turnstileはサーバー側で検証する @@ -455,7 +455,7 @@ Cloudflare内に閉じると、その代わりに自分たちで作る責任は 他のAstroサイトに入れるなら、流れはこうです。 -1. Cloudflare D1 databaseをpreview用とproduction用に作る +1. Cloudflare D1 databaseを作る 2. `wrangler.jsonc` に `COMMENTS_DB` bindingを追加する 3. `TURNSTILE_SECRET_KEY` と `COMMENT_HASH_SALT` をPages secretに設定する 4. `COMMENT_ALLOWED_HOSTNAMES` に本番hostとPages preview hostを入れる @@ -464,7 +464,7 @@ Cloudflare内に閉じると、その代わりに自分たちで作る責任は 7. `functions/api/comments.ts` でGET/POST/OPTIONSを実装する 8. `BlogComments.astro` で一覧、フォーム、Turnstile widgetを実装する 9. `BlogPostPage.astro` の本文下へコメントコンポーネントを置く -10. productionとpreviewで別D1に書き込まれることを確認する +10. 投稿が想定したD1 databaseに書き込まれることを確認する Cloudflare D1のWrangler commandでは、SQLファイルを実行する `d1 execute` や、versioned migration fileを作る `d1 migrations create` / `d1 migrations apply` が用意されています。プロジェクトの運用に合わせて、単発のschema適用にするか、migrations applyに寄せるかを決めます。 @@ -479,7 +479,7 @@ Cloudflare D1のWrangler commandでは、SQLファイルを実行する `d1 exec - Turnstile未完了ではPOSTできない - URLやメールアドレス入りの本文が拒否される - 同じ本文の連投が拒否される -- production previewで本番D1へ書き込まない +- `COMMENTS_DB` が想定したD1 databaseへ書き込む - `COMMENT_ALLOWED_HOSTNAMES` にないoriginから拒否される - `deleted_at` を入れたコメントが表示されない @@ -519,10 +519,10 @@ Astroの通常dev serverだけでは、Cloudflare Pages FunctionsやD1 binding ただ、すでにCloudflare Pagesで配信しているサイトなら、Cloudflareだけで作る選択肢もかなり現実的です。 -Pages FunctionsでAPI境界を作り、D1に保存し、Turnstileでbot対策をし、Wranglerで環境ごとのbindingを管理する。これで、静的サイトの強みを残したまま、必要な部分だけ動的にできます。 +Pages FunctionsでAPI境界を作り、D1に保存し、Turnstileでbot対策をし、Wranglerでbindingを管理する。これで、静的サイトの強みを残したまま、必要な部分だけ動的にできます。 外部サービスに頼らない分、入力検証、rate limit、hostname allowlist、削除運用は自分たちで設計する必要があります。 -その代わり、コメント欄のUI、データ、セキュリティ境界、preview/production分離をサイトの方針に合わせられます。 +その代わり、コメント欄のUI、データ、セキュリティ境界、インフラ設定をサイトの方針に合わせられます。 公式サイトのブログに小さくコメント機能を足したいなら、Cloudflareだけで作る構成は十分に候補になります。 diff --git a/src/content/blog/de/cloudflare-only-blog-comments.md b/src/content/blog/de/cloudflare-only-blog-comments.md index fb17c61..d07c5c0 100644 --- a/src/content/blog/de/cloudflare-only-blog-comments.md +++ b/src/content/blog/de/cloudflare-only-blog-comments.md @@ -42,7 +42,7 @@ Acecore hat keinen externen Kommentardienst eingebettet. In [PR #101](https://gi - Cloudflare Pages Functions stellt `/api/comments` bereit. - Cloudflare D1 speichert Kommentare. - Cloudflare Turnstile schützt POST-Anfragen. -- `wrangler.jsonc` trennt preview und production. +- `wrangler.jsonc` definiert das `COMMENTS_DB`-Binding. Der Vorteil: Der Kommentarbereich bleibt Teil der bestehenden Cloudflare-Architektur. @@ -71,9 +71,9 @@ Prepared Statements mit `bind()` verhindern, dass Benutzereingaben direkt in SQL ## Wrangler als Vertrag -`COMMENTS_DB` wird in `wrangler.jsonc` definiert. Preview nutzt `acecore-comments-preview`, production nutzt `acecore-comments-production`. +`COMMENTS_DB` wird in `wrangler.jsonc` definiert und zeigt auf die einzige D1-Datenbank `acecore-comments`. -So schreibt eine PR-Preview nicht in die Produktionsdatenbank. +So bleibt der Binding-Name stabil, während Dashboard und Repository denselben Datenbanknamen verwenden. ## Turnstile serverseitig prüfen diff --git a/src/content/blog/en/cloudflare-only-blog-comments.md b/src/content/blog/en/cloudflare-only-blog-comments.md index 27fe7cb..5b6dfb7 100644 --- a/src/content/blog/en/cloudflare-only-blog-comments.md +++ b/src/content/blog/en/cloudflare-only-blog-comments.md @@ -42,7 +42,7 @@ For Acecore, we did not add an external comment SaaS or embedded widget. The imp - Cloudflare Pages Functions expose `/api/comments`. - Cloudflare D1 stores comments. - Cloudflare Turnstile protects POST requests. -- `wrangler.jsonc` defines production and preview bindings. +- `wrangler.jsonc` defines the `COMMENTS_DB` binding. That is the main point: **the comment feature is not a third-party island inside the page**. It uses the same Cloudflare boundary as the rest of the static site. @@ -86,7 +86,7 @@ Bindings are defined in `wrangler.jsonc`. "d1_databases": [ { "binding": "COMMENTS_DB", - "database_name": "acecore-comments-preview", + "database_name": "acecore-comments", }, ], "env": { @@ -94,7 +94,7 @@ Bindings are defined in `wrangler.jsonc`. "d1_databases": [ { "binding": "COMMENTS_DB", - "database_name": "acecore-comments-production", + "database_name": "acecore-comments", }, ], }, @@ -102,7 +102,7 @@ Bindings are defined in `wrangler.jsonc`. } ``` -The important part is separating preview and production. A PR preview should never write to the production comments database. +The important part is keeping the binding name stable while pointing every environment at the single D1 database, `acecore-comments`. Cloudflare Pages documentation treats Wrangler configuration as the source of truth for a Pages project, which is exactly what we want for reviewable infrastructure changes. @@ -140,7 +140,7 @@ External comment services are convenient, but they are not the only option. If a site already runs on Cloudflare Pages, a lightweight comment feature can live entirely inside Cloudflare: Pages Functions for the API, D1 for storage, Turnstile for abuse prevention, and Wrangler for bindings. -That keeps UI, data, security boundaries, and preview/production separation under the same operational model as the site itself. +That keeps UI, data, security boundaries, and infrastructure configuration under the same operational model as the site itself. ## References diff --git a/src/content/blog/es/cloudflare-only-blog-comments.md b/src/content/blog/es/cloudflare-only-blog-comments.md index b80c465..e8b7d6a 100644 --- a/src/content/blog/es/cloudflare-only-blog-comments.md +++ b/src/content/blog/es/cloudflare-only-blog-comments.md @@ -42,7 +42,7 @@ En Acecore no usamos un servicio externo de comentarios. En [PR #101](https://gi - Cloudflare Pages Functions expone `/api/comments`. - Cloudflare D1 guarda los comentarios. - Cloudflare Turnstile protege el POST. -- `wrangler.jsonc` separa preview y production. +- `wrangler.jsonc` define el binding `COMMENTS_DB`. La ventaja es que el comentario no queda como una isla de terceros dentro de la página. @@ -75,9 +75,9 @@ Por eso D1 es más cómodo que un almacén key-value. Además, las consultas usa ## Configuración por Wrangler -El binding `COMMENTS_DB` se define en `wrangler.jsonc`. Preview apunta a `acecore-comments-preview`; production apunta a `acecore-comments-production`. +El binding `COMMENTS_DB` se define en `wrangler.jsonc` y apunta a la única base D1 `acecore-comments`. -Esta separación evita que una preview de Pull Request escriba en la base real. +Así el nombre del binding se mantiene estable y el dashboard de Cloudflare coincide con el repositorio. ## Turnstile en servidor diff --git a/src/content/blog/fr/cloudflare-only-blog-comments.md b/src/content/blog/fr/cloudflare-only-blog-comments.md index 4c3f013..ef718d9 100644 --- a/src/content/blog/fr/cloudflare-only-blog-comments.md +++ b/src/content/blog/fr/cloudflare-only-blog-comments.md @@ -42,7 +42,7 @@ Pour Acecore, nous n'avons pas utilisé de service externe de commentaires. Dans - Cloudflare Pages Functions expose `/api/comments`. - Cloudflare D1 stocke les commentaires. - Cloudflare Turnstile protège les envois. -- `wrangler.jsonc` sépare preview et production. +- `wrangler.jsonc` définit le binding `COMMENTS_DB`. Le point fort est clair : la zone de commentaires n'est pas un îlot tiers dans la page. @@ -71,9 +71,9 @@ Les requêtes passent par des prepared statements et `bind()`, sans concaténer ## Wrangler comme contrat -Le binding `COMMENTS_DB` est défini dans `wrangler.jsonc`. Preview pointe vers `acecore-comments-preview`; production vers `acecore-comments-production`. +Le binding `COMMENTS_DB` est défini dans `wrangler.jsonc` et pointe vers l'unique base D1 `acecore-comments`. -C'est important : une preview de Pull Request ne doit pas écrire dans la base de production. +Cela garde le nom du binding stable tout en alignant le tableau de bord Cloudflare et le dépôt sur le même nom de base. La documentation Cloudflare Pages indique aussi que la configuration Wrangler devient la source de vérité du projet Pages. diff --git a/src/content/blog/ko/cloudflare-only-blog-comments.md b/src/content/blog/ko/cloudflare-only-blog-comments.md index 4a10aa9..015b0f3 100644 --- a/src/content/blog/ko/cloudflare-only-blog-comments.md +++ b/src/content/blog/ko/cloudflare-only-blog-comments.md @@ -42,7 +42,7 @@ Acecore는 외부 댓글 SaaS나 widget을 쓰지 않았습니다. [PR #101](htt - Cloudflare Pages Functions가 `/api/comments`를 제공합니다. - Cloudflare D1이 댓글을 저장합니다. - Cloudflare Turnstile이 POST를 보호합니다. -- `wrangler.jsonc`가 preview와 production을 나눕니다. +- `wrangler.jsonc`가 `COMMENTS_DB` binding을 정의합니다. 핵심은 댓글 영역이 페이지 안의 외부 서비스가 아니라, 기존 Cloudflare 구성의 일부라는 점입니다. @@ -71,9 +71,9 @@ Function은 origin, payload, Turnstile, rate limit, 중복, 금지 내용을 검 ## Wrangler로 환경을 나누기 -`COMMENTS_DB`는 `wrangler.jsonc`에 정의합니다. preview는 `acecore-comments-preview`, production은 `acecore-comments-production`을 사용합니다. +`COMMENTS_DB`는 `wrangler.jsonc`에 정의하며, 단일 D1 database인 `acecore-comments`를 가리킵니다. -PR preview가 production DB에 쓰지 않도록 하는 것이 중요합니다. +binding 이름은 유지하고 Cloudflare dashboard와 repository의 database 이름을 맞춥니다. ## Turnstile은 서버에서 검증 diff --git a/src/content/blog/pt/cloudflare-only-blog-comments.md b/src/content/blog/pt/cloudflare-only-blog-comments.md index 9d008d9..d97afdc 100644 --- a/src/content/blog/pt/cloudflare-only-blog-comments.md +++ b/src/content/blog/pt/cloudflare-only-blog-comments.md @@ -42,7 +42,7 @@ No Acecore, escolhemos outro caminho: em [PR #101](https://github.com/acecore-sy - Cloudflare Pages Functions expõe `/api/comments`. - Cloudflare D1 armazena comentários. - Cloudflare Turnstile protege o envio. -- `wrangler.jsonc` separa preview e production. +- `wrangler.jsonc` define o binding `COMMENTS_DB`. O ponto principal é que a área de comentários não vira uma dependência externa dentro da página. @@ -71,9 +71,9 @@ As queries usam prepared statements com `bind()`, evitando concatenar input de u ## Wrangler e ambientes -`COMMENTS_DB` fica em `wrangler.jsonc`. Preview aponta para `acecore-comments-preview`; production aponta para `acecore-comments-production`. +`COMMENTS_DB` fica em `wrangler.jsonc` e aponta para o único banco D1 `acecore-comments`. -Isso evita que uma preview de PR grave dados reais de produção. +Assim o nome do binding continua estável, enquanto o dashboard da Cloudflare e o repositório usam o mesmo nome de banco. ## Turnstile no servidor diff --git a/src/content/blog/ru/cloudflare-only-blog-comments.md b/src/content/blog/ru/cloudflare-only-blog-comments.md index a18bc7d..ea3b921 100644 --- a/src/content/blog/ru/cloudflare-only-blog-comments.md +++ b/src/content/blog/ru/cloudflare-only-blog-comments.md @@ -42,7 +42,7 @@ Acecore не стал подключать внешний сервис комм - Cloudflare Pages Functions предоставляет `/api/comments`. - Cloudflare D1 хранит комментарии. - Cloudflare Turnstile защищает POST. -- `wrangler.jsonc` разделяет preview и production. +- `wrangler.jsonc` задает binding `COMMENTS_DB`. Главное преимущество: комментарии не становятся сторонним виджетом внутри страницы. @@ -71,9 +71,9 @@ Function проверяет origin, payload, Turnstile, лимиты, дубли ## Wrangler и окружения -`COMMENTS_DB` задается в `wrangler.jsonc`. Preview пишет в `acecore-comments-preview`, production — в `acecore-comments-production`. +`COMMENTS_DB` задается в `wrangler.jsonc` и указывает на единственную D1-базу `acecore-comments`. -Это защищает production от случайных записей из PR preview. +Так имя binding остается стабильным, а Cloudflare dashboard и репозиторий используют одно имя базы. ## Turnstile на сервере diff --git a/src/content/blog/zh-cn/cloudflare-only-blog-comments.md b/src/content/blog/zh-cn/cloudflare-only-blog-comments.md index 6cbce69..d1d77dc 100644 --- a/src/content/blog/zh-cn/cloudflare-only-blog-comments.md +++ b/src/content/blog/zh-cn/cloudflare-only-blog-comments.md @@ -42,7 +42,7 @@ Acecore 没有引入外部评论 SaaS 或嵌入式 widget,而是在 [PR #101]( - Cloudflare Pages Functions 提供 `/api/comments` - Cloudflare D1 保存评论 - Cloudflare Turnstile 保护投稿 -- `wrangler.jsonc` 区分 preview 和 production +- `wrangler.jsonc` 定义 `COMMENTS_DB` binding 重点是:评论栏不是页面里的第三方孤岛,而是站点现有 Cloudflare 架构的一部分。 @@ -75,7 +75,7 @@ Pages Function 在写入前验证 origin、payload、Turnstile、rate limit、 `wrangler.jsonc` 中定义 `COMMENTS_DB`。 -preview 使用 `acecore-comments-preview`,production 使用 `acecore-comments-production`。这样 PR preview 不会误写 production 数据库。 +`COMMENTS_DB` 指向唯一的 D1 数据库 `acecore-comments`,这样 Cloudflare dashboard 和仓库中的数据库名称保持一致。 Cloudflare Pages 文档也说明,使用 Wrangler 配置时,它会成为 Pages project configuration 的 source of truth。 @@ -115,7 +115,7 @@ Cloudflare Pages 文档也说明,使用 Wrangler 配置时,它会成为 Page 如果网站已经运行在 Cloudflare Pages 上,那么 Pages Functions、D1、Turnstile 和 Wrangler 就足以构成一个轻量评论系统。 -这样可以把 UI、数据、preview/production 分离和安全边界都放在同一个 Cloudflare 运维模型中。 +这样可以把 UI、数据、安全边界和基础设施配置都放在同一个 Cloudflare 运维模型中。 ## 参考 diff --git a/wrangler.jsonc b/wrangler.jsonc index 86e561b..a55519c 100644 --- a/wrangler.jsonc +++ b/wrangler.jsonc @@ -18,8 +18,8 @@ "d1_databases": [ { "binding": "COMMENTS_DB", - "database_name": "acecore-comments-production", - "database_id": "10bb4e84-2c31-427f-931c-fcb123c57501", + "database_name": "acecore-comments", + "database_id": "3f31c39c-e418-4460-8651-4385e0409157", "migrations_dir": "./migrations", }, ], @@ -40,8 +40,8 @@ "d1_databases": [ { "binding": "COMMENTS_DB", - "database_name": "acecore-comments-production", - "database_id": "10bb4e84-2c31-427f-931c-fcb123c57501", + "database_name": "acecore-comments", + "database_id": "3f31c39c-e418-4460-8651-4385e0409157", "migrations_dir": "./migrations", }, ], @@ -62,8 +62,8 @@ "d1_databases": [ { "binding": "COMMENTS_DB", - "database_name": "acecore-comments-production", - "database_id": "10bb4e84-2c31-427f-931c-fcb123c57501", + "database_name": "acecore-comments", + "database_id": "3f31c39c-e418-4460-8651-4385e0409157", "migrations_dir": "./migrations", }, ],