Files
DriverVault/Web App
tajniak81andClaude Opus 4.8 e64c89a564 Add fuel, maintenance, document and reminder tracking
Four features layered onto cars, each following the existing parts/services
pattern: a Go handler gated on requireCarAccess, snake_case PocketBase
mappers, a Vue form modal, and a tab on CarDetail (now driven by an array
rather than repeated markup).

Fuel: refills logged with odometer, litres and cost. Consumption is derived
on read from the whole history rather than stored, so correcting an old fill
re-derives every window it touches with no rows to migrate. Efficiency uses
the full-tank method — two consecutive full tanks are the same known level,
so the fuel burned between them is exactly what was poured in. Partial fills
roll into the window that closes them; a missed-fill flag leaves that window
uncomputed rather than reporting an implausibly good figure. Averages in the
stats rollup are distance-weighted, so a long motorway run counts for more
than a trip across town — which is what actually happened to the fuel.

Maintenance: workshop visits and repairs, deliberately separate from
service_records. That collection is the routine interval schedule and drives
next-service-due; this one is unplanned garage work with a workshop, an
invoice and a labour bill, and no bearing on the interval.

Documents: insurance, pollution certificates and registration papers. The
renewal date is the point of the record, so expiry is assessed live on every
read instead of stored and left to go stale. Scans are proxied through the
API — PocketBase's collections have no public read rule, so an attachment is
never a public URL and car access is re-checked per fetch.

Reminders: fire on a date, an odometer reading, or both (whichever comes
first). Stored reminders sit alongside read-only ones derived from document
expiry and next-service-due, so a renewal date is never typed twice and can
never drift from the document it came from. Derived ids are namespaced
"auto:" and every write endpoint rejects them.

A refill or a completed visit also writes the car's odometer forward, since
it is the freshest reading there is — never backwards, so backfilling old
history can't rewind the car.

Adds fuel_entries, maintenance_entries, car_documents and reminders to the
idempotent schema script, plus a file-field builder for attachments.

Verified end-to-end against a live PocketBase with a throwaway account: 39
checks covering the efficiency maths, expiry states, the derived reminders,
the upload/download round-trip, and that a stranger can reach none of it.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 09:50:11 +02:00
..

DriverVault — Web App

Maintenance tracker for your cars: a Vue 3 + Vite + Tailwind CSS v4 SPA served by a small Go backend-for-frontend (BFF). The BFF serves the built SPA and reverse-proxies /api/* to the API Server, so the browser is always same-origin and all data access still flows through the API Server (never PocketBase directly).

Browser ─► Web App BFF (:8090) ──/api/*──► API Server (:8080) ─► PocketBase
                  └── serves embedded Vue SPA

Layout

server/           Go BFF: embeds web/dist, proxies /api -> API_BASE
  main.go
  .env.example
  dist/           built SPA (generated; embedded at compile time)
web/              Vue 3 + Vite + Tailwind v4 source
  src/
    main.js       app bootstrap
    router.js     /login, / (dashboard), /cars/:id, /settings, /admin
    api.js        the only place that calls the API Server (base URL resolution)
    auth.js       session/profile state, isAdmin
    prefs.js      theme/locale/date/font preferences -> <html>
    lib/format.js date/km formatting + next-service status badges
    style.css     Tailwind v4 entry (+ dark custom-variant)
    App.vue       layout shell + nav (Admin link when admin)
    components/    Modal, CarFormModal, ServiceFormModal, PartFormModal, ShareModal, Logo
    views/         Login, Dashboard, CarDetail, Settings, AdminUsers

Requirements

  • Node 18+ and Go 1.26+
  • A running API Server (see ../API Server)

Develop

Two terminals:

# terminal 1 — API Server (see ../API Server/README.md)
cd "../API Server"; ./api-server.exe

# terminal 2 — Vite dev server with hot reload (proxies /api -> :8080)
cd web; npm install; npm run dev      # http://localhost:5173

The dev server proxies /api/* to the API Server (default http://localhost:8080, override with VITE_API_TARGET), so the client uses same-origin relative URLs and avoids CORS. It also listens on all interfaces (host: true) so it's reachable on the LAN (e.g. http://10.2.1.101:5173).

At runtime, users can override the API base URL from the login screen's Server settings (persisted in localStorage as cc_server_url); resolution order is that override → VITE_API_BASE/api.

Build & run (production-style)

./server/Run-WebApp.ps1               # builds frontend, then serves on :8090
# or manually:
cd web; npm run build                 # outputs to ../server/dist
cd ../server; go run .                # http://localhost:8090

Config (server/.env, copy from .env.example):

Variable Purpose Default
WEB_ADDR Listen address :8090
API_BASE API Server base URL http://localhost:8080

Features

  • Dashboard — one card per car: last service, odometer, next-due date/km, and a status badge (OK / due soon ≤30d / overdue) from the Excel formulas. Add a car; shared cars are labelled and gated by your access level.
  • Car detail — full service history (date, km, computed next date/km, and the changed-parts flags) plus the per-car parts catalog and all car spec fields (engine / transmission / differential oil, brake fluid, coolant, VIN, …). Add/edit/delete service records, parts, and the car; share the car with other users (read/write, owner only). Edit/delete controls are hidden for read-only shares.
  • Settings — account (name / email verification / password), appearance (theme light/dark/system, locale, date format, font size), profile (avatar, bio), data export/import, active sessions with remote logout, and the account-deletion state machine.
  • Admin/admin user management (list / create / role / reset password / delete), gated by the admin role via a router guard + nav link.
  • Theming — light/dark/system app-wide (Tailwind v4 class strategy); prefs.js toggles .dark on <html> and applies the saved theme/locale/date/font.

Auth & access

Login gets a JWT from the API Server (stored client-side) and creates a server session. auth.js exposes isAdmin and the current profile; the router guards public / admin routes. Cars are per-user (owned + shared), and the UI mirrors the server's read / write / owner access levels.