Waybound Studio

Technical

Technical documentation

Architecture, integration contracts and security model – for anyone evaluating or building against the suite.

Overview

Two schematics before the prose: which services the suite actually consists of, and where the data comes from. Every box traces back to a real file in the relevant repository.

The suite as services

WB CoreRender · Python/uvicornTravel GuideRoute PlannerOn The RoadQuestsHappy Trailsroute-planner-webWB OPRender · Python/uvicornOpen Placesroute-planner-open-placesWB EXRender · staticExplorerwayboundWB CBRender · staticCar Bingowaybound-carbingoAndroid appNot published yetAndroid AutoWB KCthis siteroute-planner-docsplaces
Nine modules, five deployed services. The boxes are services; the names inside them are the modules they deliver.

Hosting and data sources

BrowserPhone in the carCloudflarewayboundstudio.comRenderroute-planner-webroute-planner-open-placeswayboundwaybound-carbingoroute-planner-docsSupabasePostgresprojects · user_settingssupabase_api_cachesystem_error_logscb_tiles · cb_board_setsExternal data sourcesFree tierOpenRouteServiceTrafikverket NVDBOpenStreetMapWikimedia · WikivoyagePremiumGoogle Maps Platform
What runs where, and which sources the app actually asks. Dashed = premium mode only, with your own key.

Architecture

Waybound Studio is a suite of ten parts, not a single monolithic system. That's a deliberate architectural choice, not inherited history: each module owns its own responsibility, its own data where possible, and talks to its neighbours through stated contracts rather than shared databases.

The suite as repositories

WB core (Travel Guide, Route Planner, On The Road, Quests, Happy Trails) is a FastAPI/Python backend with a vanilla JS/CSS frontend, Supabase as its database, deployed on Render. It's the suite's only stateful backend – identity, saved trips and the quest catalogue live here.

Open Places is its own service: FastAPI + PostgreSQL/PostGIS, a traceable open places database built from OpenStreetMap extracts. It only ever answers where, never when – route logic and timing don't belong there.

Explorer and Car Bingo are static sites with no backend of their own. They call Open Places directly from the browser (Explorer) or run fully offline against a shared seed (Car Bingo, with a thin Supabase service used only for sharing custom boards).

Android Auto is a native Android app that reads an already-planned trip directly from WB core's Supabase data. It never plans a route itself and never draws its own map.

Why the split looks like this

The boundary between Route Planner and Open Places is deliberate and defended: Route Planner owns the journey and knows when to stop, Open Places owns the places and knows what's there. Any attempt to move route intelligence down into the places layer ends with two systems disagreeing about the truth.

Modules as contracts

Every internal module in WB core declares its own contract: the exported surface, what each call promises, and what a caller therefore never needs to check itself. It isn't a document that can drift from the code – the contract is a test, not a comment.

The same principle holds between repositories: the interface between WB core and Open Places, and between WB core and the Android Auto app, is written and tested contracts owned by whichever side has the most to lose from breaking them. An Android Auto app already sitting in a car can't be updated the same afternoon a bug is found – so WB core owns that contract, tests against it, and changes it before the app is ever touched.

Operating model

Every service runs on Render. Static sites (Explorer, Car Bingo, Open Places) deploy straight from `main` with no build step; WB core runs a full test suite on every change.

One deliberate exception to "always over an API": the Android Auto app reads WB core's Supabase data directly – the same traveller account, the same saved trips – rather than going through a separate API. That's a tradeoff, not a shortcut: the boundary is enforced by Supabase Row Level Security (each traveller only ever sees their own rows) and by the written contract between the two repositories, not by a network call. Open Places, by contrast, is fully standalone and is always reached through its public HTTP API, never by reading its database directly.

Contracts and integration

For anyone evaluating the suite as a developer: here's what the interfaces actually look like between the parts that talk to each other across a repository boundary.

Open Places — an open HTTP API

A public, read-only HTTP API with no authentication, built to be callable directly from a browser. Core surfaces:

Facilities are deliberately three-state – present, unknown, or explicitly absent – rather than a binary flag. The default mode never hides an unsurveyed place just because a facility is missing; a stricter mode exists for anyone who'd rather filter hard.

CORS is open but scoped: `GET`/`OPTIONS` only, no cookies or credentials, and an explicit allowlist of origins rather than a wildcard. It's built for a standalone static site with no server of its own – like Explorer – to call it directly.

WB core ↔ Open Places

The boundary between the route engine and the places database is a written contract, not an implicit agreement: WB core owns timing and decides *when* a stop is needed, Open Places owns geography and answers *where* something exists. Stop types (overnight, lunch, fuel …) are mapped to a set of place categories on WB core's side of the boundary.

WB core ↔ Android Auto

The car app reads a trip that's already planned – never a calculation it initiates itself. The interface is written and tested before the app is ever touched, for a simple reason: an app that's already sitting in a car can't be updated the same afternoon a bug is found. Change the contract, watch the tests that prove it fail, then — and only then — change the app.

What's deliberately not a contract

No external integration exists today for Travel Guide, Quests or Happy Trails – they're internal surfaces in WB core, reached through the same logged-in session as the rest of the app, not through a separate public API. That could change, but isn't something to build against today.

Licensing and attribution when integrating

Building something on top of Open Places: the attribution that travels with every place (OpenStreetMap, and Trafikverket where applicable) must be preserved wherever you display that data onward. See Data Sources and Licenses for exactly what terms apply to each source.

Security and guardrails

Security is architecture, not a layer added at the end. Here's how we think about it, for developers, architects or security reviewers evaluating the suite.

Core principles

What the platform is built to withstand

Traffic and route data isn't sensitive by itself, but the account, saved trips, and where you currently are, is. The architecture is built with the following in mind:

Guardrails that are product decisions, not just engineering

Data handling in short

Place data in Open Places is honestly incomplete, and says so: a missing fact like a toilet usually means "not yet surveyed," never a guess presented as fact. See Data Sources and Licenses for exactly which data sources are used and under what terms.

*This is an architecture-level overview, not a complete security audit, and not a promise of the absence of future vulnerabilities. If you find something that looks wrong, reach out through the app's system menu.*

How do we handle data?

Data sources, privacy and terms — what we've actually reviewed, sourced and dated where relevant.