BCycle Map is ready to run locally within minutes of cloning. The frontend renders the Santa Barbara basemap from the firstDocumentation 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.
npm run dev:web, and once you deploy the three Cloudflare Workers and point VITE_API_BASE at the read-api URL, live station data flows through automatically. This guide walks you from a fresh clone all the way to a fully connected deployment.
Prerequisites
Before you start, make sure you have:- Node 20+ and npm (check with
node --version) - A Cloudflare account — the free tier is sufficient for a single active system
- A GitHub account — needed for the parquet compaction GitHub Actions workflow (runs every 3 hours)
wrangleris installed as a dev dependency; no global install required
Step-by-Step Setup
This installs all dependencies including
wrangler, vitest, vite, and the full frontend dependency tree (MapLibre GL JS, Deck.gl, DuckDB-WASM).API calls to
/api/... return 404 until a Worker is running. The basemap and map chrome render fine — only the station markers and live data require the read-api Worker. Continue to the deploy steps below to wire those up.If this is a fresh Cloudflare account you need to provision the KV namespace and R2 bucket before deploying Workers.
npx wrangler login # browser OAuth flow
npx wrangler whoami # note your Account ID for GitHub Secrets later
Both commands print an
id. Open wrangler.toml, wrangler.read-api.toml, and wrangler.smoke.toml and replace every PLACEHOLDER_REPLACE_AT_DEPLOY with the production id and preview_id respectively.https://pub-<hash>.r2.dev URL; you’ll need it for VITE_R2_PUBLIC_URL.The wildcard CORS origin is safe here — all data comes from the public GBFS feed and is already redistributable. Tighten
AllowedOrigins to your Pages domain once you have one.npx wrangler deploy # bcycle-map-poller (cron every 5 min)
npx wrangler deploy --config wrangler.read-api.toml # bcycle-map-read-api (HTTP)
npx wrangler deploy --config wrangler.smoke.toml # bcycle-map-smoke (daily cron)
Each command prints a
*.workers.dev URL. Save the read-api URL — the frontend needs it in the next step.VITE_API_BASE=https://bcycle-map-read-api.developer-95b.workers.dev
VITE_R2_PUBLIC_URL=https://pub-83059e704dd64536a5166ab289eb42e5.r2.dev
VITE_API_BASE is the read-api Worker URL from the previous step. VITE_R2_PUBLIC_URL is the public R2 bucket URL you saved when enabling the public development URL.curl https://bcycle-map-read-api.<your-account>.workers.dev/api/systems/bcycle_santabarbara/current
You should receive a JSON blob with
system, snapshot_ts, and an array of ~85 stations. If you get not found, the cron hasn’t fired yet — wait a moment and retry.The poller buffers JSON snapshots in KV throughout each hour. A GitHub Actions workflow seals those into R2 parquet files every 3 hours. Add the following secrets under Settings → Secrets and variables → Actions in your fork:
CF_ACCOUNT_IDnpx wrangler whoamiCF_KV_API_TOKENCF_KV_NAMESPACE_IDid from Step 4R2_ACCESS_KEY_IDbcycle-map-archive)R2_SECRET_ACCESS_KEYR2_BUCKETbcycle-map-archiveThe workflow at
.github/workflows/compact.yml runs every 3 hours at 5 past the hour (5 */3 * * *). Because it seals every finished buffer in one pass, a 3-hour cadence still backfills cleanly even if a run is skipped. Trigger it manually from the Actions tab to test compaction before waiting for the next scheduled run.Local Three-Terminal Dev (No Deploy Required)
If you want to iterate on Worker code without deploying, usewrangler dev with a shared persist directory so both Workers see the same local KV state:
Available npm Scripts
| Script | What it does |
|---|---|
npm test | Run Vitest once (51 tests) |
npm run test:watch | Run Vitest in watch mode |
npm run typecheck | tsc --noEmit across the whole project |
npm run dev:web | Vite dev server at http://localhost:5173 |
npm run dev:worker | wrangler dev for the poller (Miniflare) |
npm run build:web | Production build → dist/ |
npm run deploy:worker | wrangler deploy (poller only) |
npm run compute-routes | Compute station-to-station travel-time matrix via Google Maps Directions API |
npm run compute-popularity | Compute per-station popularity rankings from R2 parquet archive |
npm run compute-leaderboards | Compute corridor leaderboards from R2 parquet archive |
npm run compute-corridors | Compute corridor data and write gbfs/systems-index.json to R2 |
Next Steps
Architecture
Understand the three-Worker design, KV key layout, R2 parquet partitioning, and the hot vs. cold data path split.
Add a System
Add any BCycle GBFS system to
systems.json and redeploy the poller to start collecting data.GitHub Actions
Learn how the every-3-hours compaction workflow seals KV buffers into R2 parquet using
parquet-wasm and apache-arrow.API Reference
Explore every endpoint the read-api Worker exposes, from
/current to /trips to /snapshots.