Deploying
LookAlike’s interactive scoring runs in the browser, but the production deployment uses a TypeScript Cloudflare Worker. The Worker serves the application shell through Workers Static Assets, serves the national data package from a private R2 bucket, and runs Better Auth and the protected product API against D1.
Deploying the app
Section titled “Deploying the app”Build the Cloudflare bundle
Section titled “Build the Cloudflare bundle”First, build the application to static HTML, JavaScript, and assets:
cd webpnpm installpnpm build:cloudflareThis runs the web and Worker TypeScript checks, builds the Vite application into dist/, and creates a separate dist-cloudflare/ bundle with the data directory excluded. Ordinary Vite previews retain local data, while Wrangler can only see the small application bundle.
Output structure
Section titled “Output structure”After building, web/dist/ contains:
index.html— the entry pointassets/— minified JavaScript and CSSdata/— the committed compatibility data files (PMTiles, binary feature packs, JSON metadata, metro definitions, store locations). Pre-computed candidate rankings were removed when scoring moved into the browser; the app ranks tracts live. Seeweb/public/data/RELEASE.mdfor what this copy is and is not.
The application bundles and small assets in dist-cloudflare/ deploy through Workers Static Assets. The data/ directory deploys separately to R2.
Hosting requirement: HTTP range requests
Section titled “Hosting requirement: HTTP range requests”Critical: The host must support HTTP range requests (Accept-Ranges: bytes headers). This is required to serve the PMTiles vector tile file efficiently.
PMTiles (tracts.pmtiles, about 29 MiB) is a single binary file containing all census tract boundaries as vector tiles. It is larger than Cloudflare Workers Static Assets’ 25 MiB per-file limit. The LookAlike Worker therefore reads it from R2 and returns correct 206 Partial Content responses for MapLibre’s byte-range requests.
After deployment, verify the route with:
curl -I -H "Range: bytes=0-99" https://your-deployed-site.com/data/tracts.pmtilesYou should see a 206 Partial Content response, not 200 OK.
Test the production runtime locally
Section titled “Test the production runtime locally”Seed Wrangler’s local R2 store, then run the Worker:
cd webpnpm data:seed:localcp .dev.vars.example .dev.varspnpm db:migrate:localpnpm auth:invite:local you@example.com --bootstrappnpm dev:cloudflareThe local Worker exposes /api/health, serves /data/* from local R2, and serves the application from dist/.
It also runs the invite-only authentication flow. Local email mode keeps the magic link in Worker memory and shows
a localhost-only continuation button after the sign-in request; it does not send email or print the token.
Ordinary pnpm dev is a front-end-only workflow and bypasses authentication by default. Use the Cloudflare command
when testing accounts, organizations, D1, client authorization, R2 delivery, or production routing.
After signing in, /account provides passkey and session management. Organization owners and administrators use
/admin for retail-client creation, invitations, member-to-client analyst/viewer grants, and recent audit activity.
Always test these pages through Wrangler rather than the front-end-only Vite workflow because their data and
authorization come from the Worker and D1.
Deploy to Cloudflare
Section titled “Deploy to Cloudflare”Before the first deployment, create the remote national-data R2 bucket, the separate private customer-data R2
bucket, and the D1 database; replace the placeholder D1 identifier in
wrangler.jsonc, apply the migrations, and configure BETTER_AUTH_SECRET and MAILGUN_API_KEY as Worker secrets.
Publish and activate a validated data release from the separate data-pipeline repository, then deploy the application.
cd webpnpm exec wrangler r2 bucket create lookalike-datapnpm exec wrangler r2 bucket create lookalike-customer-datapnpm deploy:cloudflareThe application repository deliberately has no remote data-upload command. Production releases are published by
LookAlike-data-pipeline/scripts/publish-release.sh and activated separately after validation.
Remote resource creation and custom-domain attachment require the approved Cloudflare account and domain decisions. Do not run the remote commands against an unintended account.
Deploying the documentation site
Section titled “Deploying the documentation site”This site is built with Astro and Starlight. It is separate from the app and serves as a reference for using and operating the explorer.
Build the docs
Section titled “Build the docs”cd docs-sitepnpm installpnpm buildThis generates static HTML in docs-site/dist/.
Deploy the docs
Section titled “Deploy the docs”The docs site is pure static HTML, deployed as its own Workers Static Assets Worker so it can stay public while the application remains invite-only. Its configuration lives in docs-site/wrangler.jsonc: Worker name lookalike-docs, assets served from ./dist, custom domain docs.lookalikeiq.com.
cd docs-sitepnpm deploy # builds, then runs wrangler deployCurrent deployment status
Section titled “Current deployment status”The application is deployed at https://app.lookalikeiq.com, with
https://lookalike.sean-525.workers.dev retained as a fallback. Both R2 buckets, D1 migrations, Better Auth
secrets, release 2026-07-11-01, and the initial owner invitation are active. Magic-link email is delivered
through Mailgun on mg.lookalikeiq.com. Live checks verified the health route, release pointer, a 100-byte PMTiles
partial response, unauthenticated API rejection, and a Mailgun magic-link request. The documentation site has its
deployment configuration in the repository but has not been deployed yet. Production sign-in completion, passkey
registration, and visual browser review remain.
Testing before deployment
Section titled “Testing before deployment”Before deploying, verify the build works and the app runs:
cd webpnpm build:cloudflarepnpm data:seed:localpnpm exec wrangler devThen test with a production-like connection (e.g., in Chrome DevTools, set a slow 4G throttle) to confirm PMTiles loads without lag.
For the docs:
cd docs-sitepnpm buildpnpm preview # serves the docs locally at http://localhost:4173Data asset size
Section titled “Data asset size”The published national release 2026-07-11-01 totals approximately 51 MiB:
tracts.pmtiles— about 35 MiB (vector tiles of all census tract boundaries)tracts/features.f32— about 6.7 MiB (census features for all tracts, binary format)tracts/labels.json— about 2.8 MiB (tract labels and metadata)tracts/sims.u8andtracts/has.u8— 1.8 MB combined for the 11 built-in brands- Metro data — 1.9 MB combined
- Store overlays — 0.7 MB combined
- Other tract arrays and metadata — ~3.2 MB
The production Worker reads all of this from R2. A compatibility copy of the same release is committed at web/public/data/ for local development and the consistency tests; it is about 46 MiB because its tracts.pmtiles is an older build (see web/public/data/RELEASE.md). Ordinary Vite builds include that committed copy, and Wrangler excludes it from Workers Static Assets. There is no browser service worker; the app relies on HTTP cache headers and ETag revalidation.
Rebuilding the data pipeline
Section titled “Rebuilding the data pipeline”If you need to update the data (e.g., new store locations, new demographic year), see Rebuilding the data.
The separate data-pipeline repository publishes immutable releases to R2. Application deployment and data publication are independent operations.