All projects
In Progress · since 2026 ·
react nativeexposqlitedrizzle

Velodok

A digital ID for your bicycles - an offline-first replacement for a cancelled government bike registry.


Velodok

A digital ID for your bicycles.

Velodok is an unofficial replacement for a cancelled government app that was meant to help you register your bike and prove ownership in case of theft. It keeps the full record of every bike you own - frame number, photos, receipts, components - on your phone, so that when you need it, you have it. No account, no cloud, no waiting for a public service that never shipped.


What it is

Velodok is a bike registry that lives on your phone. You add each bike once, in a five-step form, and it stores the things a police report or an insurance claim will actually ask for:

  • Identity - name, type, brand, model, year, size, colour, and the two numbers that matter: the frame number and the police registration number.
  • Purchase - date, price, currency, dealer, insured value, weight.
  • Components - a per-part list covering 19 component types, from frame and fork down to handlebar tape and bottom bracket, each with its own brand, model, price, weight and purchase date.
  • Photos and documents - an overview shot, detail photos, a dedicated frame-number photo, and the purchase receipt. Taken with the camera or picked from the gallery, viewable full-screen.
  • Notes - anything that doesn’t fit a field.

It’s German-language, Material Design, and works with the phone in flight mode. There is no sign-up step, because there is nothing to sign up to.


Why it exists

Bike theft is a paperwork problem as much as a crime problem. The police want a frame number. The insurer wants a receipt and proof the bike was yours. Almost nobody has either to hand, because that information lives on a sticker in a drawer, in an email from three years ago, and in a photo you didn’t take.

A government app was supposed to solve exactly this - a national bike registry you could point at after a theft. It was cancelled. The need didn’t go away with it.

Velodok is the version that exists:

  • Prepared, not reactive. The five minutes you spend adding a bike happen while you still own it. That’s the whole point.
  • Yours, on your device. Everything is in a local SQLite database and the phone’s own filesystem. No account, no server, nothing to leak, nothing to shut down. A registry that can be cancelled a second time isn’t much of a registry.
  • Detailed enough to be evidence. A frame number and a photo of it. A receipt. A component list that distinguishes your bike from every other black gravel bike on the rack.

Core features

FeatureWhat it does
🚲 Multiple bikesEvery bike is a card on the home screen with its cover photo. 11 types covered - road, MTB, gravel, e-bike, city, trekking, fixie, full-suspension, folding, cargo, other.
🔢 The numbers that matterDedicated fields for frame number and police registration number, plus a dedicated photo category for the frame number itself.
🧩 Component list19 component types per bike, each with brand, model, price, weight, purchase date and notes. Added through a bottom sheet, so it doesn’t interrupt the form.
📸 Photos & receiptsFour categories - cover, detail, frame number, receipt. Camera or gallery, stored on-device, viewable full-screen.
🧾 Purchase recordDate, price, currency, dealer, insured value and weight - the fields an insurance claim asks for.
🪜 Five-step entryGrunddaten → Kauf → Komponenten → Fotos → Notizen, with a progress bar. A bike has too many fields for one scroll.
🌗 Dark modeFollows the system theme, applied through Material Design 3 across the app and the Android navigation bar.
✈️ Fully offlineNo network code at all. The app has never made a request and doesn’t need permission to.

Vision

The local app is the product, and it stays usable without an account forever. But a registry you can only read on the phone in your pocket has an obvious limit - it’s the one device a thief might also have taken. The direction:

  • Optional accounts and cloud sync. Opt-in, never required. Bikes and media sync so a lost or stolen phone doesn’t take the evidence with it.
  • Read-only share links with a QR code. A single link you can hand to the police or an insurer - printable, no app needed on their end - with a configurable expiry.
  • PDF export for insurance paperwork, generated from the record you already have.
  • French and Italian alongside German, to actually cover the countries this is aimed at.

Beyond that, Velodok stays deliberately narrow. It’s a digital ID - it proves the bike is yours. Service history and maintenance tracking are a different job, which is what Velobase is for.


Technical details

Stack

LayerChoice
RuntimeExpo SDK 55 (managed), React Native 0.83, React 19.2
LanguageTypeScript
NavigationExpo Router - file-based, typed routes
UIReact Native Paper (Material Design 3) + @expo/ui
StylingNativeWind 5 + Tailwind v4
Databaseexpo-sqlite (on-device only, WAL mode)
ORMDrizzle ORM + drizzle-kit, committed migrations
Mediaexpo-image-picker, expo-image-manipulator, expo-file-system, expo-image
Sheets@gorhom/bottom-sheet
Animationreact-native-reanimated 4 + worklets
Local KVreact-native-mmkv
Releasesrelease-please + GitHub Actions → EAS local build → APK on the release

Engineering decisions

  • No network layer, on purpose. There is no API client, no auth code and no sync engine in the app - not stubbed, not disabled, absent. Everything reads and writes local SQLite. That’s what makes “works offline” a property of the architecture rather than a feature that can regress.
  • The schema dropped its sync bookkeeping. An earlier design carried local_id / server_id / is_dirty / is_deleted on every table for a sync layer that hadn’t been built. The shipped schema uses a plain UUID primary key instead. Carrying the cost of a distributed-systems design for a single-device app is a tax with no payer; it can be reintroduced alongside the sync layer that justifies it.
  • Media is filesystem, never blob. The database stores a local_path per image; the bytes live in the app’s own directory via expo-file-system. The SQLite file stays small enough to stay fast, and photos are handed straight to expo-image without a round trip through the DB.
  • Deletion is enforced by the database. PRAGMA foreign_keys = ON at connection time, with onDelete: "cascade" from bikes to both components and media. Removing a bike can’t leave orphaned rows behind, regardless of what the calling code forgets.
  • WAL from the start. PRAGMA journal_mode = WAL - the reads (list screen, detail screen) and the writes (form submit, photo capture) stop blocking each other, which is what keeps navigation snappy while a photo is being saved.
  • Three variants, three bundle IDs. net.ntrapp.velodok, .dev and .test, each with its own name and accent colour. Development, preview and production builds coexist on one phone, so testing a release candidate doesn’t mean uninstalling the copy holding your actual bikes.
  • A stepper instead of a wall of inputs. Sixteen fields, a component list and a photo picker in one scroll is an abandoned form. Splitting it into five labelled steps with a progress bar means every screen has an obvious end.
  • Releases are fully automated. Conventional commits drive release-please, which opens the release PR and tags the version; publishing the release triggers a local EAS production build in CI that attaches the signed APK. The app version is read from package.json, so the binary can’t disagree with the tag.

Get & use Velodok

Install (Android APK)

Velodok is not on the Play Store, so you install the APK directly:

  1. Download the latest build: Velodok.apk.
  2. Allow installs from your browser or file manager (Settings → Apps → Special access → Install unknown apps).
  3. Open the APK to install. Android will warn you the app isn’t verified - that’s expected for a sideloaded build.

First run

  1. Tap Velo hinzufügen on the empty home screen.
  2. Work through the five steps. The two fields worth not skipping are the frame number and a photo of the frame number - they’re what a police report is built on.
  3. Add the purchase receipt under Fotos while you can still find it.

Build from source

Velodok is a managed Expo app targeting Android. It depends on native modules (SQLite, MMKV, Reanimated), so run it as a development build rather than in Expo Go.

git clone https://github.com/elRatto21/Velodok
cd Velodok
pnpm install

# Start the dev-client bundler
pnpm dev

Schema changes go through Drizzle:

pnpm generate   # drizzle-kit generate

Uses pnpm for all package management.


Velodok - your bike, on the record.