tajniak81andClaude Opus 4.8 ee28b522c7 Bring the Phone App up to parity with the web app
Four rounds of web-app features never reached the phone: fuel, maintenance,
document and reminder tracking; attachments; the currency setting and the
locale split; and technical check history. The README claimed full parity
throughout, so the gap was invisible. Catch the phone up, mirroring the web
components field for field.

Car detail grows the web app's tabs, in its order: technical checks,
maintenance, fuel (with the summary panel), documents and reminders, beside
the existing service and parts lists. The derived figures are the server's
and are rendered as "—" wherever it sent null — a window with a missed fill
has no consumption, and a plausible-looking 0.0 there would be a lie.

Attachments hang off service records, technical checks, workshop visits,
refills, documents and parts on identical terms, so one field and one apply
helper cover all six rather than being copied per form. As on the web, the
form only collects intent: the file endpoints address a record that must
already exist, so a create-with-file is two calls, and a failure on the
second reports as an attachment error because the metadata is committed.

Two bugs fixed on the way:

- _carPayload omitted technicalCheckIntervalDays. The API rewrites every
  column from the body, so any car edit — including the one-tap odometer
  update — silently zeroed the car's inspection interval.
- main() never called initializeDateFormatting, so month names ignored the
  chosen language that the new Language picker exists to set.

Luxembourgish and Romansh are deliberately left off the language list: intl
ships no symbols for them and throws rather than falling back, which would
take out every date on screen. The browser has full ICU data and has no such
limit, so the web app can offer them. The server only validates a locale's
shape, so an unrenderable tag can still arrive from the web; format.dart
resolves through a supported-language check and falls back to en-US.

Labels for the language/region/currency lists are hand-kept because Dart has
no Intl.DisplayNames. The lists mirror validCurrencies in me.go.

file_picker is pinned to ^10: v8 compiles against android-34, which no longer
builds against the other plugins' compileSdk requirement of 36.

Adds the project's first test, covering the parts that fail silently rather
than loudly — null derived fields, the badge wording, and the locale guard.

The phone was not authorized over ADB, so the UI was not exercised on a
device: this is analyzer-, test- and build-clean, and every JSON field name
and route was cross-checked against models.go and server.go.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 15:15:01 +02:00
2026-07-06 08:50:52 +02:00
2026-07-06 08:50:52 +02:00
2026-07-06 08:50:52 +02:00
2026-07-06 08:50:52 +02:00

Car Control Project

A car control & service tracking system. Built incrementally — starting with a car maintenance tracker (modeled on Car Service.xlsx) and growing toward live integration with the car via an ESP32 device.

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)
   ESP32 device ──────▶│                  │
                       └──────────────────┘
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
Home Assistant Plugin later
Car Agent Device ESP32 later

The Web and Phone apps are at feature parity (the phone omits only data export/import).

Features

  • Maintenance tracking — cars, service history (date/odometer + which parts were changed), and a per-car parts catalog, with next-due date/km status.
  • Accounts & sessions — JWT login, per-device active sessions with remote logout, profile + appearance preferences (theme/locale/date/font), email verification, and account deletion.
  • 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.
  • Admin — role-gated user management (create / role / reset password / delete).
  • Phone biometric login & app lock — fingerprint / face sign-in with an app-lock that requires an unlock on relaunch (with a short grace period for quick app-switches). See the Phone App README.

Auth model

All three apps share one auth model: login via POST /api/auth/login returns a JWT issued by the API Server (after verifying against PocketBase users), and every other endpoint requires Authorization: Bearer <token>. Each login also creates a server-side session whose id is embedded in the token, so sessions can be listed and revoked. Access to cars/records/parts is gated by per-user ownership and shares; admin endpoints require the admin role.

Domain (from Car Service.xlsx)

  • Cars — one per vehicle (was: one spreadsheet sheet), with spec fields (engine / transmission / differential oil, brake fluid, coolant, VIN, …) 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.

Layout

Car Control Project/
├── API Server/            # Go gateway to PocketBase (the only DB client)
├── Web App/               # Vue 3 + Vite + Tailwind v4
├── Phone App/             # Flutter (Android)
├── Home Assistant Plugin/ # later phase
└── Car Agent Device/      # ESP32, later phase
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%