tajniak81andClaude Opus 5 fb42791f8d The card beside it had boxes, so this one gets boxes
Charger information was one long list of everything the service knows;
the readings card next to it had been splitting its fields into a box
per group all along. Same treatment here: Device, Status, Network and
On the account, plus the service's own fields and the per-charger views,
each in its own sunken section under a heading. Both clients, since the
web and the phone draw the same card.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-02 22:18:45 +02:00

DriverVault

A car control & service-tracking system (originally "Car Control Project"). Built incrementally — starting with a car maintenance tracker (modeled on Car Service.xlsx) and growing toward live integration with the car via a cellular ESP32 device and third-party services (Toyota Connected, EV chargers).

Architecture

All clients communicate with the database only through the API Server — nothing talks to PocketBase directly.

                       ┌──────────────────┐
   Web App (Vue) ─────▶│                  │
   Phone App (Flutter)▶│   API Server     │────▶  PocketBase
   Home Assistant ────▶│   (Go, stdlib)   │       (10.2.1.10:8027)
   Car Agent (ESP32) ─▶│                  │
                       └──────────────────┘
Component Stack Status Docs
API Server Go (stdlib) built, running, verified API Server/README.md
Database PocketBase running, schema + seed done
Web App Vue 3 + Vite + Tailwind v4 full feature set (below) Web App/README.md
Phone App Flutter (Android) web parity + biometric login Phone App/README.md
Docker Compose (multi-container / all-in-one) deployment configs Docker/README.md · Docker-AIO/README.md
Car Agent Device ESP32 + SIM7600 (LILYGO TTGO) 🚧 firmware in progress Car Agent Device
Home Assistant Plugin later

The Web and Phone apps are at feature parity.

Features

  • Maintenance tracking — cars, service history (date/odometer + which parts were changed), and a per-car parts catalog, with next-due date/km status from the spreadsheet formulas.
  • Technical checks — the mandatory roadworthiness inspections (przegląd techniczny / MOT / TÜV): result, cost, station and the certificate's valid-until, which overrides the car's interval and drives the next-due date.
  • Maintenance log — workshop visits and repairs outside the routine schedule: type/status, workshop, parts used, labour + parts cost, invoice, warranty-until.
  • Fuel tracking — refills with derived efficiency (average / best / worst consumption, cost per km, price per litre). Consumption is measured between full tanks, so partial fills roll into the next full one.
  • Documents — insurance, registration, road tax and the rest, each with a server-computed renewal/expiry state.
  • Reminders — date- and/or odometer-triggered, one-off or recurring, plus read-only reminders the server derives from documents and service records.
  • Attachments — one optional file (PDF or image) per service record, technical check, maintenance entry, refill, document and part; fetched back through the API Server, never a public URL.
  • Accounts — PocketBase-token login, profile + appearance preferences (theme/locale/date format/currency/font), avatar, email verification, data export/import, and an account-deletion state machine.
  • Organizations & roles — multi-tenant user / admin / superadmin roles; admins manage users within their own organization, superadmins span all. Any user without an organization can create one and becomes its admin.
  • Per-user ownership & sharing — each car has an owner and can be shared with other users as read or write; the UI mirrors the server's access checks.
  • Integrations — per-user connectors under a superadmin → org-admin → user cascade. Built-in today: Toyota Connected (read-only vehicle data), the Anker Solix V1 EV charger and the Greencell HabuDen wallbox (read over the owner's own MQTT broker — no Greencell cloud is involved). Apprise joins them as a server-wide connector rather than a per-user one: it hands a message to an Apprise gateway the operator runs, which fans it out to any of the 100+ services Apprise speaks.
  • Cars from the manufacturer's own service — import a car straight off a connected account (MyToyota today), choosing what to pull in, and read everything that service knows about it from a dedicated first tab on the car. Generic over providers: the next manufacturer is one adapter in the API Server.
  • EV charging control — for Anker Solix chargers the owner can start, stop and limit charging from the Charging screen over whichever of three transports their control mode picks: Anker's own cloud (commands ride the connection the charger already holds to Anker, so nothing has to be reachable — the mode for a charger on a customer's network), Modbus TCP on the local network, or an OCPP 1.6J Central System the charger dials back into.
  • Translated UI — the interface reads its text from per-language files (English, Polish, Danish today), with English as the fallback for any untranslated string. See TRANSLATIONS.md.
  • Phone biometric login & app lock — fingerprint / face sign-in with an app-lock that requires an unlock on relaunch. See the Phone App README.

Auth model

All apps share one auth model: authentication is PocketBase's own. POST /api/auth/login is proxied to the PocketBase users collection and the client keeps the token PocketBase minted — the API Server does not issue its own JWT. Every protected request carries Authorization: <token> (both Bearer <token> and a raw token are accepted) and the server re-resolves it against PocketBase on each call, so a role change or a deletion takes effect immediately. Tokens are stateless, so there is no per-device session list; changing an account's password rotates its token key and invalidates every token already issued. Access to cars/records is gated by per-user ownership and shares; user management requires the admin or superadmin role. Creating an organization is the one management action open to a plain user — it promotes them to admin of the organization they just created.

Domain (from Car Service.xlsx)

  • Cars — one per vehicle (was: one spreadsheet sheet), with spec fields (engine / transmission / differential oil, brake fluid, coolant, VIN, fuel type, build / first-registration dates, …) and configurable service intervals.
  • Service records — date + odometer per service, plus which parts were changed (oil & oil filter, engine air filter, cabin air filter).
  • Parts — per-car catalog of part numbers.

Key spreadsheet formulas, reproduced by the API Server on read:

Next Service Date = service date + serviceIntervalDays   (default 365; Excel: =A+365)
Next Service Km   = service km   + serviceIntervalKm      (default 15 000; Excel: =B+15000)

Intervals are configurable per car.

Getting started

Bring up the stack in this order — each app's README has the details:

  1. API Server — configure .env, run setup-pocketbase.mjs, start the server. This must be running for either app.
  2. Web Appnpm install && npm run dev (proxies /api to the server).
  3. Phone Appflutter build apk / flutter run with --dart-define=API_BASE=http://<server-ip>:8080/api.

Or skip all of that and bring the whole stack up with Docker, which runs the schema setup itself — see Docker (PocketBase + API Server + Web App as three containers) or Docker-AIO (all three in a single image).

Layout

DriverVault/
├── API Server/            # Go gateway to PocketBase (the only DB client)
├── Web App/               # Vue 3 + Vite + Tailwind v4 SPA + Go BFF
├── Phone App/             # Flutter (Android)
├── Car Agent Device/      # ESP32 + SIM7600 firmware (LILYGO TTGO T-SIM7600)
├── Home Assistant Plugin/ # later phase
├── Docker/                # Compose deployment (API Server + Web App)
└── Docker-AIO/            # single all-in-one image
S
Description
No description provided
Readme
8.2 MiB
Languages
Go 43.3%
Dart 26.3%
Vue 19.2%
C++ 4.7%
JavaScript 3.8%
Other 2.7%