Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/samgutentag/bcycle-map/llms.txt

Use this file to discover all available pages before exploring further.

BCycle Map supports two local development modes. The lightweight mode starts only the Vite dev server and is enough for verifying tests pass and the basemap renders — no Cloudflare credentials required. The full-stack mode adds two Wrangler processes backed by Miniflare so you can develop and test Worker code without pushing anything to Cloudflare. Both modes are covered below.

Mode 1: Frontend only (no Workers)

Use this mode when you want to iterate on UI code, run the test suite, or verify the basemap renders on a fresh clone.
npm install
npm test          # 51 tests via Vitest
npm run typecheck # tsc --noEmit
npm run dev:web   # Vite at http://localhost:5173
The map boots and renders the Santa Barbara basemap. Every call to /api/... returns 404 because there is no Worker running. That’s expected. Pointing at the deployed Worker for live data: If you want real station data without running Workers locally, copy .env.example to .env.local and set the read API URL:
# .env.local
VITE_API_BASE=https://bcycle-map-read-api.<your-account>.workers.dev
With VITE_API_BASE set, npm run dev:web fetches from the deployed Worker and every /api/... call succeeds, so you get live data in the local frontend without spinning up any local Workers.

Mode 2: Full-stack with local Workers

Use this mode when developing or debugging Worker code. Wrangler runs both the read API and the poller inside Miniflare, which simulates KV and R2 locally on disk.
Both wrangler dev processes must share the same --persist-to directory so they read each other’s KV writes. If you use different directories, the read API will never see snapshots written by the poller.
1

Terminal 1 — read API on port 8787

Start the read API Worker. Port 8787 matches the proxy target configured in vite.config.ts, so the frontend’s /api/... requests are forwarded here automatically.
npx wrangler dev --config wrangler.read-api.toml --persist-to .wrangler-state
2

Terminal 2 — poller on port 8788 with test-scheduled

Start the poller Worker on a different port. The --test-scheduled flag exposes the /__scheduled HTTP endpoint so you can trigger the cron handler manually instead of waiting for the real timer.
npx wrangler dev --port 8788 --persist-to .wrangler-state --test-scheduled
3

Terminal 3 — Vite dev server

Start the frontend. Because VITE_API_BASE is not set (or is empty), Vite’s proxy forwards every /api/... request to localhost:8787 where the read API is listening.
npm run dev:web
Open http://localhost:5173. The map will render but the station markers will be empty until data is seeded in the next step.
4

Seed data by triggering the poller

The poller’s scheduled handler is not called automatically in local dev. Trigger it once to fetch a live GBFS snapshot and write it to the local Miniflare KV store:
curl 'http://localhost:8788/__scheduled?cron=*/5+*+*+*+*'
After the request completes, refresh the frontend — station markers should appear on the map.

Simulating the production cron

To keep local KV fresh during a longer dev session, run the poller on a loop at the same 5-minute cadence as production:
while true; do
  curl -s 'http://localhost:8788/__scheduled?cron=*/5+*+*+*+*' > /dev/null
  echo "polled at $(date '+%H:%M:%S')"
  sleep 300
done
When running local Workers, do not set VITE_API_BASE in .env.local (or set it to an empty string). If VITE_API_BASE is set to a remote URL, Vite skips its proxy and the frontend talks to the deployed Worker instead of your local one.

Available npm scripts

ScriptWhat it does
npm testRun Vitest once and exit
npm run test:watchVitest in interactive watch mode
npm run typechecktsc --noEmit — type-checks the entire project
npm run dev:webVite dev server at http://localhost:5173
npm run dev:workerwrangler dev (poller only, local Miniflare)
npm run build:webProduction Vite build → dist/
npm run deploy:workerwrangler deploy (deploys the poller to Cloudflare)
npm run dev:worker starts only the poller in Miniflare — it does not start the read API. For a full local stack use the three-terminal setup above, which gives each Worker its own port and shared persistence.

Build docs developers (and LLMs) love