English | Русский
A mobile app that turns the shoebox of fuel receipts and half-remembered service dates into a clean, offline-first car history logbook - every fill-up, repair, oil change and insurance renewal in one place, with reminders before the next one is due and a shareable PDF report of the whole history.
This is a product & architecture write-up of my own project. Source code is not published here.
Three layers, built outward from the driver:
- For the owner - a car logbook (built). Log fuel, service, repairs, painting, insurance; track mileage and spending; get reminded before maintenance is due; export a full PDF history - useful on its own and when selling the car.
- For auto services - a B2B side (planned). With the owner's consent, a shop sees the car's real state, spots upcoming maintenance (oil, timing belt, filters) from mileage and history, and reaches out at the right moment instead of waiting.
- AI care tips (planned). Turn the car's history into personalized upkeep advice - what to check next, based on make, mileage and what has already been done.
A polished Android app (Expo / React Native) with a real backend:
- Garage - multiple cars, one active; rich add-car flow (brand, engine type, transmission, LPG, mileage, VIN, plate, tank).
- History - fuel and service records typed (fuel / service / repair / insurance / oil / wash / tuning / …), grouped by month, filterable, with running totals.
- Reminders - by mileage, date, fuel volume or combined; three priority levels; delivered as local push notifications.
- Analytics - spending breakdown, mileage trend, real fuel consumption and range estimation from full-tank intervals.
- Car profile - photo gallery by category (Supabase Storage), full spec sheet, PDF export, and owner-to-owner transfer.
- Offline-first - works fully as a guest on-device, then syncs to the cloud on sign-in.
React Native 0.81 · Expo ~54 · React 19 · TypeScript · expo-router · Zustand · Supabase (PostgreSQL + Auth + Storage + Row-Level Security) · expo-notifications · expo-print / expo-sharing · expo-image-picker · NativeWind / Tailwind · EAS Build (Android).
Offline-first with a single storage seam: the UI and Zustand stores never know
whether data lives on the device or in the cloud - a storageAdapter routes reads
and writes, and a guest's local data is synced up on first sign-in.
flowchart TD
UI[Screens · expo-router] --> Z[Zustand stores<br/>auth · cars · records · reminders]
Z --> SA{storageAdapter}
SA -->|guest| AS[(AsyncStorage · on device)]
SA -->|signed in| SB[(Supabase PostgreSQL<br/>Row-Level Security)]
AS -. sync on sign-in .-> SYNC[syncService] --> SB
SB --- AUTH[Auth · Magic Link OTP]
SB --- ST[Storage · car-photos bucket]
Z --> NOTIF[expo-notifications<br/>local reminders]
Z --> PDF[expo-print<br/>HTML → PDF report]
- One storage seam, two backends.
storageAdapterpresents the same API over on-deviceAsyncStorage(guest) and Supabase (signed in);syncServicemigrates guest data up on sign-in. Users get value before creating an account, and lose nothing when they do. - Per-user isolation in the database. PostgreSQL Row-Level Security scopes every
row to its owner (
auth.uid()), with separateSELECT/INSERT/UPDATE/DELETEpolicies -INSERTneedsWITH CHECK, which a singleFOR ALLpolicy silently misses. - Reminders that actually fire. Mileage- and date-based reminders are scheduled as local notifications and re-armed whenever the app becomes active.
- Real consumption maths. Fuel economy and range are computed from full-tank intervals (two+ full-tank records), not naive per-fill averages.
- PDF from HTML, not a screenshot. The history report is built as an HTML
document and rendered via
expo-print, with a web fallback to the browser's print.
Seven tables in PostgreSQL, all under Row-Level Security; a trigger auto-creates a profile on sign-up, and car photos live in a Supabase Storage bucket.
erDiagram
profiles ||--o{ cars : owns
profiles ||--o{ service_records : logs
cars ||--o{ service_records : has
cars ||--o{ reminders : has
cars ||--o{ car_photos : has
cars ||--o{ car_ownership_history : "history of"
service_records ||--o{ record_parts : includes
- profiles - extends Supabase auth users (phone, name, push token).
- cars - make/model/year, engine & transmission, mileage, VIN, plate, tank, LPG.
- service_records - typed events (fuel/service/repair/insurance/…), cost, mileage, plus type-specific fields (litres, full-tank flag, oil volume, valid-until).
- record_parts - parts used in a service record (name, article, qty, cost).
- reminders - mileage/date/fuel-volume/combined, priority, notification toggle.
- car_photos - categorized gallery, stored in the
car-photosbucket. - car_ownership_history - ownership over time, with a pending → transferred flow.
- Server-side transfer completion - the new owner claims the car automatically on sign-in with the invited email.
- B2B auto-service side - consented shops see car state and due maintenance.
- AI care tips - personalized upkeep guidance from each car's history.
App screenshots (garage, add-car flow, history, analytics, PDF report) go in
docs/screenshots/.