運用、seed、リリース
後日 provisioning するための順序、remote target、acknowledgement と復旧
この checklist は「何を確認するか」の正本です。実際に打つ command の完全版(copy-paste できる順序)は operator runbook を参照してください。
Site 全体は password wall の背後にあり、それ自体が public writes を有効化する前提条件です — AUTH_PASSWORD/AUTH_PASS_COOKIE の 2 つの secret が production Worker に届いていない限り、Worker は serve 自体を拒否します(詳細は step 9)。password wall は認証済み運用者 API(/ prefix — readiness と purge)には適用されません。この bearer-auth な exemption は password gate より厳格な認証であることに加え、readiness preflight と purge tooling がこの経路に到達できる必要があるため、そして gate 自体が misconfigured な状態でも readiness がその問題を report できるよう、gate の状態に関わらず常に有効です。
公開前チェックリスト(順序を変えない)
権限を分離する。 専用 Cloudflare API token を作り、必要な account/zone と Workers deploy、D1、R2、Queues、Vectorize、Workers AI、rate-limit binding、route の最小権限だけを与えます。token、account ID、resource ID、preflight bearer token を git・ブラウザー・ログに入れません。
資源を作る。 production 用の D1、private R2 bucket、photo Queue、別の DLQ、Workers AI access、rate-limit namespace、Vectorize index を作ります。Vectorize は作成時に固定なので必ず
--dimensions=768 --metric=cosineを指定します。Queue consumer は photo Queue に接続し、DLQ を設定します。実名を CI variables/secrets に置く。
DEMO_D1_DATABASE_NAME/ID、DEMO_R2_BUCKET_NAME、DEMO_QUEUE_NAME、DEMO_DLQ_NAME、DEMO_VECTORIZE_INDEX_NAME、DEMO_RATE_LIMIT_NAMESPACE_IDを repository に書き込みません。render-production-config.mjsが deployment 時だけ生成 config に差し込みます。remote migration を明示して適用する。 committed の
wrangler.production.jsoncに直接--configを向けてはいけません — placeholderdatabase_id(00000000-0000-0000-0000-000000000000)が非空のため、wrangler の D1 lookup は account への名前解決をせずこの placeholder をそのまま使い、--remoteを付けても実 DB には届きません。先に手元でDEMO_D1_DATABASE_NAMEなどの env var を揃えてnode apps/を実行し、生成されたdemo/ scripts/ render- production- config. mjs .wrangler.production.generated.jsonに対してのみpnpm -を実行します。- filter @vector- image- detection/ demo exec wrangler d1 migrations apply DB - - remote - - config . wrangler. production. generated. json --remoteのない command は local D1 なので production migration に使いません。手順の全体は operator runbook を参照してください。構成を検証する。
pnpm --filter @vector-image-detection/demo run deploy:dry-run:productionは placeholder config の構文確認で、PR CI が credential なしで実行します。deploy workflow のほうは.wrangler.production.generated.jsonを一度だけ render し、その同じ file を dry-run して deploy するため、dry-run が実 resource 名と writes-on 設定まで含めて検証されます。migration、D1 metadata の二つの pinned model ID、768/cosine index、Queue/DLQ、private R2、rate limit、production environment を readiness が pass する必要があります。seed を準備する。
node apps/は local manifest を検証します。remote を選ぶなら必ずdemo/ scripts/ seed- manifest. mjs node apps/と明記します。これは manifest/target 検証のみで、resource に書き込みません。demo/ scripts/ seed- manifest. mjs - - remote - - target production pnpm run demo:seed:localは deterministic local Worker resources で 100 thumbnails を同じ validation、D1 upload-operation、private R2、outbox/enrichment path に通し、attribution と unchanged rerun を確認します。この credential-free command は remote target を明示的に拒否します。remote seed は provision 後の authenticated operator action として deferred のままです。write をまだ off のまま deploy する。 production template は
PUBLIC_WRITES_ENABLED: "false"です。read-only gallery/search と operator readiness を確認します。docs job はこの demo gate とは独立して deploy できます。3 つの risk acknowledgement を人が承認する。 次の完全一致 values を secure CI variables に入れます。匿名 public writes、元画像 metadata の残留、reactive purge only moderation を理解していることが条件です。
ACK_ANONYMOUS_PUBLIC_WRITES=I_ACKNOWLEDGE_ANONYMOUS_PUBLIC_WRITES ACK_RETAINED_IMAGE_METADATA=I_ACKNOWLEDGE_RETAINED_IMAGE_METADATA ACK_REACTIVE_PURGE_ONLY=I_ACKNOWLEDGE_REACTIVE_PURGE_ONLY_MODERATION認証済み preflight を pass させる。 provisioning 中は repository variable
DEMO_DEPLOYMENT_ENABLEDを unset のままにし、demo deploy job を安全に skip させます。resource、read-only Worker、secret、acknowledgement がすべて用意できた最後の段階でだけDEMO_DEPLOYMENT_ENABLED=trueを設定します。DEMO_PREFLIGHT_URLと secretDEMO_PREFLIGHT_TOKENを用意し、pnpm run cloudflare:demo-preflightを実行します。/がすべての required check をapi/ v1/ operator/ readiness pass、production、public writes enabled、正しいモデル/Vectorize invariant と返さない限り CI の demo deploy は停止します。 deploy 用 secret も同時に用意します。AUTH_PASSWORD、AUTH_PASS_COOKIE、DEMO_PREFLIGHT_TOKEN(deploy 後のOPERATOR_PREFLIGHT_TOKEN)の 3 つを repository secret に入れます。gate secret 2 つは prefix を付けません。すでにその名前で repository secret に存在し、local の.envでも同じ key を使うためです。CI はwrangler deploy --secrets-fileで version と一緒に upload するので、dashboard での手動設定は不要です。gate secret が欠けた production Worker は serve を拒否します。 deploy 前の gate は「この Worker の readiness endpoint がまだそこに無い」状態を許容します。name が解決しない、connection が拒否される、Cloudflare の 1000 番台 edge error が返る場合に加えて、readiness JSON として parse できない body を返す200(旧 build や SPA shell が応答している状態)も同じ扱いで::warning::にして先へ進み、deploy がその Worker を置き換えます。境界は parse できるかどうかです。parse できる body はこの Worker が応答した証拠なので、check が fail していれば従来どおり job を止めます。401や404などの応答も止めます。初回 deploy だけは verification より先に traffic が切り替わりますが、password wall が公開を防ぎ、DEMO_DEPLOYMENT_ENABLEDが人による opt-in として残り、deploy 後の strict gate が必ず走って失敗時に rollback command を出力します。public writes を有効化する。 preflight と acknowledgement 後にのみ generated production config が true を設定し deploy します。deploy 後は一つの upload、処理状態、media authorization、human tag exact search、AI-word exact search、related degradation を運用者が記録して確認します。この live smoke test は provisioning 前には「完了」と宣言しません。
Related photos の実 index smoke check(手動、再現可能)
credential-free CI の Worker e2e leg は AI/Vectorize binding を持たないため(wrangler.e2e.jsonc)、GET / が実際の neighbours を返すかどうかは自動テストで確認できません。デプロイ済みの production/preview に対して、以下を運用者が手動で実行します。
# 0. cookie jar は checkout の外、mode 600 の使い捨てにする
# ("vid_demo_pass" は 1 年有効な bypass credential — repo に残してはいけない)
COOKIE_JAR=$(mktemp)
chmod 600 "$COOKIE_JAR"
trap 'rm -f "$COOKIE_JAR"' EXIT
# 1. password wall を通過して session cookie を保存
# AUTH_PASSWORD は運用者が保持する production secret
# --data-urlencode: password に + や & などの reserved 文字があっても壊れない
curl -sS -c "$COOKIE_JAR" --data-urlencode "password=$AUTH_PASSWORD" \
"https://<deployed-host>/__auth" -o /dev/null -w '%{http_code}\n'
# → 302 を確認
# 2. state=ready な既存写真の photoId を選ぶ(gallery か GET /api/v1/photos から)
PHOTO_ID="<既存の ready photo の id>"
# 3. related endpoint を叩く
curl -sS -b "$COOKIE_JAR" \
"https://<deployed-host>/api/v1/photos/$PHOTO_ID/related?version=v1&limit=8" | jq .期待される shape(RelatedPhotosResponse、apps/):
{
"version": "v1",
"photoId": "<PHOTO_ID>",
"items": [
{
"photo": { "id": "...", "state": "ready", "...": "..." },
"reason": {
"tier": "semantic",
"score": 0.83,
"vectorId": "<neighbourPhotoId>:<revision>",
"indexedDocumentRevision": 1
}
}
],
"nextCursor": null,
"degraded": false,
"degradedReason": null
}判定基準:
degraded: falseかつitemsが非空 — index は生きており、実 neighbours を返している。これが合格ライン。degraded: true, degradedReason: "vector_pending"— その写真の canonical vector がまだ Vectorize に反映されていない一時的な状態(eventually consistent)。数秒待って再試行する。degraded: true, degradedReason: "provider_unavailable"— Vectorize 参照そのものが失敗した障害状態。恒久的に続くなら Vectorize index の health/binding を調査する。items: []かつdegraded: false— index は生きているが、この写真の AI description に近い他の写真が存在しない、正当な「該当なし」。
Cloudflare CLI は認証済み account を操作します。wrangler r2 bucket create <name>、wrangler queues create <name>、wrangler vectorize create <name> --dimensions=768 --metric=cosine の対象名は各環境専用にし、production と local/preview を混ぜません。Queue/DLQ の consumer 構成は Wrangler config でも確認します。
100 thumbnails の seed と帰属
apps/ に 100 件(Oxford-IIIT Pet 60、Wikimedia Commons components 40)の明示的な collection があります。source、license、author は fixture credits と manifest.json に残します。配布・公開では各 source license を再確認してください。repository にあるのは thumbnail だけで、upstream full-resolution original はありません。
internal importer は同じ byte validation、durable upload operation、private R2、outbox/enrichment を使います。path 由来 stable seed ID と SHA-256 で completed/unchanged を skip するため再実行は idempotent、途中中断は再開可能、checksum 変更は旧写真を purge して置換します。削除は operator tombstone/purge を使い、R2、全 vector generation、D1 を成功まで再試行します。knownLabel は test expectation だけで、AI word/human tag として import してはいけません。legacy embeddings.bin も import しません。
日常運用と障害対応
誤用/緊急事態:
PUBLIC_WRITES_ENABLEDを false にして deploy し、新規 anonymous write を止めます。既存の ready media/search は別の明示的な公開停止を行わない限り読めることに注意します。不適切/削除要求: 公開または browser admin UI は作らず、認証済み運用者 purge を実行します。
DEMO_PURGE_URL、secretDEMO_PURGE_TOKEN(deploy 済み Worker のOPERATOR_PREFLIGHT_TOKENと同じ値)、DEMO_PURGE_PHOTO_ID、non-emptyDEMO_PURGE_REASONを shell/secret manager から渡してpnpm run cloudflare:demo-purgeを実行します。HTTPS の operator endpoint が durable tombstone/outbox を202で受理した後、Queue/repair が R2、全 vector generation、D1 relations を削除し、terminal tombstone diagnostics を保持します。reactive-only であり、自動検出・審査・通報ではありません。pending / enqueue_failed: outbox drain と upload-operation/R2 repair が durable record から再送・cleanup します。
processing retryable / DLQ: lease expiry、attempt/backoff、DLQ diagnostics を見て原因を直し、repair を再実行します。terminal error は無条件に公開しません。
検索が古い/related だけ失敗: D1 exact tiers は正本なので残ります。required revision、canonical revision、
photoId:revision、stale generation cleanup を確認します。retention: 期限切れは tombstone と retryable deletion で処理します。R2 lifecycle を追加するならアプリの purge record と矛盾させず、削除失敗を調査できるようにします。