See the map first.
Prices, freshness and a clear next step. No account wall in the preview.
From c3169cd15e98b412070d733be28e08563d7ce106 Mon Sep 17 00:00:00 2001 From: AKolenda <91154044+AKolenda@users.noreply.github.com> Date: Sun, 27 Sep 2026 15:13:13 -0600 Subject: [PATCH] Link every download to the latest GitHub release The website, handbook and README link the Android APK and the source archive at github.com/AKolenda/openfuel/releases/latest/download/, and the site no longer bundles them under /downloads. A new release-assets command collects the APK, its checksum and the source archive in dist/release for a GitHub release; the build still packages the source archive for the checks. --- .env.example | 2 +- README.md | 4 +-- apps/docs/pages.js | 2 +- apps/docs/pages.json | 10 +++--- apps/web/_headers | 5 --- apps/web/designs/variant-b/index.html | 4 +-- apps/web/index.html | 6 ++-- apps/web/preview/index.html | 4 +-- docs/BUILD_STATUS.md | 3 +- docs/HOSTING.md | 22 ++++++++++---- docs/RUNNING_COSTS.md | 5 +-- tests/browser_checks.py | 9 +++--- tests/test_foundation.py | 2 +- tests/test_repository.py | 2 +- tools/project.py | 44 +++++++++++++-------------- tools/public_config.py | 3 +- 16 files changed, 67 insertions(+), 60 deletions(-) diff --git a/.env.example b/.env.example index 864cc9f..86b8c71 100644 --- a/.env.example +++ b/.env.example @@ -3,7 +3,7 @@ # The builder reads only the keys in this file; never store admin credentials here. OPENFUEL_PUBLIC_ENV=development OPENFUEL_PUBLIC_API_BASE_URL=/api/v1 -OPENFUEL_PUBLIC_SOURCE_URL=/downloads/openfuel-source.zip +OPENFUEL_PUBLIC_SOURCE_URL=https://github.com/AKolenda/openfuel/releases/latest/download/openfuel-source.zip # A built static site does NOT read its host's environment after deployment. # Changing these values requires a fresh site build. # Optional donation page (HTTPS) for the database and map costs. Without it no donate diff --git a/README.md b/README.md index d67c746..382cdf0 100644 --- a/README.md +++ b/README.md @@ -8,8 +8,8 @@ SwiftUI app still needs an Apple SDK build and simulator verification on a Mac. - [Public repository](https://github.com/AKolenda/openfuel) - [Website](https://openfuel.ca/) and [station map](https://openfuel.ca/preview/) -- [Android APK](https://openfuel.ca/downloads/openfuel-android.apk) — development build, Android 8+ -- [API health](https://openfuel.ca/api/v1/health) and [source download](https://openfuel.ca/downloads/openfuel-source.zip) +- [Android APK](https://github.com/AKolenda/openfuel/releases/latest/download/openfuel-android.apk) — development build, Android 8+ +- [API health](https://openfuel.ca/api/v1/health) and [source download](https://github.com/AKolenda/openfuel/releases/latest/download/openfuel-source.zip) Allow location when you enter the app to find nearby stations. If permission is unavailable, search a Canadian city or choose an area on the map. The app uses diff --git a/apps/docs/pages.js b/apps/docs/pages.js index fdad839..801077c 100644 --- a/apps/docs/pages.js +++ b/apps/docs/pages.js @@ -1,2 +1,2 @@ /* SPDX-License-Identifier: AGPL-3.0-only; generated from pages.json. */ -window.OPENFUEL_PAGES=[{"id":"start","title":"Get started","group":"Start here","description":"Open the real station map, install Android, or run the Expo project.","body":"
OpenFuel is an open-source fuel map with a working web app, native Android app, React Native Expo project and SwiftUI source. The shared Cloudflare database contains real OpenStreetMap station locations.
Open the app Download Android APK
Allow location to find stations near you, or search a Canadian city. Prices are blank until someone reports what they actually saw at the pump. Community reports are public and unverified. Station and price coverage may be incomplete.
npm install\nnpm run devThe local development database stays on your computer. Follow the root README for station data import and mobile build commands.
apps/web/ Website + real station web app\napps/docs/ Handbook UI and content\napps/android/ Kotlin / Jetpack Compose\napps/expo/ React Native / Expo Go\napps/ios/ SwiftUI + Foundation core + XcodeGen\nservices/live/ Current Cloudflare Worker + D1\nservices/edge/ Earlier Worker references\nservices/api/ Earlier FastAPI / SQLite reference\nservices/registry/ Review model and PostgreSQL draft\npackages/ Shared contracts, data and design assets\ntools/ Build, import and verification commands\n.github/workflows/ CI and native build jobsEach platform keeps its own build system and shares the public station API. One change can update the API, website and mobile clients together. Do not create nested Git repositories in the apps.
The earlier synthetic fixtures and interface studies are retained as historical design and test resources. The live web route reads real station data and rejects a sample API response.
"},{"id":"website","title":"Website & documentation","group":"Build","description":"A real Leaflet map, browser location and Canadian city search.","body":"The landing page is in apps/web/. The working map is in apps/web/preview/. Documentation content is apps/docs/pages.json; the build generates pages.js.
npm run build\nnpm run devThe web app and API share an origin. A plain static server can render the shell but needs the API for city search and station lookup. Website /, map /preview/ and handbook /docs/ ship together, with the station snapshot as static files under /data/stations/ for the Worker.
To show donate links, set OPENFUEL_PUBLIC_DONATE_URL (HTTPS) in .env before building. Without it no donate link appears.
On entry, the browser asks for location. The map shows the returned device coordinates and accuracy. If location is denied or unavailable, search a Canadian city, enter latitude and longitude, or move the map and choose Search this area. The app never substitutes a fictional current location.
Leaflet 1.9.4 and MapLibre GL JS 5.24.0 are bundled locally; MapLibre loads when the base map starts. The base map is OpenFreeMap vector tiles drawn in OpenFuel’s style from packages/map-style. Without WebGL, or if OpenFreeMap refuses its tiles, OpenStreetMap raster tiles are used instead. Tiles load for the viewed area with visible attribution and normal browser caching. No bulk download or offline tile feature is provided.
If OpenFuel’s database reaches its free daily limit, the map keeps saved prices on screen under a notice until live prices return after midnight UTC.
"},{"id":"android","title":"Android development","group":"Build","description":"Install the native APK or develop with React Native and Expo Go.","body":"This is a development APK, not a Play Store release. Android may ask you to allow installation from your browser. Allow location in the app, or use a manual area. Real station coordinates are shared with the web app; missing prices stay unknown until reported.
The apps/expo/ project provides a React Native implementation for Expo Go. Follow its README to install dependencies, start Metro and open the project on your phone. Your phone must be able to reach the development server. Expo source and the compiled native Android APK are separate deliverables.
The Kotlin / Jetpack Compose project lives in apps/android/. Use its Gradle wrapper and README for build and device commands. The public API URL is safe to ship in the app; account credentials and signing secrets are not.
Check the root README and evidence files for the exact APK build and emulator runs. An emulator test does not replace testing location and navigation on your own phone.
"},{"id":"ios","title":"iOS development","group":"Build","description":"SwiftUI, MapKit and the current live station API; a Mac is required for Apple SDK and device verification.","body":"The active app uses MapKit, foreground CoreLocation, Canadian city search and the current Cloudflare API. Stations without reported prices remain visible. Lists and map pins use direct remote brand logos with initials as a fallback. A compact control row and fully hideable results sheet preserve map space.
OpenFuelCore validates live station responses, report receipts and cached areas. The last approximate area loads before a fresh location or network request completes. Earlier sample fixtures remain separate historical tests.
swift test --package-path apps/ios/OpenFuelCore\n# On a Mac with Xcode + XcodeGen:\npython3 tools/project.py ios-buildXcodeGen reads apps/ios/project.yml, including public xcconfig inputs and the UI-test target. No signing credentials are embedded. Follow apps/ios/README.md when Xcode is available.
The portable Swift tests and read-only live API checks pass on Linux. SwiftUI files passed syntax parsing. Apple SDK compilation, MapKit rendering, permission dialogs, iPhone layout and a signed IPA still require macOS/Xcode; these have not been verified.
Current build status · Xcode configuration
"},{"id":"api","title":"API & contracts","group":"Build","description":"Nearby real stations, Canadian city search and public unverified reports.","body":"| Endpoint | Use |
|---|---|
GET /api/v1/health | Service and database health |
GET /api/v1/stations?lat=53.54&lon=-113.49&radius=10000&fuel=regular | Nearby real stations; radius is metres |
GET /api/v1/geocode?q=Edmonton | Canadian city search |
GET /api/v1/regions | Snapshot coverage and attribution |
POST /api/v1/reports | A price actually observed at a station |
Live responses identify mode: live and is_demo: false. Station IDs have the form osm-node-123 or osm-way-123. Prices are nullable integer thousandths of CAD per litre: a value of 1499 means $1.499/L, displayed as 149.9 ¢/L. This is a unit example, not a reported pump price.
Station locations, city search and regions come from the bundled snapshot; D1 holds current prices and reports. Station answers carry Cache-Control: private, max-age=15, city search public, max-age=86400, regions public, max-age=3600 and health no-store. Prices can be about 15 seconds behind a new report on other Worker instances.
A request contains station_id, fuel_type, price_milli, a random client_id and a unique request_id. Reuse the same request ID when retrying an unconfirmed submission. Only show a report as accepted after the service confirms its ID, station, fuel and price. Rate limits and validation apply.
When OpenFuel’s daily database budget is spent, the API answers HTTP 503 with {\"error\":\"spending_cap\",\"reason\":…,\"scope\":\"all\"|\"reports\",\"resets_at\":…,\"message\":…,\"donate_url\":…} until midnight UTC. scope: all pauses database reads: searches still answer for areas whose prices the Worker already holds. scope: reports pauses new reports only. When Cloudflare’s own daily request limit is reached, Cloudflare answers HTTP 429 with error 1027: an HTML page, or JSON with error_code 1027 and error_name workers_daily_limit when the client sends Accept: application/json. Treat either like scope: \"all\" until midnight UTC and keep saved stations on screen. Other Cloudflare 429s, such as 1015 rate limiting, are not the daily limit.
Reports are public, anonymous and unverified. Only submit prices actually checked at that station. Run integration tests against local D1; never seed made-up pump prices into the public database.
The FastAPI/SQLite service and PostgreSQL/PostGIS registry drafts remain as earlier reference work. They are separate from the deployed Cloudflare API.
Current live API contract · OpenAPI JSON
"},{"id":"parity","title":"Native visual parity","group":"Build","description":"Historical design references and honest native verification boundaries.","body":"The current web app, Kotlin Android app and Expo project use real station coordinates. The earlier six-station fixture and illustrated map remain historical design/test resources. SwiftUI source now uses the live API and MapKit; Apple SDK compilation and iPhone verification remain outstanding.
Browser screenshots verify browser rendering. Native screenshots must come from the Android app or iOS app being evaluated. JavaScript export proves bundling, not Expo device behavior. Do not claim pixel parity or an iPhone build from shared source alone.
Review map interaction, location permission denial, missing-price stations, reporting, cache age, keyboard behavior and large text on the intended device.
Current build status · Historical visual acceptance requirements
"},{"id":"state","title":"Station lifecycle","group":"Data & community","description":"Additions, corrections and closures stay separate from a raw vote count.","body":"The working app uses a Cloudflare Worker, static station files and D1 for real station locations and unverified community prices. PostgreSQL/PostGIS and Supabase material below describes the retained registry foundation, not a prerequisite for this prototype.
The tested model lives in services/registry/policy.py. Three proposal-scoped attestations raise triage priority; they do not publish a station. New records need checked evidence and review. Permanent closure requires two distinct reviewer inputs.
The production service still needs actual authorization, source verification, coordinated-abuse resistance and prevention of self-review. The model is not a deployed moderation API.
A status change or reopening retains history and version checks. Old prices do not mean a station is closed. Nearby records are duplicate candidates, not automatic merges. Reviewed changes append public history; private reviewer/attester details are not exported.
The included schema is an unexecuted PostgreSQL/PostGIS draft. It is not the database currently running under the reference API. Test the schema, transaction paths and permissions before wiring either native app to it.
Read docs/reference/DATABASE_AND_STATION_LIFECYCLE.md in the source for the detailed original proposal. Imported OSM data, brand artwork and source code have separate licence obligations.
OpenFuel imports Canadian fuel-station locations from OpenStreetMap. Records can have missing addresses, names or amenities. Their provenance and import date are recorded with the dataset. OpenStreetMap data is available under ODbL and city names from GeoNames under CC BY 4.0.
The website and Android app draw OpenFreeMap vector tiles with MapLibre inside a Leaflet map, in OpenFuel’s own style: a fork of OpenFreeMap Liberty recoloured after CARTO Voyager. No map key or account is needed. Without WebGL, or if OpenFreeMap refuses its tiles, the map uses OpenStreetMap’s standard raster tiles. Expo uses those raster tiles, and the SwiftUI app uses MapKit.
On the website the credit reads “OpenFreeMap © OpenMapTiles · Style after CARTO Voyager · Data © OpenStreetMap contributors” and stays visible on desktop and mobile. The browser sends its normal user agent and an origin referrer, respects HTTP caching, and requests only tiles for the viewed map. There is no area-download feature.
OpenFreeMap · OpenStreetMap tile policy · OSM licence · GeoNames
Google Maps and Apple Maps are only used for directions; their links contain the actual selected station coordinates. The destination app handles origin location and route calculation. Straight-line distances in OpenFuel are not road distances or journey times.
The repository retains fictional map artwork and sample fixture sets for the earlier design study. They are not used as live station locations or current prices. Third-party brand logos are not bundled into the new web map.
"},{"id":"testing","title":"Build evidence","group":"Operate","description":"Executed checks, explicit unexecuted platform gates, and logs—not inferred release readiness.","body":"python3 tools/project.py check --native-cores --web\nnpm test\npython3 tools/generate_mobile.py --checkXcode/SwiftUI compilation, iPhone simulator screenshots, real-device handoff and the retained PostgreSQL/pgTAP migration path. Android and Cloudflare prototype checks are recorded in the executed output above. A workflow file is not a successful run, and the real map requires actual imported station records, valid coordinates and a working API. Test location coordinates used in browser/emulator checks are explicitly injected for reproducibility, not the operator’s physical location.
The visual gate fails when approved real native screenshots are missing. Native parity · Database checks
"},{"id":"privacy","title":"Privacy & source boundaries","group":"Operate","description":"One-shot location permission, public reports and device-local saved areas.","body":"The web app requests a one-shot device location on entry. Your browser owns the permission decision. It displays the returned coordinates and accuracy; denial leaves city search and map exploration available. Coordinates go to OpenFuel to query nearby stations. The application does not request background location or track journeys.
Cloudflare serves the website and public API. OpenFreeMap receives requests for the viewed map area (OpenStreetMap's tile servers if WebGL or OpenFreeMap is unavailable), including normal IP/browser metadata and the site origin. Canadian city search uses a GeoNames index through the OpenFuel API. Choosing directions opens your map provider with the selected station coordinates.
The browser stores up to four searched-area station snapshots, favourites, and an anonymous reporting identifier. Area keys round coordinates to two decimals. The browser’s HTTP cache may also keep recent API answers, whose URLs contain the searched coordinates. Last-returned device position is held in memory for this session. Clear browser data in the map’s Privacy panel.
When a connection drops, cached station details remain readable. Tiles are not downloaded for offline use. Unconfirmed report attempts keep an idempotency key; they are only retried when you choose to submit, never silently sent in the background.
A report contains the station ID, fuel grade, price and random identifiers. The service timestamps it. Reports are unverified public observations; no account is required. Report only the price you actually saw, without personal information.
Nearby-search URLs contain coordinates. Automatic Worker invocation logs and tracing are disabled. Hosting and map providers may still receive ordinary network metadata. Complete data-flow notice
"},{"id":"hosting","title":"Cloudflare hosting","group":"Operate","description":"Cloudflare Workers, static assets and D1, without a paid fuel feed.","body":"Cloudflare Workers serves the website, API and static files. The site build writes the bundled OpenStreetMap station snapshot as one static file per 0.5° area, which the Worker reads for nearby searches; city search uses the bundled GeoNames list. Lookups do not depend on a paid geocoder or a runtime Overpass query. D1 stores current prices (read as one row per area), community reports and a daily usage count; its copy of the stations only validates reports. A stations request makes at most one D1 query for prices; now and then a Worker instance also adds its usage to the daily budget table after responding.
The base map comes from OpenFreeMap’s free public service, which is donation-funded with no availability guarantee. OpenStreetMap’s tile servers, used when WebGL is missing or OpenFreeMap refuses, have a best-effort usage policy. Both are separate from Cloudflare. No commercial live pump-price feed is connected.
Cloudflare costs depend on the account’s plan and actual usage. The Worker keeps its own daily D1 budget below the Workers Free limits. Once it is spent, the API answers HTTP 503 spending_cap until midnight UTC, and the website and Android app keep saved prices on screen under a notice. Donate links are optional settings. Running costs, limits and donations
npm install\nnpm run devFollow the root README for current migration and station-import commands. The local database is separate from hosted D1. Use local D1 for test price submissions.
Set your own Worker name, account ID, D1 binding and domain in wrangler.jsonc. Credentials remain in your development environment. Apply D1 migrations with npm run db:remote, and seed a changed station snapshot with npm run db:seed:remote, before npm run deploy. Build the mobile APK separately, then build the site to include it in the download folder. The source archive contains the monorepo, not private local credentials or databases.
The web app uses same-origin /api/v1. Its public configuration and source download contain no database passwords. Android compiles a public HTTPS API endpoint, Expo reads EXPO_PUBLIC_API_URL and iOS uses its public Xcode configuration. Any setting shipped to a browser or mobile binary is inspectable.
Donate links are optional; without one no donate link appears. Set OPENFUEL_PUBLIC_DONATE_URL in .env before building the website, OPENFUEL_DONATE_URL as an Android Gradle property or environment variable, or EXPO_PUBLIC_DONATE_URL for Expo. Use an HTTPS URL; the website and Android builds reject anything else.
The root Wrangler configuration binds D1 as DB, the static site as ASSETS (the Worker also reads the station files through it) and the report limiter as REPORT_LIMITER. Worker variables set the daily D1 budget, D1_DAILY_READ_BUDGET (default 4,000,000 rows read) and D1_DAILY_WRITE_BUDGET (default 80,000 rows written), and the donate link in the limit answer, OPENFUEL_DONATE_URL. Cloudflare account authorization stays in your development environment, and D1 access runs only inside the Worker. Browsers and apps never receive an account token.
npm run dev uses a local database. npm run db:remote applies migrations to the hosted database. A successful local test does not change the hosted deployment.
Supabase, PostgreSQL and migration-environment examples remain for the retained registry foundation. They are not required credentials for the current D1 prototype.
"},{"id":"migrations","title":"Database migrations","group":"Operate","description":"One versioned schema path; local checks, staged rollout and explicitly approved production changes.","body":"The working app uses a Cloudflare Worker, static station files and D1 for real station locations and unverified community prices; its D1 migrations are in services/live/migrations/. PostgreSQL/PostGIS and Supabase material below describes the retained registry foundation, not a prerequisite for this prototype.
Only supabase/migrations is active. The old registry SQL is historical provenance. Keep source imports, private evidence, accepted audit events and schema migrations distinct.
supabase start\nsupabase migration new add_station_access_details\n# Edit the new migration; then rebuild LOCAL development only:\nsupabase db reset --local\nsupabase db lint --local --level warning\nsupabase test dbpython3 tools/database.py plan --target staging\npython3 tools/database.py apply --target staging --confirm YOUR_EXACT_STAGING_PROJECT_REF\n# After review, same migration history to production with explicit confirmation.Protect the production GitHub Environment with required reviewers. Choose one migration deployer, never an automatic second integration. No migration runs inside a website build, phone launch or ordinary API request.
Add first, backfill in bounded batches, update compatible servers/clients, then remove old fields after a support window. Test real restore points, private storage backups and RLS. No remote reset, automatic sample seed or destructive rollback shortcut.
Execution status: SQL and 20 pgTAP checks are written but have not run against PostgreSQL here.
Full migration and maintenance runbook
"},{"id":"licence","title":"Licence & contributions","group":"Project","description":"AGPL-3.0-only for first-party code; data and third-party rights remain separate.","body":"The requested first-party code and documentation licence is AGPL-3.0-only. The full unmodified text is in the root LICENSE. Real OpenStreetMap station data is ODbL. GeoNames city search data is CC BY 4.0. Leaflet is BSD-2-Clause, MapLibre GL JS is BSD-3-Clause and its Leaflet binding is ISC. The map style is a fork of OpenFreeMap Liberty: its code is BSD-3-Clause and its design CC BY 4.0. Original historical fictional fixtures/map retain CC0. Logos, dependency assets and imported datasets are not relicensed by our code licence.
Read the full AGPL licence · Read the notices
\nEarlier uploaded copies used MPL for client code and AGPL-or-later for some services. Their original scope notes are retained. Those past grants to recipients are not retroactively revoked. This source merge claims no authority over third-party marks or other owners’ artwork.
\nChange the canonical component, update its tests and relevant documentation, and run the root checks. A PR can include website, native and contract changes without producing separate ZIP forks. Submit only work you may contribute under the project terms.
Download the source repository
"},{"id":"github","title":"GitHub & release workflow","group":"Project","description":"One public-source monorepo with independent application builds.","body":"The project keeps web, native mobile, Expo, API, database migrations and documentation in one repository. Use the root README for the canonical GitHub URL and current release status. The site also offers a complete source archive.
Fork the repository, work in the relevant app or service, and include the checks that exercise your change. Use local D1 for report tests; never fill the public database with test pump prices. Do not create nested Git repositories inside the apps.
Native APK and iOS build workflows are separate from the web deployment. A workflow is not evidence of a successful run; check executed logs. Debug Android downloads are development builds and do not imply a Play Store release. iPhone signing and App Store distribution require a separate release process.
Before a public push, scan every Git ref and the generated source archive. The repository includes a pinned Gitleaks workflow with only exact test/type-annotation exceptions. Initial publication audit and its limits
"}]; +window.OPENFUEL_PAGES=[{"id":"start","title":"Get started","group":"Start here","description":"Open the real station map, install Android, or run the Expo project.","body":"OpenFuel is an open-source fuel map with a working web app, native Android app, React Native Expo project and SwiftUI source. The shared Cloudflare database contains real OpenStreetMap station locations.
Open the app Download Android APK
Allow location to find stations near you, or search a Canadian city. Prices are blank until someone reports what they actually saw at the pump. Community reports are public and unverified. Station and price coverage may be incomplete.
npm install\nnpm run devThe local development database stays on your computer. Follow the root README for station data import and mobile build commands.
apps/web/ Website + real station web app\napps/docs/ Handbook UI and content\napps/android/ Kotlin / Jetpack Compose\napps/expo/ React Native / Expo Go\napps/ios/ SwiftUI + Foundation core + XcodeGen\nservices/live/ Current Cloudflare Worker + D1\nservices/edge/ Earlier Worker references\nservices/api/ Earlier FastAPI / SQLite reference\nservices/registry/ Review model and PostgreSQL draft\npackages/ Shared contracts, data and design assets\ntools/ Build, import and verification commands\n.github/workflows/ CI and native build jobsEach platform keeps its own build system and shares the public station API. One change can update the API, website and mobile clients together. Do not create nested Git repositories in the apps.
The earlier synthetic fixtures and interface studies are retained as historical design and test resources. The live web route reads real station data and rejects a sample API response.
"},{"id":"website","title":"Website & documentation","group":"Build","description":"A real Leaflet map, browser location and Canadian city search.","body":"The landing page is in apps/web/. The working map is in apps/web/preview/. Documentation content is apps/docs/pages.json; the build generates pages.js.
npm run build\nnpm run devThe web app and API share an origin. A plain static server can render the shell but needs the API for city search and station lookup. Website /, map /preview/ and handbook /docs/ ship together, with the station snapshot as static files under /data/stations/ for the Worker.
To show donate links, set OPENFUEL_PUBLIC_DONATE_URL (HTTPS) in .env before building. Without it no donate link appears.
On entry, the browser asks for location. The map shows the returned device coordinates and accuracy. If location is denied or unavailable, search a Canadian city, enter latitude and longitude, or move the map and choose Search this area. The app never substitutes a fictional current location.
Leaflet 1.9.4 and MapLibre GL JS 5.24.0 are bundled locally; MapLibre loads when the base map starts. The base map is OpenFreeMap vector tiles drawn in OpenFuel’s style from packages/map-style. Without WebGL, or if OpenFreeMap refuses its tiles, OpenStreetMap raster tiles are used instead. Tiles load for the viewed area with visible attribution and normal browser caching. No bulk download or offline tile feature is provided.
If OpenFuel’s database reaches its free daily limit, the map keeps saved prices on screen under a notice until live prices return after midnight UTC.
"},{"id":"android","title":"Android development","group":"Build","description":"Install the native APK or develop with React Native and Expo Go.","body":"This is a development APK, not a Play Store release. Android may ask you to allow installation from your browser. Allow location in the app, or use a manual area. Real station coordinates are shared with the web app; missing prices stay unknown until reported.
The apps/expo/ project provides a React Native implementation for Expo Go. Follow its README to install dependencies, start Metro and open the project on your phone. Your phone must be able to reach the development server. Expo source and the compiled native Android APK are separate deliverables.
The Kotlin / Jetpack Compose project lives in apps/android/. Use its Gradle wrapper and README for build and device commands. The public API URL is safe to ship in the app; account credentials and signing secrets are not.
Check the root README and evidence files for the exact APK build and emulator runs. An emulator test does not replace testing location and navigation on your own phone.
"},{"id":"ios","title":"iOS development","group":"Build","description":"SwiftUI, MapKit and the current live station API; a Mac is required for Apple SDK and device verification.","body":"The active app uses MapKit, foreground CoreLocation, Canadian city search and the current Cloudflare API. Stations without reported prices remain visible. Lists and map pins use direct remote brand logos with initials as a fallback. A compact control row and fully hideable results sheet preserve map space.
OpenFuelCore validates live station responses, report receipts and cached areas. The last approximate area loads before a fresh location or network request completes. Earlier sample fixtures remain separate historical tests.
swift test --package-path apps/ios/OpenFuelCore\n# On a Mac with Xcode + XcodeGen:\npython3 tools/project.py ios-buildXcodeGen reads apps/ios/project.yml, including public xcconfig inputs and the UI-test target. No signing credentials are embedded. Follow apps/ios/README.md when Xcode is available.
The portable Swift tests and read-only live API checks pass on Linux. SwiftUI files passed syntax parsing. Apple SDK compilation, MapKit rendering, permission dialogs, iPhone layout and a signed IPA still require macOS/Xcode; these have not been verified.
Current build status · Xcode configuration
"},{"id":"api","title":"API & contracts","group":"Build","description":"Nearby real stations, Canadian city search and public unverified reports.","body":"| Endpoint | Use |
|---|---|
GET /api/v1/health | Service and database health |
GET /api/v1/stations?lat=53.54&lon=-113.49&radius=10000&fuel=regular | Nearby real stations; radius is metres |
GET /api/v1/geocode?q=Edmonton | Canadian city search |
GET /api/v1/regions | Snapshot coverage and attribution |
POST /api/v1/reports | A price actually observed at a station |
Live responses identify mode: live and is_demo: false. Station IDs have the form osm-node-123 or osm-way-123. Prices are nullable integer thousandths of CAD per litre: a value of 1499 means $1.499/L, displayed as 149.9 ¢/L. This is a unit example, not a reported pump price.
Station locations, city search and regions come from the bundled snapshot; D1 holds current prices and reports. Station answers carry Cache-Control: private, max-age=15, city search public, max-age=86400, regions public, max-age=3600 and health no-store. Prices can be about 15 seconds behind a new report on other Worker instances.
A request contains station_id, fuel_type, price_milli, a random client_id and a unique request_id. Reuse the same request ID when retrying an unconfirmed submission. Only show a report as accepted after the service confirms its ID, station, fuel and price. Rate limits and validation apply.
When OpenFuel’s daily database budget is spent, the API answers HTTP 503 with {\"error\":\"spending_cap\",\"reason\":…,\"scope\":\"all\"|\"reports\",\"resets_at\":…,\"message\":…,\"donate_url\":…} until midnight UTC. scope: all pauses database reads: searches still answer for areas whose prices the Worker already holds. scope: reports pauses new reports only. When Cloudflare’s own daily request limit is reached, Cloudflare answers HTTP 429 with error 1027: an HTML page, or JSON with error_code 1027 and error_name workers_daily_limit when the client sends Accept: application/json. Treat either like scope: \"all\" until midnight UTC and keep saved stations on screen. Other Cloudflare 429s, such as 1015 rate limiting, are not the daily limit.
Reports are public, anonymous and unverified. Only submit prices actually checked at that station. Run integration tests against local D1; never seed made-up pump prices into the public database.
The FastAPI/SQLite service and PostgreSQL/PostGIS registry drafts remain as earlier reference work. They are separate from the deployed Cloudflare API.
Current live API contract · OpenAPI JSON
"},{"id":"parity","title":"Native visual parity","group":"Build","description":"Historical design references and honest native verification boundaries.","body":"The current web app, Kotlin Android app and Expo project use real station coordinates. The earlier six-station fixture and illustrated map remain historical design/test resources. SwiftUI source now uses the live API and MapKit; Apple SDK compilation and iPhone verification remain outstanding.
Browser screenshots verify browser rendering. Native screenshots must come from the Android app or iOS app being evaluated. JavaScript export proves bundling, not Expo device behavior. Do not claim pixel parity or an iPhone build from shared source alone.
Review map interaction, location permission denial, missing-price stations, reporting, cache age, keyboard behavior and large text on the intended device.
Current build status · Historical visual acceptance requirements
"},{"id":"state","title":"Station lifecycle","group":"Data & community","description":"Additions, corrections and closures stay separate from a raw vote count.","body":"The working app uses a Cloudflare Worker, static station files and D1 for real station locations and unverified community prices. PostgreSQL/PostGIS and Supabase material below describes the retained registry foundation, not a prerequisite for this prototype.
The tested model lives in services/registry/policy.py. Three proposal-scoped attestations raise triage priority; they do not publish a station. New records need checked evidence and review. Permanent closure requires two distinct reviewer inputs.
The production service still needs actual authorization, source verification, coordinated-abuse resistance and prevention of self-review. The model is not a deployed moderation API.
A status change or reopening retains history and version checks. Old prices do not mean a station is closed. Nearby records are duplicate candidates, not automatic merges. Reviewed changes append public history; private reviewer/attester details are not exported.
The included schema is an unexecuted PostgreSQL/PostGIS draft. It is not the database currently running under the reference API. Test the schema, transaction paths and permissions before wiring either native app to it.
Read docs/reference/DATABASE_AND_STATION_LIFECYCLE.md in the source for the detailed original proposal. Imported OSM data, brand artwork and source code have separate licence obligations.
OpenFuel imports Canadian fuel-station locations from OpenStreetMap. Records can have missing addresses, names or amenities. Their provenance and import date are recorded with the dataset. OpenStreetMap data is available under ODbL and city names from GeoNames under CC BY 4.0.
The website and Android app draw OpenFreeMap vector tiles with MapLibre inside a Leaflet map, in OpenFuel’s own style: a fork of OpenFreeMap Liberty recoloured after CARTO Voyager. No map key or account is needed. Without WebGL, or if OpenFreeMap refuses its tiles, the map uses OpenStreetMap’s standard raster tiles. Expo uses those raster tiles, and the SwiftUI app uses MapKit.
On the website the credit reads “OpenFreeMap © OpenMapTiles · Style after CARTO Voyager · Data © OpenStreetMap contributors” and stays visible on desktop and mobile. The browser sends its normal user agent and an origin referrer, respects HTTP caching, and requests only tiles for the viewed map. There is no area-download feature.
OpenFreeMap · OpenStreetMap tile policy · OSM licence · GeoNames
Google Maps and Apple Maps are only used for directions; their links contain the actual selected station coordinates. The destination app handles origin location and route calculation. Straight-line distances in OpenFuel are not road distances or journey times.
The repository retains fictional map artwork and sample fixture sets for the earlier design study. They are not used as live station locations or current prices. Third-party brand logos are not bundled into the new web map.
"},{"id":"testing","title":"Build evidence","group":"Operate","description":"Executed checks, explicit unexecuted platform gates, and logs—not inferred release readiness.","body":"python3 tools/project.py check --native-cores --web\nnpm test\npython3 tools/generate_mobile.py --checkXcode/SwiftUI compilation, iPhone simulator screenshots, real-device handoff and the retained PostgreSQL/pgTAP migration path. Android and Cloudflare prototype checks are recorded in the executed output above. A workflow file is not a successful run, and the real map requires actual imported station records, valid coordinates and a working API. Test location coordinates used in browser/emulator checks are explicitly injected for reproducibility, not the operator’s physical location.
The visual gate fails when approved real native screenshots are missing. Native parity · Database checks
"},{"id":"privacy","title":"Privacy & source boundaries","group":"Operate","description":"One-shot location permission, public reports and device-local saved areas.","body":"The web app requests a one-shot device location on entry. Your browser owns the permission decision. It displays the returned coordinates and accuracy; denial leaves city search and map exploration available. Coordinates go to OpenFuel to query nearby stations. The application does not request background location or track journeys.
Cloudflare serves the website and public API. OpenFreeMap receives requests for the viewed map area (OpenStreetMap's tile servers if WebGL or OpenFreeMap is unavailable), including normal IP/browser metadata and the site origin. Canadian city search uses a GeoNames index through the OpenFuel API. Choosing directions opens your map provider with the selected station coordinates.
The browser stores up to four searched-area station snapshots, favourites, and an anonymous reporting identifier. Area keys round coordinates to two decimals. The browser’s HTTP cache may also keep recent API answers, whose URLs contain the searched coordinates. Last-returned device position is held in memory for this session. Clear browser data in the map’s Privacy panel.
When a connection drops, cached station details remain readable. Tiles are not downloaded for offline use. Unconfirmed report attempts keep an idempotency key; they are only retried when you choose to submit, never silently sent in the background.
A report contains the station ID, fuel grade, price and random identifiers. The service timestamps it. Reports are unverified public observations; no account is required. Report only the price you actually saw, without personal information.
Nearby-search URLs contain coordinates. Automatic Worker invocation logs and tracing are disabled. Hosting and map providers may still receive ordinary network metadata. Complete data-flow notice
"},{"id":"hosting","title":"Cloudflare hosting","group":"Operate","description":"Cloudflare Workers, static assets and D1, without a paid fuel feed.","body":"Cloudflare Workers serves the website, API and static files. The site build writes the bundled OpenStreetMap station snapshot as one static file per 0.5° area, which the Worker reads for nearby searches; city search uses the bundled GeoNames list. Lookups do not depend on a paid geocoder or a runtime Overpass query. D1 stores current prices (read as one row per area), community reports and a daily usage count; its copy of the stations only validates reports. A stations request makes at most one D1 query for prices; now and then a Worker instance also adds its usage to the daily budget table after responding.
The base map comes from OpenFreeMap’s free public service, which is donation-funded with no availability guarantee. OpenStreetMap’s tile servers, used when WebGL is missing or OpenFreeMap refuses, have a best-effort usage policy. Both are separate from Cloudflare. No commercial live pump-price feed is connected.
Cloudflare costs depend on the account’s plan and actual usage. The Worker keeps its own daily D1 budget below the Workers Free limits. Once it is spent, the API answers HTTP 503 spending_cap until midnight UTC, and the website and Android app keep saved prices on screen under a notice. Donate links are optional settings. Running costs, limits and donations
npm install\nnpm run devFollow the root README for current migration and station-import commands. The local database is separate from hosted D1. Use local D1 for test price submissions.
Set your own Worker name, account ID, D1 binding and domain in wrangler.jsonc. Credentials remain in your development environment. Apply D1 migrations with npm run db:remote, and seed a changed station snapshot with npm run db:seed:remote, before npm run deploy. Downloads are GitHub release assets, not part of the site: build the Android APK, run python3 tools/project.py release-assets, and attach the files it collects to a GitHub release. The source archive contains the monorepo, not private local credentials or databases.
The web app uses same-origin /api/v1. Its public configuration and source download contain no database passwords. Android compiles a public HTTPS API endpoint, Expo reads EXPO_PUBLIC_API_URL and iOS uses its public Xcode configuration. Any setting shipped to a browser or mobile binary is inspectable.
Donate links are optional; without one no donate link appears. Set OPENFUEL_PUBLIC_DONATE_URL in .env before building the website, OPENFUEL_DONATE_URL as an Android Gradle property or environment variable, or EXPO_PUBLIC_DONATE_URL for Expo. Use an HTTPS URL; the website and Android builds reject anything else.
The root Wrangler configuration binds D1 as DB, the static site as ASSETS (the Worker also reads the station files through it) and the report limiter as REPORT_LIMITER. Worker variables set the daily D1 budget, D1_DAILY_READ_BUDGET (default 4,000,000 rows read) and D1_DAILY_WRITE_BUDGET (default 80,000 rows written), and the donate link in the limit answer, OPENFUEL_DONATE_URL. Cloudflare account authorization stays in your development environment, and D1 access runs only inside the Worker. Browsers and apps never receive an account token.
npm run dev uses a local database. npm run db:remote applies migrations to the hosted database. A successful local test does not change the hosted deployment.
Supabase, PostgreSQL and migration-environment examples remain for the retained registry foundation. They are not required credentials for the current D1 prototype.
"},{"id":"migrations","title":"Database migrations","group":"Operate","description":"One versioned schema path; local checks, staged rollout and explicitly approved production changes.","body":"The working app uses a Cloudflare Worker, static station files and D1 for real station locations and unverified community prices; its D1 migrations are in services/live/migrations/. PostgreSQL/PostGIS and Supabase material below describes the retained registry foundation, not a prerequisite for this prototype.
Only supabase/migrations is active. The old registry SQL is historical provenance. Keep source imports, private evidence, accepted audit events and schema migrations distinct.
supabase start\nsupabase migration new add_station_access_details\n# Edit the new migration; then rebuild LOCAL development only:\nsupabase db reset --local\nsupabase db lint --local --level warning\nsupabase test dbpython3 tools/database.py plan --target staging\npython3 tools/database.py apply --target staging --confirm YOUR_EXACT_STAGING_PROJECT_REF\n# After review, same migration history to production with explicit confirmation.Protect the production GitHub Environment with required reviewers. Choose one migration deployer, never an automatic second integration. No migration runs inside a website build, phone launch or ordinary API request.
Add first, backfill in bounded batches, update compatible servers/clients, then remove old fields after a support window. Test real restore points, private storage backups and RLS. No remote reset, automatic sample seed or destructive rollback shortcut.
Execution status: SQL and 20 pgTAP checks are written but have not run against PostgreSQL here.
Full migration and maintenance runbook
"},{"id":"licence","title":"Licence & contributions","group":"Project","description":"AGPL-3.0-only for first-party code; data and third-party rights remain separate.","body":"The requested first-party code and documentation licence is AGPL-3.0-only. The full unmodified text is in the root LICENSE. Real OpenStreetMap station data is ODbL. GeoNames city search data is CC BY 4.0. Leaflet is BSD-2-Clause, MapLibre GL JS is BSD-3-Clause and its Leaflet binding is ISC. The map style is a fork of OpenFreeMap Liberty: its code is BSD-3-Clause and its design CC BY 4.0. Original historical fictional fixtures/map retain CC0. Logos, dependency assets and imported datasets are not relicensed by our code licence.
Read the full AGPL licence · Read the notices
\nEarlier uploaded copies used MPL for client code and AGPL-or-later for some services. Their original scope notes are retained. Those past grants to recipients are not retroactively revoked. This source merge claims no authority over third-party marks or other owners’ artwork.
\nChange the canonical component, update its tests and relevant documentation, and run the root checks. A PR can include website, native and contract changes without producing separate ZIP forks. Submit only work you may contribute under the project terms.
Download the source repository
"},{"id":"github","title":"GitHub & release workflow","group":"Project","description":"One public-source monorepo with independent application builds.","body":"The project keeps web, native mobile, Expo, API, database migrations and documentation in one repository. Use the root README for the canonical GitHub URL and current release status. Each GitHub release includes the Android APK and a complete source archive.
Fork the repository, work in the relevant app or service, and include the checks that exercise your change. Use local D1 for report tests; never fill the public database with test pump prices. Do not create nested Git repositories inside the apps.
Native APK and iOS build workflows are separate from the web deployment. A workflow is not evidence of a successful run; check executed logs. Debug Android downloads are development builds and do not imply a Play Store release. iPhone signing and App Store distribution require a separate release process.
Before a public push, scan every Git ref and the generated source archive. The repository includes a pinned Gitleaks workflow with only exact test/type-annotation exceptions. Initial publication audit and its limits
"}]; diff --git a/apps/docs/pages.json b/apps/docs/pages.json index db42996..0a29487 100644 --- a/apps/docs/pages.json +++ b/apps/docs/pages.json @@ -4,7 +4,7 @@ "title": "Get started", "group": "Start here", "description": "Open the real station map, install Android, or run the Expo project.", - "body": "OpenFuel is an open-source fuel map with a working web app, native Android app, React Native Expo project and SwiftUI source. The shared Cloudflare database contains real OpenStreetMap station locations.
Open the app Download Android APK
Allow location to find stations near you, or search a Canadian city. Prices are blank until someone reports what they actually saw at the pump. Community reports are public and unverified. Station and price coverage may be incomplete.
npm install\nnpm run devThe local development database stays on your computer. Follow the root README for station data import and mobile build commands.
OpenFuel is an open-source fuel map with a working web app, native Android app, React Native Expo project and SwiftUI source. The shared Cloudflare database contains real OpenStreetMap station locations.
Open the app Download Android APK
Allow location to find stations near you, or search a Canadian city. Prices are blank until someone reports what they actually saw at the pump. Community reports are public and unverified. Station and price coverage may be incomplete.
npm install\nnpm run devThe local development database stays on your computer. Follow the root README for station data import and mobile build commands.
This is a development APK, not a Play Store release. Android may ask you to allow installation from your browser. Allow location in the app, or use a manual area. Real station coordinates are shared with the web app; missing prices stay unknown until reported.
The apps/expo/ project provides a React Native implementation for Expo Go. Follow its README to install dependencies, start Metro and open the project on your phone. Your phone must be able to reach the development server. Expo source and the compiled native Android APK are separate deliverables.
The Kotlin / Jetpack Compose project lives in apps/android/. Use its Gradle wrapper and README for build and device commands. The public API URL is safe to ship in the app; account credentials and signing secrets are not.
Check the root README and evidence files for the exact APK build and emulator runs. An emulator test does not replace testing location and navigation on your own phone.
" + "body": "This is a development APK, not a Play Store release. Android may ask you to allow installation from your browser. Allow location in the app, or use a manual area. Real station coordinates are shared with the web app; missing prices stay unknown until reported.
The apps/expo/ project provides a React Native implementation for Expo Go. Follow its README to install dependencies, start Metro and open the project on your phone. Your phone must be able to reach the development server. Expo source and the compiled native Android APK are separate deliverables.
The Kotlin / Jetpack Compose project lives in apps/android/. Use its Gradle wrapper and README for build and device commands. The public API URL is safe to ship in the app; account credentials and signing secrets are not.
Check the root README and evidence files for the exact APK build and emulator runs. An emulator test does not replace testing location and navigation on your own phone.
" }, { "id": "ios", @@ -81,7 +81,7 @@ "title": "Cloudflare hosting", "group": "Operate", "description": "Cloudflare Workers, static assets and D1, without a paid fuel feed.", - "body": "Cloudflare Workers serves the website, API and static files. The site build writes the bundled OpenStreetMap station snapshot as one static file per 0.5° area, which the Worker reads for nearby searches; city search uses the bundled GeoNames list. Lookups do not depend on a paid geocoder or a runtime Overpass query. D1 stores current prices (read as one row per area), community reports and a daily usage count; its copy of the stations only validates reports. A stations request makes at most one D1 query for prices; now and then a Worker instance also adds its usage to the daily budget table after responding.
The base map comes from OpenFreeMap’s free public service, which is donation-funded with no availability guarantee. OpenStreetMap’s tile servers, used when WebGL is missing or OpenFreeMap refuses, have a best-effort usage policy. Both are separate from Cloudflare. No commercial live pump-price feed is connected.
Cloudflare costs depend on the account’s plan and actual usage. The Worker keeps its own daily D1 budget below the Workers Free limits. Once it is spent, the API answers HTTP 503 spending_cap until midnight UTC, and the website and Android app keep saved prices on screen under a notice. Donate links are optional settings. Running costs, limits and donations
npm install\nnpm run devFollow the root README for current migration and station-import commands. The local database is separate from hosted D1. Use local D1 for test price submissions.
Set your own Worker name, account ID, D1 binding and domain in wrangler.jsonc. Credentials remain in your development environment. Apply D1 migrations with npm run db:remote, and seed a changed station snapshot with npm run db:seed:remote, before npm run deploy. Build the mobile APK separately, then build the site to include it in the download folder. The source archive contains the monorepo, not private local credentials or databases.
Cloudflare Workers serves the website, API and static files. The site build writes the bundled OpenStreetMap station snapshot as one static file per 0.5° area, which the Worker reads for nearby searches; city search uses the bundled GeoNames list. Lookups do not depend on a paid geocoder or a runtime Overpass query. D1 stores current prices (read as one row per area), community reports and a daily usage count; its copy of the stations only validates reports. A stations request makes at most one D1 query for prices; now and then a Worker instance also adds its usage to the daily budget table after responding.
The base map comes from OpenFreeMap’s free public service, which is donation-funded with no availability guarantee. OpenStreetMap’s tile servers, used when WebGL is missing or OpenFreeMap refuses, have a best-effort usage policy. Both are separate from Cloudflare. No commercial live pump-price feed is connected.
Cloudflare costs depend on the account’s plan and actual usage. The Worker keeps its own daily D1 budget below the Workers Free limits. Once it is spent, the API answers HTTP 503 spending_cap until midnight UTC, and the website and Android app keep saved prices on screen under a notice. Donate links are optional settings. Running costs, limits and donations
npm install\nnpm run devFollow the root README for current migration and station-import commands. The local database is separate from hosted D1. Use local D1 for test price submissions.
Set your own Worker name, account ID, D1 binding and domain in wrangler.jsonc. Credentials remain in your development environment. Apply D1 migrations with npm run db:remote, and seed a changed station snapshot with npm run db:seed:remote, before npm run deploy. Downloads are GitHub release assets, not part of the site: build the Android APK, run python3 tools/project.py release-assets, and attach the files it collects to a GitHub release. The source archive contains the monorepo, not private local credentials or databases.
The requested first-party code and documentation licence is AGPL-3.0-only. The full unmodified text is in the root LICENSE. Real OpenStreetMap station data is ODbL. GeoNames city search data is CC BY 4.0. Leaflet is BSD-2-Clause, MapLibre GL JS is BSD-3-Clause and its Leaflet binding is ISC. The map style is a fork of OpenFreeMap Liberty: its code is BSD-3-Clause and its design CC BY 4.0. Original historical fictional fixtures/map retain CC0. Logos, dependency assets and imported datasets are not relicensed by our code licence.
Read the full AGPL licence · Read the notices
\nEarlier uploaded copies used MPL for client code and AGPL-or-later for some services. Their original scope notes are retained. Those past grants to recipients are not retroactively revoked. This source merge claims no authority over third-party marks or other owners’ artwork.
\nChange the canonical component, update its tests and relevant documentation, and run the root checks. A PR can include website, native and contract changes without producing separate ZIP forks. Submit only work you may contribute under the project terms.
Download the source repository
" + "body": "The requested first-party code and documentation licence is AGPL-3.0-only. The full unmodified text is in the root LICENSE. Real OpenStreetMap station data is ODbL. GeoNames city search data is CC BY 4.0. Leaflet is BSD-2-Clause, MapLibre GL JS is BSD-3-Clause and its Leaflet binding is ISC. The map style is a fork of OpenFreeMap Liberty: its code is BSD-3-Clause and its design CC BY 4.0. Original historical fictional fixtures/map retain CC0. Logos, dependency assets and imported datasets are not relicensed by our code licence.
Read the full AGPL licence · Read the notices
\nEarlier uploaded copies used MPL for client code and AGPL-or-later for some services. Their original scope notes are retained. Those past grants to recipients are not retroactively revoked. This source merge claims no authority over third-party marks or other owners’ artwork.
\nChange the canonical component, update its tests and relevant documentation, and run the root checks. A PR can include website, native and contract changes without producing separate ZIP forks. Submit only work you may contribute under the project terms.
Download the source repository
" }, { "id": "github", "title": "GitHub & release workflow", "group": "Project", "description": "One public-source monorepo with independent application builds.", - "body": "The project keeps web, native mobile, Expo, API, database migrations and documentation in one repository. Use the root README for the canonical GitHub URL and current release status. The site also offers a complete source archive.
Fork the repository, work in the relevant app or service, and include the checks that exercise your change. Use local D1 for report tests; never fill the public database with test pump prices. Do not create nested Git repositories inside the apps.
Native APK and iOS build workflows are separate from the web deployment. A workflow is not evidence of a successful run; check executed logs. Debug Android downloads are development builds and do not imply a Play Store release. iPhone signing and App Store distribution require a separate release process.
Before a public push, scan every Git ref and the generated source archive. The repository includes a pinned Gitleaks workflow with only exact test/type-annotation exceptions. Initial publication audit and its limits
" + "body": "The project keeps web, native mobile, Expo, API, database migrations and documentation in one repository. Use the root README for the canonical GitHub URL and current release status. Each GitHub release includes the Android APK and a complete source archive.
Fork the repository, work in the relevant app or service, and include the checks that exercise your change. Use local D1 for report tests; never fill the public database with test pump prices. Do not create nested Git repositories inside the apps.
Native APK and iOS build workflows are separate from the web deployment. A workflow is not evidence of a successful run; check executed logs. Debug Android downloads are development builds and do not imply a Play Store release. iPhone signing and App Store distribution require a separate release process.
Before a public push, scan every Git ref and the generated source archive. The repository includes a pinned Gitleaks workflow with only exact test/type-annotation exceptions. Initial publication audit and its limits
" } ] diff --git a/apps/web/_headers b/apps/web/_headers index c82d5db..253413d 100644 --- a/apps/web/_headers +++ b/apps/web/_headers @@ -7,8 +7,3 @@ Cache-Control: no-store /preview/sw.js Cache-Control: no-cache -/downloads/* - Cache-Control: public, max-age=300 -/downloads/openfuel-android.apk - Content-Type: application/vnd.android.package-archive - Content-Disposition: attachment; filename="openfuel-android.apk" diff --git a/apps/web/designs/variant-b/index.html b/apps/web/designs/variant-b/index.html index f50fffe..1468b00 100644 --- a/apps/web/designs/variant-b/index.html +++ b/apps/web/designs/variant-b/index.html @@ -5,7 +5,7 @@ Accountable everywhere.The product is simple. The commitments behind it should be just as clear.
Prices, freshness and a clear next step. No account wall in the preview.
The native prototype requests no location or background-driving permissions. Maps opens only when you choose it.
Public exports and independently runnable code are the plan—not an exclusive database tied to one company.
No mystery scores. No invisible corrections. A station record with a source, a status and a history.
| Station | Fuel | CAD ¢/L | Record status |
|---|---|---|---|
| Petro-Canada | Regular | 142.9 | Synthetic example |
| Shell | Regular | 147.9 | Synthetic example |
| Esso | Regular | 149.9 | Synthetic example |
Native Android and iPhone clients, one shared sample database. Start on Android or build the SwiftUI source with Xcode.
The ambition is national. The next step is a carefully tested local launch.
The six stations and map are fictional, so these are not real pump prices. Reports you share are stored online and visible in the web and native prototypes. Real coverage and licensed data feeds still need to be added.
Yes. The Android prototype uses Kotlin and Jetpack Compose and is available as a downloadable APK. The iPhone app uses Swift and SwiftUI; its source is included, and building it requires a Mac with Xcode.
The proposed model lets people suggest additions, edits and closures. Evidence is reviewed before changes reach the public map. A vote count alone does not delete a station.
Download the full repository: website, Android and SwiftUI apps, Cloudflare API, D1 database migrations and tests. A public GitHub repository has not been published yet.
Start with the map. Help shape what comes next.
Open the appNative Android and iPhone clients, one shared sample database. Start on Android or build the SwiftUI source with Xcode.
The ambition is national. The next step is a carefully tested local launch.
The six stations and map are fictional, so these are not real pump prices. Reports you share are stored online and visible in the web and native prototypes. Real coverage and licensed data feeds still need to be added.
Yes. The Android prototype uses Kotlin and Jetpack Compose and is available as a downloadable APK. The iPhone app uses Swift and SwiftUI; its source is included, and building it requires a Mac with Xcode.
The proposed model lets people suggest additions, edits and closures. Evidence is reviewed before changes reach the public map. A vote count alone does not delete a station.
Download the full repository: website, Android and SwiftUI apps, Cloudflare API, D1 database migrations and tests. A public GitHub repository has not been published yet.
Start with the map. Help shape what comes next.
Open the app