Deployment topology
Everything runs in the vumbnail.com Cloudflare zone. The product is a small
set of Workers plus an edge Snippet; several supporting and legacy Workers sit
around them.
Workers & routes
Section titled “Workers & routes”| Worker | Route | Role |
|---|---|---|
vumbnail-thumbnail | vumbnail.com/* (apex catch-all) | the product: resolve + watermark + serve thumbnails |
| (Snippet) watermark-router | runs ahead of the apex Worker | hot-set short-circuit & edge redirects (cost) |
vumbnail-accounts | accounts.vumbnail.com/* | Stripe webhook → entitlement sync (KV + D1 + GitHub) |
vumbnail-astro-site | astro.vumbnail.com/* | marketing site; thumbnail Worker passes non-thumbnail paths here |
vumbnail-animated-thumbnail-renderer | service binding | WASM animated rendering (flagged) |
vumbnail-video-metadata (consumer) | queue | metadata observation (flagged) |
playlist-resolver(-worker) | external resolver | resolves unknown YouTube playlists |
| API / dashboard | starter-kit routes | operator metrics + auth (mostly internal) |
Public R2 is exposed at cache.vumbnail.com; the edge Snippet redirects hot
watermarked traffic there, and a WAF rule blocks …/clean.jpg.
Test & staging hosts
Section titled “Test & staging hosts”watermark-test.vumbnail.com— thumbnail Worker with animated thumbnails and debug enabled.relay-test.vumbnail.com— forces Vimeo relay-only mode, separate R2 prefix.accounts-staging.vumbnail.com,accounts-preview.vumbnail.com— webhook staging/preview.
Legacy (pre-Cloudflare)
Section titled “Legacy (pre-Cloudflare)”legacy-vumbnail-vercel-api, legacy-vumbnail-video, and
legacy-vumbnail-worker-canary are retained from the Vercel era; moving the last
/6* canary routes fully onto Cloudflare is a roadmap item.
Bindings
Section titled “Bindings”Thumbnail Worker: THUMBNAIL_BUCKET (R2), THUMBNAIL_CONFIG (KV), ASSETS
(watermark.png + fallbacks), IMAGES (legacy transform), SITE_PASSTHROUGH_SERVICE
(→ Astro site), ANIMATED_THUMBNAIL_RENDERER (service binding),
VIDEO_METADATA_QUEUE (producer), plus VERSION_METADATA.
Accounts Worker: PROCESSED_EVENTS_STORE (KV), THUMBNAIL_CONFIG (KV,
shared), BILLING_ENTITLEMENTS_DB (D1); secrets STRIPE_SECRET_KEY,
STRIPE_WEBHOOK_SECRET, GH_TOKEN.
Request path (clean vs. watermarked)
Section titled “Request path (clean vs. watermarked)”Browser → vumbnail.com/<id>.jpg │ ▼ Cloudflare edge Snippet (watermark-router) ├─ paying domain/IP? → pass through ──┐ ├─ /.jpg malformed? → 308 error.jpg │ ├─ Borås loop? → 307 wm.jpg │ ├─ hot id + wm referrer? → 307 cache.vumbnail.com/.../wm.jpg └─ else → pass through ──┤ ▼ vumbnail-thumbnail Worker ├─ parse id/size/password ├─ watermark decision (clean | wm) │ └─ KV entitlement projection (paid bypass) ├─ edge cache → R2 variant → R2 clean→wm └─ miss: resolve source (Vimeo/YouTube/relay) → store R2 → cache → respondDeploy & safety
Section titled “Deploy & safety”- Per-app deploys via Wrangler (
bun --filter @repo/<app> deploy); the Snippet has its owndeploy/verify-hotset/smoke/rollback:snapshot. - The thumbnail Worker ships with a predeploy route-safety guard and ramps by
percentage (
0 → 1 → 5 → 10 → 25 → 50 → 100) with a health-check suite. - Multi-worker deploy safety is enforced by
scripts/cloudflarechecks so one app’s deploy can’t clobber another’s routes. - The hard cost guardrail applies to every deploy: ≥ $1/month of new Cloudflare
spend requires a written estimate in
docs/first.