Skip to content

Deployment

A Cloudflare Worker with a D1 database and an R2 binding.

Bindings

BindingKindResource
DBD1scry-diff-db — pairs, issues, events, connections, screens
SCREENSHOT_BUCKETR2scry-component-snapshot-bucket — screenshots, evidence, run artifacts

The bucket is shared with build processing and the dashboard. This service reads screenshots it did not write, which is the point: pairs reference existing objects rather than copying them.

Secrets

SecretPurpose
SERVICE_AUTH_TOKENBearer token for every route except /healthz. Held only by the dashboard
OPENROUTER_API_KEYThe configured production annotator
ANTHROPIC_API_KEYSupported when ANNOTATOR_PROVIDER=anthropic
FIGMA_CLIENT_ID / FIGMA_CLIENT_SECRETFigma OAuth app
FIGMA_OAUTH_REDIRECT_URIMust match the app's registered callback
FIGMA_TOKEN_ENCRYPTION_KEYEncrypts stored Figma tokens at rest in D1

FIGMA_TOKEN_ENCRYPTION_KEY is load-bearing: stored connections cannot be decrypted without it, so rotating it invalidates every existing connection and each project has to reconnect.

Variables

VariableProduction default
ANNOTATOR_PROVIDERopenrouter
ANNOTATOR_MODELopenai/gpt-5.6-sol
ANNOTATOR_REASONING_EFFORTmedium
ANNOTATOR_MAX_TOKENS16000
FIGMA_APP_KINDWhich kind of Figma app the connection uses
ANNOTATOR_BASE_URLOverride the provider endpoint

Deploy stamps — SCRY_ENV, SCRY_COMMIT, SCRY_BRANCH, SCRY_BUILD_TIME, SCRY_DEPLOY_ID, SCRY_ACTOR — are injected at build time and reported by /healthz.

Migrations

Schema lives in migrations/, applied in order:

MigrationAdds
0001_initPairs, issues, review state
0002_issue_lifecycleStatus transitions and events
0003_diff_evidenceHybrid evidence keys on a pair
0004_figma_oauthEncrypted Figma connections
0005_figma_ingestDesign snapshots and imported screens
0006_candidates_severityCandidate status, severity, confidence

Staging has its own database (scry-diff-db-staging) and its own bucket (scry-component-snapshot-bucket-staging), so review data never crosses tiers.

Local development

bash
npm install
echo 'SERVICE_AUTH_TOKEN = "local-dev-token"' > .dev.vars
npm run db:migrate:local
npm run dev          # http://localhost:8789
npm test             # vitest + @cloudflare/vitest-pool-workers

Tests run against real D1 and R2 through miniflare rather than mocks, so migrations and bucket behaviour are exercised as written.

Verifying a deploy

bash
curl -s -o /dev/null -w '%{http_code}\n' https://diff.scrymore.com/healthz   # 200
curl -s -o /dev/null -w '%{http_code}\n' https://diff.scrymore.com/api/queue # 401

401 on an authenticated route is the healthy answer without a token — a 200 there would mean the service is answering unauthenticated callers.

Released under the MIT License.