From 14d6a9c4e14e1e6a83ae23e115f7e517dc42b34d Mon Sep 17 00:00:00 2001 From: BASICBIT Date: Sat, 30 May 2026 17:27:43 -0400 Subject: [PATCH 1/2] Document custom staging domain --- docs/deployment/convex-environments.md | 9 +++++++++ docs/deployment/vercel-preview.md | 10 ++++++++-- docs/testing/playwright-visual-preview.md | 2 +- 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/docs/deployment/convex-environments.md b/docs/deployment/convex-environments.md index fb9ab64..846bb4b 100644 --- a/docs/deployment/convex-environments.md +++ b/docs/deployment/convex-environments.md @@ -46,6 +46,15 @@ The shared development deployment `scrupulous-corgi-247` is the current hosted E $env:CONVEX_DEPLOYMENT="dev:scrupulous-corgi-247"; $env:CONVEX_SELF_HOSTED_URL=""; pnpm exec convex dev --once --typecheck=try --tail-logs=disable ``` +## Custom Domain Plan + +Candidate direction: use readable Convex Cloud custom domains once the deployment settings are configured in the Convex dashboard: + +- development/staging Convex API: `convex.staging.vrdex.net` +- production Convex API: `convex.vrdex.net` + +Convex Cloud custom domains are configured from each deployment's dashboard settings and require a Convex Pro plan. Do not create Route 53 records alone; Convex must first provide the deployment-specific DNS records and certificate binding. After binding a custom Convex function domain, update the matching Vercel environment `NEXT_PUBLIC_CONVEX_URL` and `CONVEX_URL`, then redeploy the web app and rerun deployed health. + ## Notes There are two similarly named Convex projects in the account history: `vrdex` and `vrdex-85631`. Current recommendation is to keep the `vrdex` line of deployments and archive/delete the other only after confirming no dashboard, env, or deployment history still depends on it. diff --git a/docs/deployment/vercel-preview.md b/docs/deployment/vercel-preview.md index 5c985c5..8a915f4 100644 --- a/docs/deployment/vercel-preview.md +++ b/docs/deployment/vercel-preview.md @@ -62,9 +62,15 @@ Locked decision: `staging` is the shared non-production Vercel custom environmen - target name: `staging` - type: Preview custom environment - branch tracking: `staging` -- stable alias: `https://vr-dex-web-env-staging-basicbit.vercel.app` +- primary URL: `https://staging.vrdex.net` +- Vercel environment alias: `https://vr-dex-web-env-staging-basicbit.vercel.app` - deploy command from the repository root: `pnpm dlx vercel@54.4.1 deploy --target=staging --yes` +DNS for `staging.vrdex.net` is managed in the Route 53 public hosted zone for `vrdex.net`: + +- record: `staging.vrdex.net CNAME 0d67c3b757aeccf9.vercel-dns-016.com` +- Vercel domain binding: project `vr-dex-web`, custom environment `staging` + The `staging` Vercel environment points at the shared Convex development deployment: - `NEXT_PUBLIC_CONVEX_URL=https://scrupulous-corgi-247.convex.cloud` @@ -77,7 +83,7 @@ The `staging` Vercel environment points at the shared Convex development deploym GitHub Actions uses these repository settings for hosted mutation health: -- variable `VRDEX_HOSTED_E2E_BASE_URL=https://vr-dex-web-env-staging-basicbit.vercel.app` +- variable `VRDEX_HOSTED_E2E_BASE_URL=https://staging.vrdex.net` - secret `VRDEX_HOSTED_E2E_BROWSER_TOKEN` ## Validation diff --git a/docs/testing/playwright-visual-preview.md b/docs/testing/playwright-visual-preview.md index db5902f..061f01a 100644 --- a/docs/testing/playwright-visual-preview.md +++ b/docs/testing/playwright-visual-preview.md @@ -134,4 +134,4 @@ The `Deployed Health Checks` workflow runs after merges to `main`, after success Manual dispatch can run `all`, `staging-mutation`, or `production-smoke`. The optional `base_url` override applies only when dispatching a single selected target. The deployed health workflow uploads artifacts and fails the workflow on test failure, but it does not create GitHub issues automatically. -Current hosted mutation target: `https://vr-dex-web-env-staging-basicbit.vercel.app`, backed by the shared Convex development deployment. The deployed health workflow run `26682711966` passed `staging-mutation` after the Vercel staging environment and Convex dev E2E helper variables were configured. +Current hosted mutation target: `https://staging.vrdex.net`, backed by the shared Convex development deployment. The deployed health workflow run `26695304658` passed `staging-mutation` after the Vercel staging custom domain was configured. From c6b94fa8794a1b8c141c73f41391a90f4b3967ee Mon Sep 17 00:00:00 2001 From: BASICBIT Date: Sat, 30 May 2026 17:42:39 -0400 Subject: [PATCH 2/2] Wait for Convex functions before Playwright --- scripts/sync-convex-local-env.mjs | 43 +++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/scripts/sync-convex-local-env.mjs b/scripts/sync-convex-local-env.mjs index e89dd8e..2ee39d8 100644 --- a/scripts/sync-convex-local-env.mjs +++ b/scripts/sync-convex-local-env.mjs @@ -2,6 +2,8 @@ import { spawnSync } from "node:child_process"; import { mkdirSync } from "node:fs"; import path from "node:path"; import { fileURLToPath } from "node:url"; +import { ConvexHttpClient } from "convex/browser"; +import { makeFunctionReference } from "convex/server"; const scriptDir = path.dirname(fileURLToPath(import.meta.url)); const repoRoot = path.resolve(scriptDir, ".."); @@ -11,6 +13,9 @@ const localConvexEnvNames = ["VRDEX_ENABLE_E2E_HELPERS", "VRDEX_E2E_CONVEX_SECRE const localDeploymentName = process.env.CONVEX_LOCAL_DEPLOYMENT_NAME || "anonymous-agent"; const localCloudPort = process.env.CONVEX_LOCAL_CLOUD_PORT || "3210"; const localConvexUrl = process.env.CONVEX_LOCAL_URL || `http://127.0.0.1:${localCloudPort}`; +const readyTimeoutMs = Number(process.env.CONVEX_LOCAL_READY_TIMEOUT_MS || 180_000); +const readyPollMs = Number(process.env.CONVEX_LOCAL_READY_POLL_MS || 500); +const healthStatus = makeFunctionReference("health:status"); const convexBin = path.join( repoRoot, "node_modules", @@ -40,6 +45,40 @@ function convexEnv() { }; } +function sleep(ms) { + return new Promise((resolve) => setTimeout(resolve, ms)); +} + +function runConvex(args) { + return spawnSync(convexBin, args, { + cwd: repoRoot, + encoding: "utf8", + env: convexEnv(), + shell: process.platform === "win32", + timeout: 10_000, + }); +} + +async function waitForFunctionsReady() { + const startedAt = Date.now(); + let lastError = "Convex functions are not ready yet."; + const client = new ConvexHttpClient(localConvexUrl); + + while (Date.now() - startedAt < readyTimeoutMs) { + try { + await client.query(healthStatus, {}); + return true; + } catch (error) { + lastError = error instanceof Error ? error.message : String(error); + } + + await sleep(readyPollMs); + } + + console.error(`Timed out waiting for local Convex functions to become ready: ${lastError}`); + return false; +} + function syncEnvVarsOnce() { const entries = localConvexEnvNames .map((name) => [name, process.env[name]]) @@ -61,6 +100,10 @@ function syncEnvVarsOnce() { return true; } +if (!(await waitForFunctionsReady())) { + process.exit(1); +} + if (!localConvexEnvNames.some((name) => process.env[name])) { process.exit(0); }