T
Sign in

DEPLOY-PAGES.md — Cloudflare Pages (`trading-tyno.pages.dev`)

DEPLOY-PAGES.md — Cloudflare Pages (trading-tyno.pages.dev)

Production URL: https://trading-tyno.pages.dev — the only host since 2026-11-03, when trading.tynolabs.com, dsh.tynolabs.com and terminal.tynolabs.com were removed from the Cloudflare tunnel and their DNS records deleted (only ssh.tynolabs.com remains on the tunnel). No custom domain is attached. Same source tree, SvelteKit SSR on Workers + Turso (libSQL); the default bun run build (Bun server) still exists for a self-hosted checkout.

Build / deploy

master is connected to the Pages project through the Cloudflare GitHub App: a push deploys. Any other branch produces a preview deployment.

git push origin master                  # → Pages build → production
bun run build                           # Bun server → build/ (self-hosted only)
ADAPTER=cloudflare bun run build        # what Pages runs → .svelte-kit/cloudflare
bunx wrangler pages deploy --project-name trading-tyno   # manual fallback

Pages dashboard: build command ADAPTER=cloudflare bun run build, output .svelte-kit/cloudflare, BUN_VERSION=1.4.4 (matches .bun-version).

wrangler.jsonc holds the project name, compatibility flags and the plain vars. TURSO_DATABASE_URL must stay in vars: wrangler pages deploy replaces the project's plain-text vars with that block, so a value set only in the dashboard is silently dropped on the next deploy (secrets survive). Without it db.ts falls back to file:, which the Workers client rejects — every route returns an empty 500. .dev.vars (gitignored) is the local equivalent for wrangler pages dev.

Secrets (set once, never committed)

bunx wrangler pages secret put TURSO_AUTH_TOKEN      --project-name trading-tyno
bunx wrangler pages secret put BETTER_AUTH_SECRET    --project-name trading-tyno
bunx wrangler pages secret put CAPTURE_LLM_KEY       --project-name trading-tyno

TURSO_DATABASE_URL is not a secret here: it is a plain var in wrangler.jsonc (see above), which is what makes it survive a wrangler deploy.

ORIGIN must be exactly https://trading-tyno.pages.dev. If a custom domain is added later, ORIGIN moves with it. Better Auth rejects /api/auth/* whose request origin differs from baseURL, and SvelteKit's CSRF check 403s every form POST — a mismatch shows up as a 404 on sign-in, not an obvious error.

Data

  • Turso aws-ap-south-1 (Mumbai, ~16 ms/query) — libsql://trading-skpawar1305.aws-ap-south-1.turso.io. The older aws-eu-west-1 DB is ~145 ms/query from India and is not used.
  • Schema: the live SQLite schema copied verbatim (sqlite_master), because the committed drizzle chain is not replayable (0016 writes REFERENCES order(id) unquoted). drizzle/ is still the source of truth for new migrations.
  • Import is FK-safe: orphan rows are skipped and reported. Production carries test residue (quote.party_id = 'c67-save-party', 1340 rows from the suite running against data.db), which Turso rejects.
  • Uploads are rows in upload_file (bin, name, mime, size, base64 bytes) in the same database — no object store and no filesystem. The client shrinks images to ~1600 px / q0.75 before sending (src/lib/imageShrink.ts), because the Worker must base64-encode the body inside its 10 ms CPU budget; the server caps every bin at 2 MB.

Known gaps on Workers

  • OCR / PDF capture (/capture, /api/capture-ocr): tesseract, magick and mutool are host CLIs; there is no equivalent on Workers. The LLM gateway path works, the local fallback and PDF rasterising do not.
  • No filesystem: anything that reaches for node:fs at request time must go through a bundled copy (import.meta.glob) or the upload_file table.
  • Worker CPU/body limits: uploads are capped at 2 MB per file because the base64 encode happens inside the 10 ms budget — raising the cap without re-measuring will reintroduce error code: 1102.
  • Worker CPU: the free plan allows 10 ms of CPU per request. It first bit five screens (error code: 1102); both causes were N+1 reads, not SSR — /hishob's per-contract legs preview and /weft-issue's full-table beam/order selects. Batched, all 81 screens fit again (86/86 live-check), so no plan upgrade is required. If a future screen trips 1102, fix the query shape before paying.

Backups

Production's only durable copy is Turso, so the restore point is the db-backup GitHub workflow: nightly at 20:30 UTC (02:00 IST) it dumps every table to one gzipped JSON per table plus a manifest (~1.3 MB, 58 tables, 33k rows) and keeps it as a workflow artifact for 14 days. Run it by hand from the Actions tab before a risky change. The phone's backup unit snapshots a file production no longer reads, so it protects nothing.

# restore into whatever TURSO_* points at: wipes, then inserts parents-first
export TURSO_DATABASE_URL=libsql://… TURSO_AUTH_TOKEN=…
bun scripts/db-snapshot.ts                 # dump → ./snapshot/<day>/
bun scripts/db-restore.ts snapshot/<day>   # restore that snapshot

A Cloudflare Worker cron was tried first and abandoned: serialising the dump exceeds the 10 ms CPU budget, and a Pages project has no cron triggers.